I have an optimization problem of wagons repairs.
'Lon': 125, # London
'Ber': 175, # Berlin
'Maa': 225, # Maastricht
'Ams': 250, # Amsterdam
'Utr': 225, # Utrecht
'Hag': 200 # The Hague
}
Supply = {
'Arn': 600, # Arnhem
'Gou': 650 # Gouda
}
T = {
('Lon','Arn'): 1000,
('Lon','Gou'): 2.5,
('Ber','Arn'): 2.5,
('Ber','Gou'): 1000,
('Maa','Arn'): 1.6,
('Maa','Gou'): 2.0,
('Ams','Arn'): 1.4,
('Utr','Arn'): 0.8,
('Utr','Gou'): 1.0,
('Hag','Arn'): 1.4,
('Hag','Gou'): 0.8
}
T is a cost for all permitted routes. I defined the model and objective function.
# Step 0: Create an instance of the model
model = ConcreteModel()
model.dual = Suffix(direction=Suffix.IMPORT)
# Step 1: Define index sets
CUS = list(Demand.keys())
SRC = list(Supply.keys())
# Step 2: Define the decision
model.x = Var(list(T), domain = NonNegativeReals)
# Step 3: Define Objective
model.Cost = Objective(
expr = sum([T[i]*model.x[i] for i in model.x]),
sense = minimize)
But I have problems with constraints. If I am doing as shown below it throws an error.
# Step 4: Constraints
model.src = ConstraintList()
for s in SRC:
model.src.add(sum([model.x[c,s] for c in CUS]) <= Supply[s])
model.dmd = ConstraintList()
for c in CUS:
model.dmd.add(sum([model.x[c,s] for s in SRC]) == Demand[c])
Error is like that:
Maybe anyone knows how to fix the problem with constraints. To make it more flexible. I understand why it is an error because in T there are not all possible combinations, but it is right, some of the routes is restricted and I do not want to use them in optimization.
You can first get the possible ones like this:
# Step 4: Constraints
model.src = ConstraintList()
for s in SRC:
cposs = [t[0] for t in T.keys() if t[1] == s]
model.src.add(sum([model.x[c,s] for c in cposs]) <= Supply[s])
model.dmd = ConstraintList()
for c in CUS:
sposs = [t[1] for t in T.keys() if t[0] == c]
model.dmd.add(sum([model.x[c,s] for s in sposs]) == Demand[c])
Related
We are currently facing a problem with a Prophet model which stops unexpectedly. We've used optuna as our HyperParameter model searching framework, and gave 400 trials per each TimeSeries (we are traininig Prophet on ~ 1000 Timeseries, 1 by 1, not all at once). For cross validation, we've used the methode from the Prophet class called cross_validation.
Here is the code we've used:
def get_best_hp_prophet_cv(df_for_cv, weeks_to_forecast):
logging.getLogger('prophet').setLevel(logging.ERROR)
logging.getLogger('fbprophet').setLevel(logging.ERROR)
# print('DF entered for search: ', df_for_cv)
cutoffs = generate_cutoffs(df_for_cv, weeks_to_forecast)
def objective(trial):
# print(cutoffs)
# print(df.tail(30))
param_grid = {
"changepoint_prior_scale": trial.suggest_categorical(
"changepoint_prior_scale", [0.001, 0.01, 0.1, 0.5, 0.05, 0.8, 0.9]
),
"seasonality_prior_scale": trial.suggest_categorical(
"seasonality_prior_scale", [0.01, 0.05, 0.1, 0.5, 1.0, 10]
),
"seasonality_mode": trial.suggest_categorical(
"seasonality_mode", ["multiplicative", "additive"]
),
"growth": trial.suggest_categorical("growth", ["linear"]),
"yearly_seasonality": trial.suggest_categorical(
"yearly_seasonality", [3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 16]
),
"daily_seasonality": trial.suggest_categorical("daily_seasonality",[False]),
"weekly_seasonality": trial.suggest_categorical("weekly_seasonality",[False]),
"uncertainty_samples": trial.suggest_categorical("uncertainty_samples",[0]),
}
prior_scale_month = trial.suggest_categorical('prior_scale_month', [0.001, 0.01, 0.1, 0.5, 0.05, 0.9])
prior_scale_week_num = trial.suggest_categorical('prior_scale_week_num', [0.001, 0.01, 0.1, 0.5, 0.05, 0.9])
prior_scale_avg_month_qty_over_df = trial.suggest_categorical('prior_scale_avg_month_qty_over_df', [0.001, 0.01, 0.1, 0.5, 0.05, 0.9])
prior_scale_avg_week_nr_qty_over_df = trial.suggest_categorical('prior_scale_avg_week_nr_qty_over_df', [0.001, 0.01, 0.1, 0.5, 0.05, 0.9])
# I ve used this only for testing to see if everything works fine
# param_grid = {
# 'changepoint_prior_scale': trial.suggest_categorical('changepoint_prior_scale', [0.001]),
# 'seasonality_prior_scale': trial.suggest_categorical('seasonality_prior_scale',[0.01, 0.1]),
# 'seasonality_mode' : trial.suggest_categorical('seasonality_mode',['additive']),
# 'growth': trial.suggest_categorical('growth',['linear']),
# 'yearly_seasonality': trial.suggest_categorical('yearly_seasonality',[14,15]),
# 'holidays_prior_scale' : trial.suggest_categorical('holidays_prior_scale',[10])
# }
# all_params = [dict(zip(param_grid.keys(), v)) for v in itertools.product(*param_grid.values())]
# mses = [] # Store the MSEs for each params here
# Use cross validation to evaluate all parameters
# for params in all_params:
m = Prophet(**param_grid)
m.add_regressor('month', prior_scale = prior_scale_month)
m.add_regressor('week_num', prior_scale = prior_scale_week_num)
m.add_regressor('avg_month_qty_over_df', prior_scale = prior_scale_avg_month_qty_over_df)
m.add_regressor('avg_week_nr_qty_over_df', prior_scale = prior_scale_avg_week_nr_qty_over_df)
m.fit(df_for_cv)
df_cv = cross_validation(
m, cutoffs=cutoffs, horizon="{} days".format(weeks_to_forecast*7), parallel="processes"
)
df_p = performance_metrics(df_cv, rolling_window=1)
return df_p["mse"].values[0]
# Find the best parameters
optuna_prophet = optuna.create_study(
direction="minimize", sampler=TPESampler(seed=321)
)
# * n_trials optuna hyperparameter.
#optuna_prophet.optimize(objective, n_trials=400)
optuna_prophet.optimize(objective, n_trials=1)
prophet_trial = optuna_prophet.best_trial
prophet_trial_params = prophet_trial.params
list_of_variables_outside_the_param_grid = ['prior_scale_month','prior_scale_week_num','prior_scale_avg_month_qty_over_df','prior_scale_avg_week_nr_qty_over_df']
params_outside_the_param_grid={}
param_grid = {}
for param_name in prophet_trial_params.keys():
if param_name in list_of_variables_outside_the_param_grid:
params_outside_the_param_grid.update({param_name : prophet_trial_params[param_name]})
else:
param_grid.update({param_name : prophet_trial_params[param_name]})
return param_grid, params_outside_the_param_grid
We've used Prophet before, but on less Timeseries (around 20) and with even more nr_of_trials in Optuna and never faced this issue before. Does anybody knows why is this happening? Has anybody a workaround? It always stops at the begging of the 54 trial from Optuna Search.
We've tried to run with only 1 trial on all 1000 Timeseries and it worked end - 2 - end, but still we can't figure it out why it stops on the 54th trial ?
Versions:
Optuna ---- 3.0.3.
Prophet ---- 1.1
I would like to have instead of only the vector of optimal solution to a mip , all the feasible (suboptimal) vectors.
I found some old questions here, but I am not sure how they work.
First of all, is there any new library tool/way to do that automatically ?
I tried this but, it did nothing:
if termination_status(m) == MOI.FEASIBLE_POINT
println(x)
end
optimize!(m);
If not, what's the easiest way?
I thought of scanning the optimal solution till I find the first non -zero decision variable, then constraint this variable to be zero and solving the model again.
for i in 1:active_variables
if value.(z[i])==1
#constraint(m, x[i] == 0)
break
end
end
optimize!(m);
But I see this problem with this method** :
Ιf I constraint x[i] to be zero, in the next step I will want maybe to drop again this constraint? This comes down to whether there can exist two(or more) different solutions in which x[i]==1
JuMP supports returning multiple solutions.
Documentation: https://jump.dev/JuMP.jl/stable/manual/solutions/#Multiple-solutions
The workflow is something like:
using JuMP
model = Model()
#variable(model, x[1:10] >= 0)
# ... other constraints ...
optimize!(model)
if termination_status(model) != OPTIMAL
error("The model was not solved correctly.")
end
an_optimal_solution = value.(x; result = 1)
optimal_objective = objective_value(model; result = 1)
for i in 2:result_count(model)
#assert has_values(model; result = i)
println("Solution $(i) = ", value.(x; result = i))
obj = objective_value(model; result = i)
println("Objective $(i) = ", obj)
if isapprox(obj, optimal_objective; atol = 1e-8)
print("Solution $(i) is also optimal!")
end
end
But you need a solver that supports returning multiple solutions, and to configure the right solver-specific options.
See this blog post: https://jump.dev/tutorials/2021/11/02/tutorial-multi-jdf/
The following is an example of all-solution finder for a boolean problem. Such problems are easier to handle since the solution space is easily enumerated (even though it can still grow exponentially big).
First, let's get the packages and define the sample problem:
using Random, JuMP, HiGHS, MathOptInterface
function example_knapsack()
profit = [5, 3, 2, 7, 4]
weight = [2, 8, 4, 2, 5]
capacity = 10
minprofit = 10
model = Model(HiGHS.Optimizer)
set_silent(model)
#variable(model, x[1:5], Bin)
#objective(model, FEASIBILITY_SENSE, 0)
#constraint(model, weight' * x <= capacity)
#constraint(model, profit' * x >= minprofit)
return model
end
(it is a knapsack problem from the JuMP docs).
Next, we use recursion to explore the tree of all possible solutions. The tree does not go down branches with no solution (so the running time is not always exponential):
function findallsol(model, x)
perm = shuffle(1:length(x))
res = Vector{Float64}[]
_findallsol!(res, model, x, perm, 0)
return res
end
function _findallsol!(res, model, x, perm, depth)
n = length(x)
depth > n && return
optimize!(model)
if termination_status(model) == MathOptInterface.OPTIMAL
if depth == n
push!(res, value.(x))
return
else
idx = perm[depth+1]
v = value(x[idx])
newcon = #constraint(model, x[idx] == v)
_findallsol!(res, model, x, perm, depth + 1)
delete(model, newcon)
newcon = #constraint(model, x[idx] == 1 - v)
_findallsol!(res, model, x, perm, depth + 1)
delete(model, newcon)
end
end
return
end
Now we can:
julia> m = example_knapsack()
A JuMP Model
Maximization problem with:
Variables: 5
...
Names registered in the model: x
julia> res = findallsol(m, m.obj_dict[:x])
5-element Vector{Vector{Float64}}:
[1.0, 0.0, 0.0, 1.0, 1.0]
[0.0, 0.0, 0.0, 1.0, 1.0]
[1.0, 0.0, 1.0, 1.0, 0.0]
[1.0, 0.0, 0.0, 1.0, 0.0]
[0.0, 1.0, 0.0, 1.0, 0.0]
And we get a vector with all the solutions.
If the problem in question is a boolean problem, this method might be used, as is. In case it has non-boolean variables, the recursion will have to split the feasible space in some even fashion. For example, choosing a variable and cutting its domain in half, and recursing to each half with a smaller domain on this variable (to ensure termination).
P.S. This is not the optimal method. This problem has been well studied. Possible terms to search for are 'model counting' (especially in the boolean domain).
(UPDATE: Changed objective to use FEASIBLE)
My intention is to pass the initial guess as an argument of a function instead of directly defining it in the body of the code.
1)Is there a way to do this without getting: TypeError: cannot unpack non-iterable int object
Also, my additional goal is to use this function to iterate over different initial guesses which also produces a float working when defining for example:
initial_guess = [8, 0.1], [9, 0.1], [10, 0.1], [11, 0.1] and doing:
for i in initial_guess:
...
...
result1 = opt.solve_ocp(
vehicle, horizon, x0, quad_cost, initial_guess[i], log=True,
minimize_method='trust-constr',
minimize_options={'finite_diff_rel_step': 0.01},
)
...
...
return(t1, y1, u1)
2)Is there a way to achieve iteration of various floating parameters for initial_guess list values?
Please note that the optimal control function ocp takes initial_guess as a list in the form initial_guess = [f, g], where f, g floats or integers.
# Set up the cost functions
Q = np.diag([20, 20, 0.01]) # keep lateral error low
R = np.diag([10, 10]) # minimize applied inputs
quad_cost = opt.quadratic_cost(vehicle, Q, R, x0=xf, u0=uf)
# Define the time horizon (and spacing) for the optimization
horizon = np.linspace(0, Tf, Tf, endpoint=True)
# Provide an intial guess (will be extended to entire horizon)
#bend_left = [8, 0.01] # slight left veer
########################################################################################################################
def Approach1(Velocity_guess, Steer_guess):
# Turn on debug level logging so that we can see what the optimizer is doing
logging.basicConfig(
level=logging.DEBUG, filename="steering-integral_cost.log",
filemode='w', force=True)
#constraints = [ opt.input_range_constraint(vehicle, [8, -0.1], [12, 0.1]) ]
initial_guess = [Velocity_guess, Steer_guess]
# Compute the optimal control, setting step size for gradient calculation (eps)
start_time = time.process_time()
result1 = opt.solve_ocp(
vehicle, horizon, x0, quad_cost, initial_guess, log=True,
minimize_method='trust-constr',
minimize_options={'finite_diff_rel_step': 0.01},
)
print("* Total time = %5g seconds\n" % (time.process_time() - start_time))
# If we are running CI tests, make sure we succeeded
if 'PYCONTROL_TEST_EXAMPLES' in os.environ:
assert result1.success
# Extract and plot the results (+ state trajectory)
t1, u1 = result1.time, result1.inputs
t1, y1 = ct.input_output_response(vehicle, horizon, u1, x0)
Final_x_deviation = xf[0] - y1[0][len(y1[0])-1]
Final_y_deviation = xf[1] - y1[1][len(y1[1])-1]
V_variation = uf[0] - u1[0][len(u1[0])-1]
Angle_Variation = uf[1] - u1[1][len(u1[1])-1]
plot_results(t1, y1, u1, xf, uf, Tf, yf=xf[0:2])
return(t1, u1, y1)
I want to sample datas using weighted distribution (probability)
The examples are like below:
class distribution:
doc_distribution = {0: 40, 1: 18, 2: 8, 3: 598, ... , 9: 177}
I would to make the batch of dataset by equal probability of class.
total_dataset = 0
init_dist = []
for value in doc_distribution.values():
total_dataset += value
for value in doc_distribution.values():
init_dist.append(value / total_dataset)
target_dist = []
for value in doc_distribution.values():
target_dist.append(1 / len(doc_distribution))
Then, I make input_fn of tf.estimator to export the model,
def input_fn(ngram_words, labels, opts):
dataset = tf.data.Dataset.from_tensor_slices((ngram_words, labels))
rej = tf.data.experimental.rejection_resample(class_func = lambda _, c : c, \
target_dist = target_dist, initial_dist = init_dist, seed = opts.seed)
dataset = dataset.shuffle(buffer_size = len(ngram_words) * 2, seed = opts.seed)
return dataset.batch(20)
Finally, I could get the result of rejection_resample as below:
for next_elem in a:
k = next_elem[1]
break
dist = {}
for val in np.array(k):
if val in dist:
dist[val] += 1
else:
dist[val] = 1
print(dist)
The result is: {3: 33, 8: 14, 4: 17, 7: 5, 5: 10, 9: 12, 0: 6, 6: 3}
I don't know why rejection_resample doesn't work well, I just want to extract samples equally.
How should I fix it?
Is there any methods to sample equally in input_fn of tf.estimator?
We can use tf.data.experimental.sample_from_datasets instead of rejection_resample.
unbatched_dataset = [(dataset.filter(lambda _, label: label == i)) for i in range(0, classify_num)]
weights = [1 / classify_num] * classify_num
balanced_ds = tf.data.experimental.sample_from_datasets(unbatched_dataset, weights, seed=opts.seed)
dataset = balanced_ds.shuffle(buffer_size = 1000, seed = opts.seed).repeat(opts.epochs)
I am trying to model an ordinal predicted variable using PyMC3 based on the approach in chapter 23 of Doing Bayesian Data Analysis. I would like to determine a good starting value using find_MAP, but am receiving an optimization error.
The model:
import pymc3 as pm
import numpy as np
import theano
import theano.tensor as tt
# Some helper functions
def cdf(x, location=0, scale=1):
epsilon = np.array(1e-32, dtype=theano.config.floatX)
location = tt.cast(location, theano.config.floatX)
scale = tt.cast(scale, theano.config.floatX)
div = tt.sqrt(2 * scale ** 2 + epsilon)
div = tt.cast(div, theano.config.floatX)
erf_arg = (x - location) / div
return .5 * (1 + tt.erf(erf_arg + epsilon))
def percent_to_thresh(idx, vect):
return 5 * tt.sum(vect[:idx + 1]) + 1.5
def full_thresh(thresh):
idxs = tt.arange(thresh.shape[0] - 1)
thresh_mod, updates = theano.scan(fn=percent_to_thresh,
sequences=[idxs],
non_sequences=[thresh])
return tt.concatenate([[-1 * np.inf, 1.5], thresh_mod, [6.5, np.inf]])
def compute_ps(thresh, location, scale):
f_thresh = full_thresh(thresh)
return cdf(f_thresh[1:], location, scale) - cdf(f_thresh[:-1], location, scale)
# Generate data
real_ps = [0.05, 0.05, 0.1, 0.1, 0.2, 0.3, 0.2]
data = np.random.choice(7, size=1000, p=real_ps)
# Run model
with pm.Model() as model:
mu = pm.Normal('mu', mu=4, sd=3)
sigma = pm.Uniform('sigma', lower=0.1, upper=70)
thresh = pm.Dirichlet('thresh', a=np.ones(5))
cat_p = compute_ps(thresh, mu, sigma)
results = pm.Categorical('results', p=cat_p, observed=data)
with model:
start = pm.find_MAP()
trace = pm.sample(2000, start=start)
When running this, I receive the following error:
Applied interval-transform to sigma and added transformed sigma_interval_ to model.
Applied stickbreaking-transform to thresh and added transformed thresh_stickbreaking_ to model.
Traceback (most recent call last):
File "cm_net_log.v1-for_so.py", line 53, in <module>
start = pm.find_MAP()
File "/usr/local/lib/python3.5/site-packages/pymc3/tuning/starting.py", line 133, in find_MAP
specific_errors)
ValueError: Optimization error: max, logp or dlogp at max have non-finite values. Some values may be outside of distribution support. max: {'thresh_stickbreaking_': array([-1.04298465, -0.48661088, -0.84326554, -0.44833646]), 'sigma_interval_': array(-2.220446049250313e-16), 'mu': array(7.68422528308479)} logp: array(-3506.530143064723) dlogp: array([ 1.61013190e-06, nan, -6.73994118e-06,
-6.93873894e-06, 6.03358122e-06, 3.18954680e-06])Check that 1) you don't have hierarchical parameters, these will lead to points with infinite density. 2) your distribution logp's are properly specified. Specific issues:
My questions:
How can I determine why dlogp is nan at certain points?
Is there a different way that I can express this model to avoid dlogp being nan?
Also worth noting:
This model runs fine if I don't find_MAP and use a Metropolis sampler. However, I'd like to have the flexibility of using other samplers as this model becomes more complex.
I have a suspicion that the issue is due to the relationship between the thresholds and the normal distribution, but I don't know how to disentangle them for the optimization.
Regarding question 2: I expressed the model for the ordinal predicted variable (single group) differently; I used the Theano #as_op decorator for a function that calculates probabilities for the outcomes. That also explains why I cannot use find_MAP() or gradient based samplers: Theano cannot calculate a gradient for the custom function. (http://pymc-devs.github.io/pymc3/notebooks/getting_started.html#Arbitrary-deterministics)
# Number of outcomes
nYlevels = df.Y.cat.categories.size
thresh = [k + .5 for k in range(1, nYlevels)]
thresh_obs = np.ma.asarray(thresh)
thresh_obs[1:-1] = np.ma.masked
#as_op(itypes=[tt.dvector, tt.dscalar, tt.dscalar], otypes=[tt.dvector])
def outcome_probabilities(theta, mu, sigma):
out = np.empty(nYlevels)
n = norm(loc=mu, scale=sigma)
out[0] = n.cdf(theta[0])
out[1] = np.max([0, n.cdf(theta[1]) - n.cdf(theta[0])])
out[2] = np.max([0, n.cdf(theta[2]) - n.cdf(theta[1])])
out[3] = np.max([0, n.cdf(theta[3]) - n.cdf(theta[2])])
out[4] = np.max([0, n.cdf(theta[4]) - n.cdf(theta[3])])
out[5] = np.max([0, n.cdf(theta[5]) - n.cdf(theta[4])])
out[6] = 1 - n.cdf(theta[5])
return out
with pm.Model() as ordinal_model_single:
theta = pm.Normal('theta', mu=thresh, tau=np.repeat(.5**2, len(thresh)),
shape=len(thresh), observed=thresh_obs, testval=thresh[1:-1])
mu = pm.Normal('mu', mu=nYlevels/2.0, tau=1.0/(nYlevels**2))
sigma = pm.Uniform('sigma', nYlevels/1000.0, nYlevels*10.0)
pr = outcome_probabilities(theta, mu, sigma)
y = pm.Categorical('y', pr, observed=df.Y.cat.codes.as_matrix())
http://nbviewer.jupyter.org/github/JWarmenhoven/DBDA-python/blob/master/Notebooks/Chapter%2023.ipynb