PuLP Optimization Traveling Salesman Problem - Calculating arrival time for each node - python

I'm solving the traveling salesman problem using PuLP optimizer on python. The code takes the time matrix as an ndarray and uses it to calculate the optimal route. My first version is running perfectly but i am facing some issue when i add a variable which calculates the time at which the vehicle reaches each point.
Version 1
import numpy as np
from pulp import *
time_matrix = np.array([[0,5,4,6,7,10],
[5,0,3,2,6,15],
[4,3,0,4,5,6],
[6,2,4,0,7,8],
[7,6,5,7,0,11],
[10,15,6,8,11,0]])
row,col = time_matrix.shape
problem = LpProblem('TravellingSalesmanProblem', LpMinimize)
# Decision variable X for truck route
decisionVariableX = LpVariable.dicts('decisionVariable_X', ((i, j) for i in range(row) for j in range(row)), lowBound=0, upBound=1, cat='Integer')
# subtours elimination
decisionVariableU = LpVariable.dicts('decisionVariable_U', (i for i in range(row)), lowBound=1, cat='Integer')
# Objective Function
problem += lpSum(time_matrix[i][j] * decisionVariableX[i, j] for i in range(row) for j in range(row))
# Constraint
for i in range(row):
problem += (decisionVariableX[i,i] == 0) # elimination of (1 to 1) route
problem += lpSum(decisionVariableX[i,j] for j in range(row))==1 # truck reaches all points once
problem += lpSum(decisionVariableX[j,i] for j in range(row)) ==1 #truck dispatches from all points once
for j in range(row):
if i != j and (i != 0 and j != 0):
problem += decisionVariableU[i] <= decisionVariableU[j] + row * (1 - decisionVariableX[i, j])-1 # sub-tour elimination for truck
status = problem.solve()
print(f"status: {problem.status}, {LpStatus[problem.status]}")
print(f"objective: {problem.objective.value()}")
for var in problem.variables():
if (problem.status == 1):
if (var.value() !=0):
print(f"{var.name}: {var.value()}")
In version 2 I add another variable decisionVariableT which stores the value of time at which the truck reaches each node. But adding this constraint makes the problem infeasible. Can someone help me in identifying whats wrong with the code?
TIA
Version 2 addition
# Decision variable T for truck arrival time
decisionVariableT = LpVariable.dicts('decisionVariable_T', (i for i in range(row)), lowBound=0, cat='Integer')
M=1000
# Calculating truck arrival time at each node
for i in range(row):
for j in range(row):
if (decisionVariableX[i,j]==1):
problem += decisionVariableT[j] == decisionVariableT[i] + time_matrix[i][j]
The result of Version 1:
status: 1, Optimal
objective: 33.0
decisionVariable_U_1: 5.0
decisionVariable_U_2: 2.0
decisionVariable_U_3: 4.0
decisionVariable_U_4: 1.0
decisionVariable_U_5: 3.0
decisionVariable_X_(0,_4): 1.0
decisionVariable_X_(1,_0): 1.0
decisionVariable_X_(2,_5): 1.0
decisionVariable_X_(3,_1): 1.0
decisionVariable_X_(4,_2): 1.0
decisionVariable_X_(5,_3): 1.0
The result of Version 2:
status: -1, Infeasible
objective: 0.0

Consider if your timing matrix had these values:
t[2,3] = 2
t[3,2] = 4
Because you are enumerating over all of the combos in your matrix, you are then making the (infeasible) statement that
t[2] >= t[3] + 4 + C
t[3] >= t[2] + 2 + C
Where C is a constant and the result of your big-M constraint in the case that neither (or both) are used.
Rearranged that is:
t[2] >= t[3] + 4
t[2] <= t[3] - 2
Edit... ideas on fix
As for a fix... You could either...
make a variable and keep a running sum over the rows only not the columns. In pseudocode:
problem += cumulative_time[0] >= sum(x[0,c] * t[0,c] for c in cols)
for r in rows[1:]:
prob += cumulative_time[r] >= cumulative_time[r-1] + <above, with 'r' instead of '0'>
Or
realize that it isn't necessary to treat cumulative time as a variable, because you can deduce it from your solution and just do the same construct over the result values when you are looping over them to print....

