What should I do abs in objectfunction - abstract

I want to find an expression with an absolute value as an objective function in gurobi. Specifically, it is an expression such as ∑_j ∈ J | ∑_i ∈ P x_ij-d_i *t_i |.
The variable is x_ij, and the others are constants. I tried and errored this formula using abs (), but I couldn't figure it out in the end. I would appreciate it if you could tell me.
model.setObjective(quicksum(quicksum((x[i,j] for i in P)-d[i]*t[i]) for j in W),GRB.MINIMIZE)
#objectfunction
what should I change this?

You could add additional helper variables and then use Gurobi's general abs constraints:
import gurobipy as gp
from gurobipy import quicksum, GRB
# ...your model and sets W, P, J...
helper1 = model.addVars(W, lb=GRB.INFINITY, vtype="C")
helper2 = model.addVars(W, vtype="C")
for j in W:
model.addConstr(helper1[j] == quicksum(x[i,j]-d[i]*t[i] for i in P))
model.addConstr(helper2[j] == gp.abs_(helper1[j]))
model.setObjective(quicksum(helper2[j] for j in W), GRB.MINIMIZE)

Related

Python - How to parse Boolean Sympy tree expressions to Boolean Z3Py expressions

I have some CNFs of Boolean expressions from the logic module in Sympy.
I get their Sympy expression trees with srepr() (see documentation).
Find below an example with two CNFs.
from sympy import Symbol
from sympy.logic.boolalg import And, Or, Not
# (a | ~c) & (a | ~e) & (c | e | ~a)
expr_1 = And(Or(Symbol('a'), Not(Symbol('c'))), Or(Symbol('a'), Not(Symbol('e'))), Or(Symbol('c'), Symbol('e'), Not(Symbol('a'))))
# (b | ~d) & (b | ~e) & (d | e | ~b)
expr_2 = And(Or(Symbol('b'), Not(Symbol('d'))), Or(Symbol('b'), Not(Symbol('e'))), Or(Symbol('d'), Symbol('e'), Not(Symbol('b'))))
I want to give those expression trees to a Z3Py solver as Boolean constraints.
For that, I think that need to:
transform sympy.Symbol() to z3.Bool(), and
transform the sympy logic operators to Z3 logic operators (e.g., sympy.logic.boolalg.And() to z3.And())
Then, I would add the constraints to a Z3 solver to output a solution.
If we continue with the example, as I see it, we would have the two following constraints (I wrote explicitly that I use Z3 Boolean operators to avoid confusion with the Sympy ones):
import z3 as z3
from z3 import Bool
const_1 = z3.And(z3.Or(Bool('a'), z3.Not(Bool('c'))), z3.Or(Bool('a'), z3.Not(Bool('e'))), z3.Or(Bool('c'), Bool('e'), z3.Not(Bool('a'))))
const_2 = z3.And(z3.Or(Bool('b'), z3.Not(Bool('d'))), z3.Or(Bool('b'), z3.Not(Bool('e'))), z3.Or(Bool('d'), Bool('e'), z3.Not(Bool('b'))))
How could we parse Sympy Boolean expression trees for Z3Py in an automated fashion? Is there a better way to do it than what I presented as an example?
You're on the right track. Essentially, you need to "compile" SymPy to Z3. This can be achieved in a variety of ways, but it's not a cheap/easy thing to do since you'd need to analyze large swaths of SymPy code. However, looks like your expressions are "simple" enough, so you can get away with a simple translator. Start by looking at how SymPy trees can be recursively processed: https://docs.sympy.org/latest/tutorials/intro-tutorial/manipulation.html#recursing-through-an-expression-tree
If you're in a hurry, you can use Axel's program, given in the other answer. Here's a version that is probably a bit more idiomatic and easier to extend and more robust:
import sympy
import z3
# Sympy vs Z3. Add more correspondences as necessary!
table = { sympy.logic.boolalg.And : z3.And
, sympy.logic.boolalg.Or : z3.Or
, sympy.logic.boolalg.Not : z3.Not
, sympy.logic.boolalg.Implies: z3.Implies
}
# Sympy vs Z3 Constants
constants = { sympy.logic.boolalg.BooleanTrue : z3.BoolVal(True)
, sympy.logic.boolalg.BooleanFalse: z3.BoolVal(False)
}
def compile_to_z3(exp):
"""Compile sympy expression to z3"""
pexp = sympy.parsing.sympy_parser.parse_expr(exp)
pvs = {v: z3.Bool(str(v)) for v in pexp.atoms() if type(v) not in constants}
def cvt(expr):
if expr in pvs:
return pvs[expr]
texpr = type(expr)
if texpr in constants:
return constants[texpr]
if texpr in table:
return table[texpr](*map(cvt, expr.args))
raise NameError("Unimplemented: " + str(expr))
return cvt(pexp)
if __name__ == '__main__':
z3.solve(compile_to_z3("false"))
z3.solve(compile_to_z3("a & ~b | c"))
z3.solve(compile_to_z3("false >> (a & ~b | c)"))
This prints:
no solution
[c = False, b = False, a = True]
[]
You can add new functions to table to extend it as you see fit.
I couldn't resist and implemented a basic converter.
from sympy import symbols
from sympy.parsing.sympy_parser import parse_expr
from z3 import *
# extract all variables and define a SymPy expression
def create_sympy_expression(expr):
declare_sympy_symbols(expr)
return parse_expr(expr)
# assume all single-character operands as SymPy variables
dicz3sym = {}
def declare_sympy_symbols(expr):
for c in expr:
if 'a' <= c <= 'z':
if not c in dicz3sym:
dicz3sym[c] = z3.Bool(c)
def transform_sympy_to_z3(exp):
params = [transform_sympy_to_z3(arg) for arg in exp.args]
func = str(exp.func)
if func == "And":
return z3.And(params)
elif func == "Not":
return z3.Not(params[0])
elif func == "Or":
return z3.Or(params)
elif exp.name in dicz3sym:
return dicz3sym[exp.name]
else:
raise NameError("unknown/unimplemented operator: " + func)
if __name__ == '__main__':
exp = create_sympy_expression("a & ~b | c")
z3exp = transform_sympy_to_z3(exp)
s = Solver()
s.add(z3exp)
if s.check() == sat:
m = s.model()
print("Solution found:")
for v in dicz3sym:
print(f"{v} = {m[dicz3sym[v]]}")
else:
print("No solution. Sorry!")

