Pyomo and conditional objective function - nonlinear-optimization

Is it possible (and if so how) to use an objective function that has a conditional expression?
Changing the example from the docs, I would like an expression like:
def objective_function(model):
return model.x[0] if model.x[1] < const else model.x[2]
model.Obj = Objective(rule=objective_function, sense=maximize)
Can this be modelled directly like this or do I have to consider some sort of transformation (and if so how would this look like)?
Just executing the above gives an error message like:
Evaluating Pyomo variables in a Boolean context, e.g.
if expression <= 5:
is generally invalid. If you want to obtain the Boolean value of the
expression based on the current variable values, explicitly evaluate the
expression using the value() function:
if value(expression) <= 5:
or
if value(expression <= 5):
which I think is because Pyomo thinks I'd like to obtain a value, instead of an expression with the variable.

One way to formulate that is by using a logical disjunction. You can look into the Pyomo.GDP documentation for usage, but it would look like:
m.helper_var = Var()
m.obj = Objective(expr=m.helper_var)
m.lessthan = Disjunct()
m.lessthan.linker = Constraint(expr=m.helper_var == m.x[0])
m.lessthan.constr = Constraint(expr=m.x[1] < const)
m.greaterthan = Disjunct()
m.greaterthan.linker = Constraint(expr=m.helper_var == m.x[2])
m.greaterthan.constr = Constraint(expr=m.x[1] >= const)
m.lessthanorgreaterthan = Disjunction(expr=[m.lessthan, m.greaterthan])
# some kind of transformation (convex hull or big-M)
You can also formulate this using complementarity constraints.

Related

CNTK sends an error regarding 'sequence.gather' operator

I am trying to create a model with 'sequence.gather' operator, but getting an error "Where operation can only operate on scalar input" when calling 'train_minibatch'.
input_seq_axis = Axis('inputAxis')
input_sequence = sequence.input_variable(shape=vocab_dim, sequence_axis=input_seq_axis)
vowel_mask_sequence = sequence.input_variable(shape=2, sequence_axis=input_seq_axis)
a = Sequential([
C.layers.Recurrence(C.layers.LSTM(hidden_dim)),
])
b=C.sequence.gather(a(input_sequence),vowel_mask_sequence)
z=Dense(3)(b)
label_sequence = sequence.input_variable(3, sequence_axis=z.dynamic_axes[1])
How can I fix the error ? I even dont use 'where' operator.
For sequence.gather(x, y), y has to be a scalar, that is to say:
assert y.shape == (1,)
The values of y must be either 0 or 1, and also with the same exact dynamic axis as x.
An example on how to use sequence.gather from a library i maintain.

Using $ceil to define a parameter in SystemVerilog in Quartus Prime

Trying to do this
parameter integer PRECHARGE_CLOCKS = $ceil(PRECHARGE_NS / CLOCK_PERIOD_NS);
And then use the value in a comparion
if(InitPrechargeCounter < PRECHARGE_CLOCKS - 1)
But getting this error
Error (10174): Verilog HDL Unsupported Feature error at Ram.sv(23): system function "$ceil" is not supported for synthesis
Is there a way around this so that I get the value calculated at compile time?
Using some different language construct instead of parameter?
Try this:
parameter integer PRECHARGE_CLOCKS = ((PRECHARGE_NS + CLOCK_PERIOD_NS -1) / CLOCK_PERIOD_NS);
It should round up as what $ceil does.
I ended up working around this with the following macro, this creates 2 extra parameters for the sake of rounding up, but this is the best solution I've found so far.
This is not limited to integer arguments and works with real numbers.
I've tested this with Quartus and Modelsim
`define Ceil(ParamName, Expression) \
parameter ParamName``_F = Expression;\
parameter integer ParamName``_R = ParamName``_F;\
parameter integer ParamName = (ParamName``_R == ParamName``_F || ParamName``_R > ParamName``_F) ? ParamName``_R : (ParamName``_R + 1);
And then instead of
parameter integer AUTOREFRESH_CLOCKS = $ceil(UTOREFRESH_NS/CLOCK_PERIOD_NS);
You would invoke the macro
`Ceil(AUTOREFRESH_CLOCKS, UTOREFRESH_NS/CLOCK_PERIOD_NS)
And this is not both synthesizable in Quartus and works in Modelsim