Related

Implementing binary constraint in PuLP Objective Function

I'm trying to determine the maximum revenue that can be earned from a battery connected to the grid using linear programming. The battery can earn revenues in two markets, the energy market and the frequency market. My model is throwing an error when I include a binary constraint in the objective function (TypeError: Non-constant expressions cannot be multiplied).
My Objective function is:
N is the time horizon of the optimisation
is the energy price at time t
are the allocated discharge and charge power at time t
is the frequency price at time t
is the allocated frequency power at time t
The battery should only be active in one market (energy or frequency) at each time period t. So needs a constraint that looks something like this:
where is a binary variable that activates activity x.
Ok, so that's what I trying to achieve. I'm struggling to create such a constraint in pulp that essentially switches off participation in one of the markets if the value in the other is higher (all other constraints being met). In my battery class, I've created decision variables for each of the power activities and also for their on/off status.
self.charge = \
pulp.LpVariable.dicts(
"charging_power",
('c_t_' + str(i) for i in range(0,time_horizon)),
lowBound=0, upBound=max_charge_power_capacity,
cat='Continuous')
self.discharge = \
pulp.LpVariable.dicts(
"discharging_power",
('d_t_' + str(i) for i in range(0,time_horizon)),
lowBound=0, upBound=max_discharge_power_capacity,
cat='Continuous')
self.freq = \
pulp.LpVariable.dicts(
"freq_power",
('f_t_' + str(i) for i in range(0,time_horizon)),
lowBound=0, upBound=max_freq_power_capacity,
cat='Continuous')
self.charge_status = \
pulp.LpVariable.dicts(
"charge_status",
('c_status_t_' + str(i) for i in range(0,time_horizon)),
cat='Binary')
self.discharge_status = \
pulp.LpVariable.dicts(
"discharge_status",
('d_status_t_' + str(i) for i in range(0,time_horizon)),
cat='Binary')
self.freq_status = \
pulp.LpVariable.dicts(
"freq_status",
('ds3_status_t_' + str(i) for i in range(0,time_horizon)),
cat='Binary')
In my objective function, I included these binary variables.
self.model = pulp.LpProblem("Max Profit", pulp.LpMaximize)
self.model +=\
pulp.lpSum(
[self.charge['c_t_' + str(i)]*-1*prices[i] *
self.charge_status['c_status_t_' + str(i)] for i in range(0,self.time_horizon)]
+ [self.discharge['d_t_' + str(i)]*prices[i] *
self.discharge_status['d_status_t_' + str(i)] for i in range(0,self.time_horizon)]
+ [self.freq['f_t_' + str(i)]*freq_prices[i] *
self.freq_status['freq_status_t_' + str(i)] for i in range(0,self.time_horizon)]
)
The constraint for these binary variables, I set up as follows:
for hour_of_sim in range(1,self.time_horizon+1):
self.model += \
pulp.lpSum([self.charge_status['c_status_t_' + str(i)] for i in range(0,self.time_horizon)] +\
[self.discharge_status['d_status_t_' + str(i)] for i in range(0,self.time_horizon)] +\
[self.freq_status['freq_status_t_' + str(i)] for i in range(0,self.time_horizon)]
) <= 1
When I try to solve, I get a
TypeError: Non-constant expressions cannot be multiplied
on the objective function. Doesn't like my binary variables, runs if they are removed. There must be an alternative way of setting this up which is escaping me?
The comment is correct... you are violating "linearity" by multiplying 2 variables together. Fortunately, this is easy to linearize. You have a binary variable controlling the mode, so the key element you are looking for (google it) is a Big-M constraint, where you use the binary variable multiplied by a max value (or just something sufficiently large) to limit the other variable either to the max, or clamp it to zero.
An example below. I also re-arranged things a bit. You might find this style more readable. Two main things on style:
You are constantly re-creating the indices you are using which is really painful to read and error prone. Just make them and re-use them...and you don't need to get complicated with the index set values
You can easily double-index this model, which I think is more clear than making multiple sets of variables. You essentially have 2 sets you are working with: Time periods, and Op modes. Just make those sets and double index.
Example
# battery modes
import pulp
# some data
num_periods = 3
rate_limits = { 'energy' : 10,
'freq' : 20}
price = 2 # this could be a table or double-indexed table of [t, m] or ....
# SETS
M = rate_limits.keys() # modes. probably others... discharge?
T = range(num_periods) # the time periods
TM = {(t, m) for t in T for m in M}
model = pulp.LpProblem('Batts', pulp.LpMaximize)
# VARS
model.batt = pulp.LpVariable.dicts('batt_state', indexs=TM, lowBound=0, cat='Continuous')
model.op_mode = pulp.LpVariable.dicts('op_mode', indexs=TM, cat='Binary')
# Constraints
# only one op mode in each time period...
for t in T:
model += sum(model.op_mode[t, m] for m in M) <= 1
# Big-M constraint. limit rates for each rate, in each period.
# this does 2 things: it is equivalent to the upper bound parameter in the var declaration
# It is a Big-M type of constraint which uses the binary var as a control <-- key point
for t, m in TM:
model += model.batt[t, m] <= rate_limits[m] * model.op_mode[t, m]
# OBJ
model += sum(model.batt[t, m] * price for t, m in TM)
print(model)
# solve...
Yields:
Batts:
MAXIMIZE
2*batt_state_(0,_'energy') + 2*batt_state_(0,_'freq') + 2*batt_state_(1,_'energy') + 2*batt_state_(1,_'freq') + 2*batt_state_(2,_'energy') + 2*batt_state_(2,_'freq') + 0
SUBJECT TO
_C1: op_mode_(0,_'energy') + op_mode_(0,_'freq') <= 1
_C2: op_mode_(1,_'energy') + op_mode_(1,_'freq') <= 1
_C3: op_mode_(2,_'energy') + op_mode_(2,_'freq') <= 1
_C4: batt_state_(2,_'freq') - 20 op_mode_(2,_'freq') <= 0
_C5: batt_state_(2,_'energy') - 10 op_mode_(2,_'energy') <= 0
_C6: batt_state_(1,_'freq') - 20 op_mode_(1,_'freq') <= 0
_C7: batt_state_(1,_'energy') - 10 op_mode_(1,_'energy') <= 0
_C8: batt_state_(0,_'freq') - 20 op_mode_(0,_'freq') <= 0
_C9: batt_state_(0,_'energy') - 10 op_mode_(0,_'energy') <= 0
VARIABLES
batt_state_(0,_'energy') Continuous
batt_state_(0,_'freq') Continuous
batt_state_(1,_'energy') Continuous
batt_state_(1,_'freq') Continuous
batt_state_(2,_'energy') Continuous
batt_state_(2,_'freq') Continuous
0 <= op_mode_(0,_'energy') <= 1 Integer
0 <= op_mode_(0,_'freq') <= 1 Integer
0 <= op_mode_(1,_'energy') <= 1 Integer
0 <= op_mode_(1,_'freq') <= 1 Integer
0 <= op_mode_(2,_'energy') <= 1 Integer
0 <= op_mode_(2,_'freq') <= 1 Integer