python 'concatenate' requires extra parentheses

I'm trying to concatenate 3 lists. When I try to use concatenate, like so, I get an error (TypeError: 'list' object cannot be interpreted as an integer):
import numpy as np
a = [1]
b = [2]
c = [3]
z = np.concatenate(a, b, c)
But if I put "extra" parentheses, it works like so:
z = np.concatenate((a, b, c))
Why?
I am not sure what library you are using (concatenate is not a built-in python 3.x function). However, I'll explain what I think is going on.
When you call concatenate(a, b, c), the function concatenate is sent three parameters: a, b, and c. concatenate then performs some logic that is (presumably) not the desired behavior.
When you call concatenate((a, b, c)), a tuple (effectively a list that cannot be changed) is created with a value of (a, b, c), which is evaluated to ([1], [2], [3]). Then this tuple is passed to the concatenate function. The following code is actually equivalent to your second code snippet:
a = [1]
b = [2]
c = [3]
y = (a, b, c) # This evaluates to ([1], [2], [3]).
z = concatenate(y)
I hope I've explained this clearly enough. Here's an article that explains tuples in more depth, if I haven't: https://www.w3schools.com/python/python_tuples.asp
EDIT: Thanks for including the library. Here's the code for what you're probably trying to do:
import numpy as np
a = [1]
b = [2]
c = [3]
z = np.array(a + b + c) # Lists can be concatenated using the `+` operator. Then, to make a numpy array, just call the constructor

How can one represent distinct non-numeric symbols in sympy?