Including time as an explicit variable in constraint in a Pyomo Model

I am using PyOMO to model a semi-batch reaction.
Consider an ODE system that describes a semi-batch reactor where one of the reactants is fed at a given volume flow for t1 units of time, the reaction goes on until t end, and obviously t1 < t end.
To specify the stop in the flow, I can either use a conditional rule (assume t1 = 3.5*60):
def _vol_flow_in_schedule(mod,t):
if t<=3.5*60:
return mod.vol_flow_in[t] == (12.3/1000)/(3.5*60)
else:
return mod.vol_flow_in[t] == 0
m1.vol_flow_in_schedule = Constraint(m1.time,rule=_vol_flow_in_schedule)
which will create a discontinuity (and then my model does not converge). What I want to do is use a sigmoidal function that will transition the flow to zero without a discontinuity.
To implement the sigmoidal though I need to refer to the time variable itself.
The below MATLAB code gives me the result I want:
t=[0:1:500];
acc=2; %Acceleration parameter, higher values yields sharper change.
time_of_step=3.5*60;
init_value = (12.3/1000)/(3.5*60);
end_value = 0;
sigmoidal=(init_value+(end_value-init_value)/2)...
+((end_value-init_value)/2)*atan((t-time_of_step)*acc)/atan(max(t));
This implementation however needs the time variable explicitly in the function. How can I access the time variable inside the PyOMO rule? I tried the below, but I get an " Cannot treat the scalar component 't_of_step' as an array" error:
m1.init_value = Param(initialize = (12.3/1000)/(3.5*60))
m1.end_value = Param(initialize = 0)
m1.t_of_step = Param(initialize = 210)
m1.acc = Param(initialize = 5)
.
.
def _vol_flow_sigmoidal (mod,t):
return mod.vol_flow_in[t] == (mod.init_value+(mod.end_value-mod.init_value)/2)+((mod.end_value-mod.init_value)/2)*atan((t-mod.t_of_step)*mod.acc)/atan(1500)
m1.vol_flow_sigmoidal = Constraint(m1.time,rule=_vol_flow_sigmoidal)
Hopefully I've described clearlyt what I am after. Any hints are most welcome,
Thanks!
Sal
How are you declaring the m1.time index?
My guess is that you are using a NumPy array to initialize the m1.time index. There is a known problem in Pyomo (see Issue #31) where the NumPy operator overloading and the Pyomo operator overloading end up fighting with each other (basically, NumPy gets fooled into thinking Pyomo scalars are actually indexed and attempts to treat them like arrays).
I was able to reproduce the error with the following complete example:
# pyomo 4.4.1
from pyomo.environ import *
import numpy as np
m1 = ConcreteModel()
m1.time = Set(initialize=np.array([0,100,200,300,400,500]))
m1.vol_flow_in = Var(m1.time)
m1.init_value = Param(initialize = (12.3/1000)/(3.5*60))
m1.end_value = Param(initialize = 0)
m1.t_of_step = Param(initialize = 210)
m1.acc = Param(initialize = 5)
def _vol_flow_sigmoidal (mod,t):
return mod.vol_flow_in[t] == (mod.init_value+(mod.end_value-mod.init_value)/2)\
+((mod.end_value-mod.init_value)/2)*atan((t-mod.t_of_step)*mod.acc)/atan(1500)
m1.vol_flow_sigmoidal = Constraint(m1.time,rule=_vol_flow_sigmoidal)
There are two alternatives that do work, both based on avoiding using NumPy arrays to initialize Pyomo Sets. You can either completely avoid Numpy:
m1.time = Set(initialize=[0,100,200,300,400,500])
or explicitly cast the NumPy array to a list:
timeArray = np.array([0,100,200,300,400,500])
m1.time = Set(initialize=timeArray.tolist())
Finally, for completeness, two other notes:
This also applies to initializing ContinuousSet objects in pyomo.dae
You will see the same behavior even if you avoid the explicit Pyomo Set declaration. That is, the following will also generate the error:
m1.time = np.array([0,100,200,300,400,500])
# ...
m1.vol_flow_sigmoidal = Constraint(m1.time,rule=_vol_flow_sigmoidal)
This is because Pyomo will quietly create the Set object for you behind the scenes as m1.vol_flow_sibmodial_index and then use that Set to index the Constraint.

1-line try/catch equivalent in MATLAB

I have a situation in MATLAB where I want to try to assign a struct field into a new variable, like this:
swimming = fish.carp;
BUT the field carp may or may not be defined. Is there a way to specify a default value in case carp is not a valid field? For example, in Perl I would write
my $swimming = $fish{carp} or my $swimming = 0;
where 0 is the default value and or specifies the action to be performed if the assignment fails. Seems like something similar should exist in MATLAB, but I can't seem to find any documentation of it. For the sake of code readability I'd rather not use an if statement or a try/catch block, if I can help it.
You can make your own function to handle this and keep the code rather clear. Something like:
swimming = get_struct(fish, 'carp', 0);
with
function v = get_struct(s, f, d)
if isfield(s, f)
v = s.(f); % Struct value
else
v = d; % Default value
end
Best,
From what I know, you can't do it in one line in MATLAB. MATLAB logical constructs require explicit if/else statements and can't do it in one line... like in Perl or Python.
What you can do is check to see if the fish structure contains the carp field. If it isn't, then you can set the default value to be 0.
Use isfield to help you do that. Therefore:
if isfield(fish, 'carp')
swimming = fish.carp;
else
swimming = 0;
end
Also, as what Ratbert said, you can put it into one line with commas... but again, you still need that if/else construct:
if isfield(fish,'carp'), swimming = fish.carp; else, swimming = 0;
Another possible workaround is to declare a custom function yourself that takes in a structure and a field, and allow it to return the value at the field, or 0.
function [out] = get_field(S, field)
if isfield(S, field)
out = S.(field);
else
out = 0;
end
Then, you can do this:
swimming = get_field(fish, 'carp');
swimming will either by 0, or fish.carp. This way, it doesn't sacrifice code readability, but you'll need to create a custom function to do what you want.
If you don't like to define a custom function in a separate function file - which is certainly a good option - you can define two anonymous functions at the beginning of your script instead.
helper = {#(s,f) 0, #(s,f) s.(f)}
getfieldOrDefault = #(s,f) helper{ isfield(s,f) + 1 }(s,f)
With the definition
fish.carp = 42
and the function calls
a = getfieldOrDefault(fish,'carp')
b = getfieldOrDefault(fish,'codfish')
you get for the first one
a = 42
and the previous defined default value for the second case
b = 0

loop starting from given index

Considering the following javascript, what's the best way to write this loop in coffee script, given the initial index is greater than 0:
function mixin(target, source, methods) {
for (var i = 2, l = arguments.length; i < l; i++){
var method = arguments[i];
target[method] = source[method].bind(source)
}
}
Automatic code converters suggest use a while loop like this:
mixin = (target, source, methods) ->
i = 2
l = arguments.length
while i < l
method = arguments[i]
target[method] = source[method].bind(source)
i++
Is there a cleaner way to do this?
You'd usually use a splat in CoffeeScript when defining your mixing function:
The JavaScript arguments object is a useful way to work with functions that accept variable numbers of arguments. CoffeeScript provides splats ..., both for function definition as well as invocation, making variable numbers of arguments a little bit more palatable.
So you'd say:
mixin = (target, source, methods...) ->
# splat ----------------------^^^
for method in methods
target[method] = source[method].bind(source)
and your problem goes away. The splat in the argument list will collect all the arguments after source into a methods array for you so you won't have to worry about arguments at all; the splat also makes the function's signature nice and obvious.
Use an exclusive range (triple dot, excludes the number at the highest.
for i in [2...arguments.length]
method = arguments[i]
target[method] = source[method].bind(source)
If you have 5 things in your args, this will hit indexes 2, 3 and 4.