PuLP: How to write a multi variable constraint?

I am trying to solve this optimization problem in Python. I have written the following code using PuLP:
import pulp
D = range(0, 10)
F = range(0, 10)
x = pulp.LpVariable.dicts("x", (D), 0, 1, pulp.LpInteger)
y = pulp.LpVariable.dicts("y", (F, D), 0, 1, pulp.LpInteger)
model = pulp.LpProblem("Scheduling", pulp.LpMaximize)
model += pulp.lpSum(x[d] for d in D)
for f in F:
model += pulp.lpSum(y[f][d] for d in D) == 1
for d in D:
model += x[d]*pulp.lpSum(y[f][d] for f in F) == 0
model.solve()
The one-but-last line here returns: TypeError: Non-constant expressions cannot be multiplied. I understand it is returning this since it cannot solve non-linear optimization problems. Is it possible to formulate this problem as a proper linear problem, such that it can be solved using PuLP?
It is always a good idea to start with a mathematical model. You have:
min sum(d, x[d])
sum(d,y[f,d]) = 1 ∀f
x[d]*sum(f,y[f,d]) = 0 ∀d
x[d],y[f,d] ∈ {0,1}
The last constraint is non-linear (it is quadratic). This can not be handled by PuLP. The constraint can be interpreted as:
x[d] = 0 or sum(f,y[f,d]) = 0 ∀d
or
x[d] = 1 ==> sum(f,y[f,d]) = 0 ∀d
This can be linearized as:
sum(f,y[f,d]) <= (1-x[d])*M
where M = |F| (number of elements in F, i.e. |F|=10). You can check that:
x[d]=0 => sum(f,y[f,d]) <= M (i.e. non-binding)
x[d]=1 => sum(f,y[f,d]) <= 0 (i.e. zero)
So you need to replace your quadratic constraint with this linear one.
Note that this is not the only formulation. You could also linearize the individual terms z[f,d]=x[d]*y[f,d]. I'll leave that as an exercise.