I am experimenting with the representation of a trivial statistics problem in Sympy:
For a sample space S, there are 6 possible distinct outcomes
a,b,c,d,e,f. We can define event A as having occurred if any of
a,b,c have, and event B as having ocurred if any of b,c,d have.
Given a probability mass function pmf defined over S, what is the
probability of event A?
When attempting to implement this symbolically, I receive the following error:
~/project/.envs/dev/lib/python3.6/site-packages/sympy/stats/frv.py in _test(self, elem)
164 elif val.is_Equality:
165 return val.lhs == val.rhs
--> 166 raise ValueError("Undecidable if %s" % str(val))
167
168 def __contains__(self, other):
ValueError: Undecidable if Eq(d, a) | Eq(d, b) | Eq(d, c)
The problem is implemented as follows with comments on the failing lines of code:
from sympy import Eq, Function, symbols
from sympy.logic import Or
from sympy.sets import FiniteSet, Union
from sympy.stats import FiniteRV, P
# 1. Define a sample space S with outcomes: a,b,c,d,e,f; Define events A, B
A = FiniteSet(*symbols('a b c'))
B = FiniteSet(*symbols('b c d'))
S = Union(A, B, FiniteSet(*symbols('e f')))
display("Sample Space", S)
pmfFunc = Function("pmf")
pmfDict = {v: pmfFunc(v) for v in S}
X = FiniteRV('X', pmfDict)
a,b = symbols('a b')
# 2. P(X = a) = pmf(a)
display(P(Eq(X,a)))
# 3. A.as_relational(X) yields `(X=a) \lor (X=b) \lor (X=c)`
display(A.as_relational(X))
# 4. P(X = a \lor X = b) = pmf(a) + pmf(b)
# - Actual Output: ValueError: Undecidable if Eq(c, a) | Eq(c, b)
display(P(Or(Eq(X,a), Eq(X,b)))) # [FAILS]
# 5. P(A) = pmf(a) + pmf(b) + pmf(c)
# - Actual Output: ValueError: Undecidable if Eq(d, a) | Eq(d, b) | Eq(d, c)
display(P(A.as_relational(X))) # [FAILS]
I obtain expected output up to display(A.as_relational(X)):
Interpreting the failure message suggests that Sympy is unable to tell that the set members are distinct. Replacing the symbols with integers resolves the error and I get output similar to what I desire.
A = FiniteSet(1, 2, 3)
B = FiniteSet(2, 3, 4)
S = Union(A, B, FiniteSet(5, 6))
If I am not misunderstanding the error or the fundamental use of the library, is there a way to tell Sympy that a collection of symbols is entirely distinct? I have attempted to replace the symbols with Dummy instances without success, and I have also attempted to leverage the assumptions module without success:
facts = [Eq(a,b) if a is b else Not(Eq(a,b)) for a, b in itertools.product(S, S)]
with assuming(*facts):
I would like to avoid confusing mappings between integers and symbolic forms, as user error may not be apparent when the results are printed as latex. I am willing to adopt some burden in a workaround (e.g., as it would have been maintaining a collection of Dummy instances), but I have yet to find an acceptable workaround.
Interesting question. Maybe it can be done with with assuming(Ne(a,b), ...): context but I take a more pragmatic approach: replace symbols with cos(non-zero integer) which SymPy can easily distinguish as equal or not:
>>> reps = dict(zip(var('a:f'),(cos(i) for i in range(1,7))))
>>> ireps = {v:k for k,v in reps.items()}
>>> a,b,c,d,e,f = [reps[i] for i in var('a:f')]
Then remove your a, b = symbols... line and replace display(x) with display(x.subs(ireps) to get
('Sample Space', FiniteSet(a, b, c, d, e, f))
(pmf(a),)
(Eq(X, a) | Eq(X, b) | Eq(X, c),)
(pmf(a) + pmf(b),)
(I use cos(int) instead of int because I am not sure whether any computation would result in addition of two elements and I want to make sure they stay distinct.)
Another approach would be to define a constant class that derives from Symbol:
class con(Symbol):
def __hash__(self):
return id(self)
def __eq__(a,b):
if isinstance(b, con):
return a.name == b.name
_eval_Eq = __eq__
a,b,c,d,e,f=map(con,'abcdef')
display=lambda*x:print(x)
from sympy import Eq, Function, symbols
from sympy.logic import Or
from sympy.sets import FiniteSet, Union
from sympy.stats import FiniteRV, P
A = FiniteSet(a,b,c)
B = FiniteSet(b,c,d)
S = Union(A, B, FiniteSet(e,f))
pmfFunc = Function("pmf")
pmfDict = {v: pmfFunc(v) for v in S}
X = FiniteRV('X', pmfDict)
display("Sample Space", S)
display(P(Eq(X,a)))
display(A.as_relational(X))
display(P(Or(Eq(X,a), Eq(X,b))))
display(P(A.as_relational(X)))
gives
('Sample Space', FiniteSet(a, b, c, d, e, f))
(pmf(a),)
(Eq(X, a) | Eq(X, b) | Eq(X, c),)
(pmf(a) + pmf(b),)
(pmf(a) + pmf(b) + pmf(c),)

How to write a cycle for creating numpy arrays?

How to write this in cycle, please?
k1 = np.empty(np.shape(u))
k2 = np.empty(np.shape(u))
k3 = np.empty(np.shape(u))
k4 = np.empty(np.shape(u))
I tried:
k = [k1, k2, k3, k4]
for i in k:
i = np.empty(np.shape(u))
k.append(i)
You can simply use list comprehension to create an arbitrary number of empty numpy arrays
num = 10
result = [np.empty(np.shape(u)) for _ in range(num)]
It is not a good practice to do this, so I would recommend using lists or dictionaries but here's the code to achieve what you asked for-
for x in range(0, n): #Replace n with the value you need
globals()['k%s' % x] = np.empty(np.shape(u))
and then for example:
print(k1)
But again this is a bad practice, use dictionaries instead

Lambdify A Parametric Integral

I have the following issue: I want to lambdify a sympy expression containing parametric integrals like Integral(tanh(a*x),(x,0,1)). I tried to do a manual implementation like here.
What we want is essentially that the integral gets converted to something like:
lambda theta: quad(lambda x: g(x,theta), a,b)[0]
where
g = sp.lambdify((x,param), f, modules='numpy'))
Consider the following MWE:
import sympy as sp
import numpy as np
from scipy.integrate import quad
def integral_as_quad(function, limits):
x, a, b = limits
param = function.free_symbols - {x}
f = sp.lambdify( (x,*param), function, modules='numpy')
return lambda y: quad(lambda x: f(x,y), a,b)[0]
a, x = sp.symbols('a,x')
I = sp.Integral(sp.tanh(a*x),(x,0,1))
K = integral_as_quad(sp.tanh(a*x),(x,0,1))
L = sp.lambdify(a, I, modules=['numpy', {'Integral':integral_as_quad}] )
Then calling for example K(1) returns the correct value. However L(1) gives
AttributeError: 'Mul' object has no attribute 'tanh'
Does anyone have an idea how to fix this?
NOTE: Doing it manually is no option, since the expressions I deal with are way more complicated and may contain several different integrals. So I really need to get the lambdify working.
I think returning a lambda from integral_as_quad cannot work, because this lambda will never be called, as the Integral object in SymPy is not callable. Instead, the parameter tuple can be passed to quad via its args argument. Another change I made is in the outer lambdification, replacing
modules=['numpy', {'Integral':integral_as_quad}]
with
modules=[{'Integral': integral_as_quad}, 'sympy']
The idea is that at this stage we don't need NumPy functions yet, we just want to replace the Integral by our callable. The order of modules list matters: the dictionary comes first to prevent SymPy from keeping Integral as an Integral.
Now L(1) returns the correct amount.
import sympy as sp
import numpy as np
from scipy.integrate import quad
def integral_as_quad(function, limits):
x, a, b = limits
param = tuple(function.free_symbols - {x})
f = sp.lambdify((x, *param), function, modules=['numpy'])
return quad(f, a, b, args=param)[0]
a, x = sp.symbols('a,x')
I = sp.Integral(sp.tanh(a*x), (x,0,1))
L = sp.lambdify(a, I, modules=[{'Integral': integral_as_quad}, 'sympy'])
So one possible workaround I have found, but I am unhappy with because it is too slow for my application, is the following:
def to_lambda(expr, param):
# Preprocessing
expr = expr.evalf()
f = sp.lambdify([param], expr, modules='sympy')
fun = lambda x: np.array(np.array(f(x).evalf()), dtype='float64')
return fun
So first, expr gets cast into a lambda function using sympy-functions, e.g. we have
f = lambda a: Integral(tanh(a*x),(x,0,1))
and then we use sympy's internal integrator via evalf() (slow!).
Also, don't ask me why theres the double np.array, if one puts the dtype='float64' into the first one, then it returns TypeError: __array__() takes 1 positional argument but 2 were given

Resources