VRP heterogeneous site-dependency

In my code, I managed to implement different vehicle types (I think) and to indicate the site-dependency. However, it seems that in the output of my optimization, vehicles can drive more then one route. I would like to implement that my vehicle, once it returns to the depot (node 0), that a new vehicle is assigned to perform another route. Could you help me with that? :)
I'm running on Python Jupyter notebook with the Docplex solver
all_units = [0,1,2,3,4,5,6,7,8,9]
ucp_raw_unit_data = {
"customer": all_units,
"loc_x": [40,45,45,42,42,42,40,40,38,38],
"loc_y" : [50,68,70,66,68,65,69,66,68,70],
"demand": [0,10,30,10,10,10,20,20,20,10],
"req_vehicle":[[0,1,2], [0], [0], [0],[0], [0], [0], [0], [0], [0]],
}
df_units = DataFrame(ucp_raw_unit_data, index=all_units)
# Display the 'df_units' Data Frame
df_units
Q = 50
N = list(df_units.customer[1:])
V = [0] + N
k = 15
# n.o. vehicles
K = range(1,k+1)
# vehicle 1 = type 1 vehicle 6 = type 2 and vehicle 11 = type 0
vehicle_types = {1:[1],2:[1],3:[1],4:[1],5:[2],6:[2],7:[2],8:[2],9:
[2],10:[2],11:[0],12:[0],13:[0],14:[0],15:[0]}
lf = 0.5
R = range(1,11)
# Create arcs and costs
A = [(i,j,k,r) for i in V for j in V for k in K for r in R if i!=j]
Y = [(k,r) for k in K for r in R]
c = {(i,j):np.hypot(df_units.loc_x[i]-df_units.loc_x[j],
df_units.loc_y[i]-df_units.loc_y[j]) for i,j,k,r in A}
from docplex.mp.model import Model
import docplex
mdl = Model('SDCVRP')
# decision variables
x = mdl.binary_var_dict(A, name = 'x')
u = mdl.continuous_var_dict(df_units.customer, ub = Q, name = 'u')
y = mdl.binary_var_dict(Y, name = 'y')
# objective function
mdl.minimize(mdl.sum(c[i,j]*x[i,j,k,r] for i,j,k,r in A))
#constraint 1 each node only visited once
mdl.add_constraints(mdl.sum(x[i,j,k,r] for k in K for r in R for j in V
if j != i and vehicle_types[k][0] in df_units.req_vehicle[j]) == 1 for i
in N)
##contraint 2 each node only exited once
mdl.add_constraints(mdl.sum(x[i,j,k, r] for k in K for r in R for i in V
if i != j and vehicle_types[k][0] in df_units.req_vehicle[j]) == 1 for j
in N )
##constraint 3 -- Vehicle type constraint (site-dependency)
mdl.add_constraints(mdl.sum(x[i,j,k,r] for k in K for r in R for i in V
if i != j and vehicle_types[k][0] not in
df_units.req_vehicle[j]) == 0 for j in N)
#Correcte constraint 4 -- Flow constraint
mdl.add_constraints((mdl.sum(x[i, j, k,r] for j in V if j != i) -
mdl.sum(x[j, i, k,r] for j in V if i != j)) == 0 for i in
N for k in K for r in R)
#constraint 5 -- Cumulative load of visited nodes
mdl.add_indicator_constraints([mdl.indicator_constraint(x[i,j,k,r],u[i] +
df_units.demand[j]==u[j]) for i,j,k,r in A if i!=0 and j!=0])
## constraint 6 -- one vehicle to one route
mdl.add_constraints(mdl.sum(y[k,r] for r in R) <= 1 for k in K)
mdl.add_indicator_constraints([mdl.indicator_constraint(x[i,j,k,r],y[k,r]
== 1) for i,j,k,r in A if i!=0 and j!=0])
##constraint 7 -- cumulative load must be equal or higher than demand in
this node
mdl.add_constraints(u[i] >=df_units.demand[i] for i in N)
##constraint 8 minimum load factor
mdl.add_indicator_constraints([mdl.indicator_constraint(x[j,0,k,r],u[j]
>= lf*Q) for j in N for k in K for r in R if j != 0])
mdl.parameters.timelimit = 15
solution = mdl.solve(log_output=True)
print(solution)
I expect every route to be visited with another vehicle, however the same vehicles perform multiple routes. Also, now the cumulative load is calculated for visited nodes, I would like to have this for the vehicle on the routes so that the last constraint (minimum load factor) can be performed.
I understand K indices are for vehicles and R are for routes. I ran your code and got the follwing assignments:
y_11_9=1
y_12_4=1
y_13_7=1
y_14_10=1
y_15_10=1
which seem to show many vehicles share the same route.
This is not forbidden by the sum(y[k,r] for r in R) <=1) constraint,
as it forbids one vehicle from working several routes.
Do you want to limit the number of assigned vehicles to one route to 1, as this is the symmetrical constraint from constraint #6?
If I got it wrong, plese send the solution you get and the constraint you want to add.
If I add the symmetrical constraint, that is, limit assignments vehicles to routes to 1 (no two vehicles on the same route), by:
mdl.add_constraints(mdl.sum(y[k, r] for r in R) <= 1 for k in K)
mdl.add_constraints(mdl.sum(y[k, r] for k in K) <= 1 for r in R)
I get a solution with the same cost, and only three vehicle-route assignments:
y_11_3=1
y_12_7=1
y_15_9=1
Still, I guess the best solution would be to add some cost factor of using a vehicle, and introducing this into the final objective. This might also reduce the symmetries in the problem.
Philippe.

Solving system of nonlinear equations with Python, Euler's formula

I am working on solving and analyzing a system of differential equations in Python. First did I solve it with help of scipy.integrate dopri5 and scopes Odeint. Which worked out fine. Then I tried to solve the equations with use of the Euler's method. The equations and code is as followed,
dj = -mu*(J**3 - (C - C0)*J - F)
dc = J + C*F + a*J**2
df = J*F - C
T = 100
dt = 0.001
t = np.linspace(0, T, int(T/dt)+1)
j = np.zeros(len(t))
c = np.zeros(len(t))
f = np.zeros(len(t))
# Initial condition
j[0] = 0.1
c[0] = -0.5
f[0] = 0.1
a = 0.3025
C0 = 0.5
mu = 50
for i in range(len(t)):
j[i+1] = j[i] + (-mu * (j[i]**3 - (c[i] - C0)*j[i] - f[i]))*dt
c[i+1] = c[i] + (j[i] + c[i] * f[i] + (a * j[i])**2)*dt
f[i+1] = f[i] + (j[i] * f[i] - c[i])*dt
Is there any reason why the Euler's method should not work when both the other two are?
In the first iteration, i is 0, and your first line of the loop essentially is:
j[0] = j[-1] + (-mu * (j[-1]**3 - (c[-1] - C0)*j[-1] - f[-1]))*dt
j[-1] is the last element of j, just like c[-1] is the last element of c, etc. Initially they are all zeros, so j[0] becomes a 0, too, which overwrites the initial conditions. To fix this problem, change range(len(t)) to range(1,len(t)). (The model diverges after the first 9200 steps, anyway.)
As DYZ says, your calculation is incorrect on the first loop iteration because j[-1] is the last element of j, which you've initialised to zero.
However, your code wastes a lot of RAM. I assume you just want arrays containing T results, plus the initial values, rather than the results calculated on every step. The code below achieves that via a double for loop. We aren't really getting any benefit from Numpy in this code, so I don't bother importing it.
Note that Euler integration is not very accurate, and you generally need to use a much smaller step size than what's required by more sophisticated integration algorithms. As DYZ mentions, with your current step size the calculation diverges before the loop finishes.
Here's a modified version of your code using a smaller step size.
T = 100
dt = 0.00001
steps = int(T / dt)
substeps = int(steps / T)
# Recalculate `dt` to compensate for possible truncation
# in the `steps` and `substeps` calculations
dt = 1.0 / substeps
print('steps, substeps, dt:', steps, substeps, dt)
a = 0.3025
C0 = 0.5
mu = 50
#dj = -mu*(J**3 - (C - C0)*J - F)
#dc = J + C*F + a*J**2
#df = J*F - C
# Initial condition
j = 0.1
c = -0.5
f = 0.1
jlst, clst, flst = [j], [c], [f]
for i in range(T):
for _ in range(substeps):
j1 = j + (-mu * (j**3 - (c - C0)*j - f))*dt
c1 = c + (j + c * f + (a * j)**2)*dt
f1 = f + (j * f - c)*dt
j, c, f = j1, c1, f1
jlst.append(j)
clst.append(c)
flst.append(f)
def round_seq(seq, places=6):
return [round(u, places) for u in seq]
print('j:', round_seq(jlst), end='\n\n')
print('c:', round_seq(clst), end='\n\n')
print('f:', round_seq(flst), end='\n\n')
output
steps, substeps, dt: 10000000 100000 1e-05
j: [0.1, 0.585459, 1.26718, 3.557956, -1.311867, -0.647698, -0.133683, 0.395812, 0.964856, 3.009683, -2.025674, -1.047722, -0.48872, 0.044296, 0.581284, 1.245423, 14.725407, -1.715456, -0.907364, -0.372118, 0.167733, 0.705257, 1.511711, -3.588555, -1.476817, -0.778593, -0.253874, 0.289294, 0.837128, 1.985792, -2.652462, -1.28088, -0.657113, -0.132971, 0.409071, 0.983504, 3.229393, -2.1809, -1.113977, -0.539586, -0.009829, 0.528546, 1.156086, 8.23469, -1.838582, -0.967078, -0.423261, 0.113883, 0.650319, 1.381138, 12.045565, -1.575015, -0.833861, -0.305952, 0.23632, 0.778052, 1.734888, -2.925769, -1.362437, -0.709641, -0.186249, 0.356775, 0.917051, 2.507782, -2.367126, -1.184147, -0.590753, -0.063942, 0.476121, 1.07614, 5.085211, -1.976542, -1.029395, -0.474206, 0.059772, 0.596505, 1.273214, 17.083466, -1.682855, -0.890842, -0.357555, 0.182944, 0.721096, 1.554496, -3.331861, -1.450497, -0.763182, -0.239007, 0.30425, 0.85435, 2.076595, -2.584081, -1.258788, -0.642362, -0.117774, 0.423883, 1.003181, 3.521072, -2.132709, -1.094792, -0.525123]
c: [-0.5, -0.302644, 0.847742, 12.886781, 0.177404, -0.423405, -0.569541, -0.521669, -0.130084, 7.97828, -0.109606, -0.363033, -0.538874, -0.61005, -0.506872, 0.05076, 216.678959, -0.198445, -0.408569, -0.566869, -0.603713, -0.451729, 0.58959, 2.252504, -0.246645, -0.451, -0.588697, -0.587898, -0.375758, 2.152898, -0.087229, -0.295185, -0.49006, -0.603411, -0.562389, -0.263696, 8.901196, -0.132332, -0.342969, -0.525087, -0.609991, -0.526417, -0.077251, 67.082608, -0.177771, -0.389092, -0.555341, -0.607658, -0.47794, 0.293664, 147.817033, -0.225425, -0.432796, -0.579951, -0.595996, -0.412269, 1.235928, -0.037058, -0.273963, -0.473412, -0.597912, -0.574782, -0.318837, 4.581828, -0.113301, -0.3222, -0.51029, -0.608168, -0.543547, -0.172371, 24.718184, -0.157526, -0.369151, -0.542732, -0.609811, -0.500922, 0.09504, 291.915024, -0.204371, -0.414, -0.56993, -0.602265, -0.443622, 0.700005, 0.740665, -0.25268, -0.456048, -0.590933, -0.585265, -0.36427, 2.528225, -0.093699, -0.301181, -0.494644, -0.60469, -0.558516, -0.245806, 10.941068, -0.137816, -0.348805, -0.52912]
f: [0.1, 0.68085, 1.615135, 1.01107, -2.660947, -0.859348, -0.134789, 0.476782, 1.520241, 4.892319, -9.514924, -2.041217, -0.61413, 0.060247, 0.792463, 2.510586, 11.393914, -6.222736, -1.559576, -0.438133, 0.200729, 1.033274, 3.348756, -39.664752, -4.304545, -1.201378, -0.282146, 0.349631, 1.331995, 4.609547, -20.169056, -3.104072, -0.923759, -0.138225, 0.513633, 1.716341, 6.739864, -11.717002, -2.307614, -0.699883, 7.4e-05, 0.700823, 2.22957, 11.017447, -7.434886, -1.751919, -0.512171, 0.138566, 0.922012, 2.9434, -30.549886, -5.028825, -1.346261, -0.348547, 0.282981, 1.19254, 3.987366, -26.554232, -3.566328, -1.0374, -0.200198, 0.439487, 1.535198, 5.645421, -14.674838, -2.619369, -0.792589, -0.060175, 0.615387, 1.985246, 8.779969, -8.991742, -1.972575, -0.590788, 0.077534, 0.820118, 2.599728, 8.879606, -5.928246, -1.509453, -0.417854, 0.218635, 1.066761, 3.477148, -36.053938, -4.124934, -1.163178, -0.263755, 0.369033, 1.37438, 4.811848, -18.741635, -2.987496, -0.893457, -0.120864, 0.535433, 1.771958, 7.117055, -11.027021, -2.227847, -0.674889]
That takes about 75 seconds on my old 2GHz machine.
Using dt = 0.000005 (which takes almost 2 minutes on this machine) the final values of j, c, and f are -0.524774, -0.529217, -0.674293, respectively, so it looks like we're beginning to get convergence.
Thanks to LutzL for pointing out that dt may need adjusting because of the rounding in the steps and substeps calculations.

Python Simulation Inconsistency

I have made a simulator using Python for a game called Final Fantasy XII. The purpose of this simulator is to see how much "gil" (in-game currency) you can get from one particular enemy.
This should output around 23000 from our experiance, but what happens with this is, it outputs 24000 usually, but sometimes 29000. Considering it takes 1000 samples, it is impossible for that to be coincident. I think this code has problems with random generator, but I have no idea.
Are there reasons python simulator sometimes goes wrong?
import random
# defining variables, dictionaries and functions here
for t in range (1, test + 1):
for n in range (1, dustia + 1):
c = c + 1 # first, increase the chain counter
r = random.random()
# deciding a thing using "if r < [probability]" here
# ....
# apparently this part caused the problem
r = random.random()
if m == 1 and r < 0.4:
m = 0
elif m == 0 and r < 0.05:
m = 1
r1 = random.random() # RNG for book
r2 = random.random() # RNG for staff
rr1 = random.random() # amount of books
rr2 = random.random() # amount of staff
# deciding another thing using r < [probability] here
#summing up samples and calculating average here

Categories

Resources