git-subtree-dir: software/mza git-subtree-split: f970a59b177c13ca3dd8aaef8cc6681d83b7e813
1416 lines
37 KiB
Python
1416 lines
37 KiB
Python
##@mainpage MiniZinc Python Interface
|
|
# @author Tai Tran
|
|
# @supervisor Guido Tack
|
|
|
|
|
|
#@Things to add:
|
|
# Improve the interface so that there is no need to assign MZN_STDLIB_DIR when starting python
|
|
# args_ret_dict: some functions type checking are not written
|
|
# Hide some internal functions such as flatten or type_presentation
|
|
|
|
#@Suggestion:
|
|
# Remove the user-defined name when declaring variable
|
|
# Consider replacing it with i, where i is the number of arguments created
|
|
# for example: calling [a,b,c] = m.Variable(1,100,3)
|
|
|
|
'''
|
|
@Usage:
|
|
definition:
|
|
lb: lower bound,
|
|
ub: upper bound,
|
|
set:minizinc.Model.Set)
|
|
|
|
|
|
* Declaration *
|
|
|
|
minizinc.Model:
|
|
accepts 1 optional argument:
|
|
a string or list of strings indicating libraries to be included.
|
|
returns:
|
|
model to be used, for example:
|
|
m = minizinc.Model
|
|
i = m.Variable
|
|
s = m.Set
|
|
m.Constraint
|
|
m.satisfy
|
|
etc..
|
|
minizinc.Model.Set:
|
|
accepts multiple arguments:
|
|
item1, item2, ... itemn
|
|
item?: a number - single element
|
|
or a list/tuple of 2 elements - elements ranging from lb to ub
|
|
returns:
|
|
an object to be used
|
|
functions:
|
|
push - push more elements onto the set
|
|
clear - clear all elements in the set
|
|
minizinc.Model.Variable:
|
|
accepts up to 2 arguments:
|
|
<None> : a boolean variable
|
|
ub : a variable ranging from 0 to ub - 1
|
|
lb, ub : a variable ranging from lb to ub
|
|
set : a variable based on the set
|
|
minizinc.Model.Array:
|
|
minizinc.Model.Construct:
|
|
|
|
|
|
|
|
|
|
* Functions *
|
|
minizinc.Model.satisfy
|
|
minizinc.Model.next
|
|
'''
|
|
|
|
import sys
|
|
import minizinc_internal
|
|
import predicate
|
|
import annotation
|
|
#import inspect
|
|
|
|
if sys.version < '3':
|
|
integer_types = (int, long, )
|
|
python_types = (int, long, float, bool, str)
|
|
int_t = long
|
|
def longify(x):
|
|
return long(x)
|
|
else:
|
|
integer_types = (int, )
|
|
python_types = (int, float, bool, str)
|
|
int_t = int
|
|
def longify(x):
|
|
return x
|
|
|
|
# turns a complex structure of items into a list of items
|
|
def flatten(x):
|
|
result = []
|
|
for el in x:
|
|
if isinstance(el, (list, tuple)):
|
|
result.extend(flatten(el))
|
|
else:
|
|
result.append(el)
|
|
return result
|
|
|
|
# nicely presents the type of a variable
|
|
def type_presentation(x):
|
|
if x is None:
|
|
return "Any_Type"
|
|
if type(x) is type:
|
|
name = x.__name__
|
|
if name[:9] == 'minizinc.':
|
|
name = name[9:]
|
|
return name
|
|
else:
|
|
if type(x) is tuple:
|
|
ret = '('
|
|
for i, t in enumerate(x):
|
|
if i != 0:
|
|
ret += ', '
|
|
ret += type_presentation(t)
|
|
ret += ')'
|
|
elif type(x) is list:
|
|
ret = 'array' + str(len(x)) + 'd of ' + type_presentation(x[0])
|
|
else:
|
|
raise TypeError('Type Presentation: Unexpected type: ' + type(x))
|
|
return ret
|
|
|
|
|
|
|
|
# All MiniZinc objects derived from here
|
|
class Expression(object):
|
|
def __init__(self, model = None):
|
|
self.model = model
|
|
|
|
def __str__(self):
|
|
return str(self.get_value())
|
|
|
|
def is_decl(self):
|
|
return isinstance(self, Declaration)
|
|
|
|
def is_pre(self):
|
|
return isinstance(self, Predicate)
|
|
|
|
def evaluate(self, var):
|
|
if isinstance(var, Expression):
|
|
ret = var.get_value()
|
|
if ret == None:
|
|
raise ValueError("'" + var.name + "'Variable value is not set")
|
|
return ret
|
|
else:
|
|
return var
|
|
|
|
def eval_type(self, args):
|
|
if isinstance(args, Expression):
|
|
return args.type
|
|
elif type(args) in integer_types:
|
|
return int_t
|
|
elif type(args) in (float, bool, str):
|
|
return type(args)
|
|
elif type(args) is list:
|
|
t = None
|
|
for i in args:
|
|
if t is None:
|
|
t = self.eval_type(i)
|
|
else:
|
|
type_i = self.eval_type(i)
|
|
if t != type_i:
|
|
raise TypeError("Type of arguments in an array must be the same: expected: " +
|
|
type_presentation((t,)) + ", received: " + type_presentation((type_i,)) )
|
|
return [t]
|
|
elif type(args) is tuple:
|
|
t = []
|
|
for i in args:
|
|
t.append(self.eval_type(i))
|
|
return tuple(t)
|
|
else:
|
|
raise TypeError("Unexpected Type: " + type_presentation(type(args)) )
|
|
|
|
def __and__(self, pred):
|
|
return And( self, pred )
|
|
|
|
def __rand__(self, pred):
|
|
return And( self, pred )
|
|
|
|
def __or__(self, pred):
|
|
return Or( self, pred )
|
|
|
|
def __xor__(self, pred):
|
|
return Xor( self, pred )
|
|
|
|
def __ror__(self, pred):
|
|
return Or( self, pred )
|
|
|
|
def __add__(self, pred):
|
|
return Add( self, pred )
|
|
|
|
def __radd__(self, pred):
|
|
return Add( pred, self )
|
|
|
|
def __sub__(self, pred):
|
|
return Sub( self, pred )
|
|
|
|
def __rsub__(self, pred):
|
|
return Sub( pred, self )
|
|
|
|
def __div__(self, pred):
|
|
return Div( self, pred )
|
|
|
|
def __rdiv__(self, pred):
|
|
return Div( pred, self )
|
|
|
|
def __floordiv__(self, pred):
|
|
return FloorDiv( self, pred )
|
|
|
|
def __rfloordiv__(self, pred):
|
|
return FloorDiv( pred, self )
|
|
|
|
def __mul__(self, pred):
|
|
return Mul( self, pred )
|
|
|
|
def __rmul__(self, pred):
|
|
return Mul( self, pred )
|
|
|
|
def __mod__(self, pred):
|
|
return Mod( self, pred )
|
|
|
|
def __rmod__(self, pred):
|
|
return Mod( pred, self )
|
|
|
|
def __pow__(self, pred):
|
|
return Pow( self, pred )
|
|
|
|
def __rpow__(self, pred):
|
|
return Pow( pred, self )
|
|
|
|
def __eq__(self, pred):
|
|
return Eq( self, pred )
|
|
|
|
def __ne__(self, pred):
|
|
return Ne( self, pred )
|
|
|
|
def __lt__(self, pred):
|
|
return Lt( self, pred )
|
|
|
|
def __gt__(self, pred):
|
|
return Gt( self, pred )
|
|
|
|
def __le__(self, pred):
|
|
return Le( self, pred )
|
|
|
|
def __ge__(self, pred):
|
|
return Ge( self, pred )
|
|
|
|
def __neg__(self):
|
|
return Neg( self )
|
|
|
|
def __pos__(self):
|
|
return Pos( self )
|
|
|
|
def __invert__(self):
|
|
return Invert( self )
|
|
|
|
def __abs__(self):
|
|
return Abs( self )
|
|
|
|
|
|
# Temporary container for Expression before evaluating to minizinc_internal object
|
|
# Calling Predicate.init automatically check:
|
|
# if the arguments belong to the same model
|
|
class Predicate(Expression):
|
|
def __init__(self, vars, args_and_return_type_tuple = None, name = None, model = None):
|
|
self.vars = vars
|
|
self.name = str(name)
|
|
|
|
def eval_model(args):
|
|
model = None
|
|
for val in args:
|
|
if isinstance(val, Expression):
|
|
if hasattr(val, 'model'):
|
|
if val.model is not None:
|
|
if model is None:
|
|
model = val.model
|
|
elif model != val.model:
|
|
raise TypeError("Arguments in the Predicate don't belong to the same model")
|
|
return model
|
|
|
|
self.vars_type = self.eval_type(vars)
|
|
self.model = eval_model(vars)
|
|
if args_and_return_type_tuple is not None:
|
|
for t in args_and_return_type_tuple:
|
|
def check_type(expected, actual):
|
|
if expected is None:
|
|
return True
|
|
if len(expected) != len(actual):
|
|
return False
|
|
for i, val in enumerate(expected):
|
|
if (val is None):
|
|
pass
|
|
elif type(val) is list and type(actual[i]) is list:
|
|
if check_type(val, actual[i]) == False:
|
|
return False
|
|
elif type(val) != type(actual[i]):
|
|
return False
|
|
return True
|
|
if check_type(t[0], self.vars_type):
|
|
#self.vars_type == t[0]:
|
|
self.type = t[1]
|
|
break
|
|
else:
|
|
s = "MiniZinc: function '" + self.name + "': Argument type does not match, expected: "
|
|
for i, t in enumerate(args_and_return_type_tuple):
|
|
if i != 0:
|
|
s += ' or '
|
|
s += type_presentation(t[0])
|
|
s += ', received: ' + type_presentation(self.vars_type)
|
|
raise TypeError(s)
|
|
else:
|
|
self.type = None
|
|
Expression.__init__(self)
|
|
|
|
|
|
class BinOp(Predicate):
|
|
def __init__(self, vars, code, args_and_return_type_tuple, name):
|
|
Predicate.__init__(self,vars,args_and_return_type_tuple, name)
|
|
self.BinOpCode = code
|
|
|
|
class UnOp(Predicate):
|
|
def __init__(self, vars, code, args_and_return_type_tuple, name):
|
|
Predicate.__init__(self,vars, args_and_return_type_tuple, name)
|
|
self.UnOpCode = code
|
|
|
|
class Call(Predicate):
|
|
def __init__(self, vars, code, args_and_return_type_tuple = None, name = None, model_list = None):
|
|
Predicate.__init__(self,vars, args_and_return_type_tuple, name)
|
|
self.CallCode = code
|
|
self.model_list = model_list
|
|
|
|
|
|
|
|
args_ret_dict = {}
|
|
|
|
to_assign = [ ((int_t, int_t), int_t ),
|
|
((float, float), float ),
|
|
((int_t, float), float ),
|
|
((float, int_t), float)]
|
|
args_ret_dict['add'] = to_assign
|
|
args_ret_dict['sub'] = to_assign
|
|
args_ret_dict['mul'] = to_assign
|
|
args_ret_dict['div'] = to_assign
|
|
args_ret_dict['floordiv'] = to_assign
|
|
args_ret_dict['pow'] = to_assign
|
|
|
|
|
|
args_ret_dict['mod'] =[ ((int_t, int_t), int_t )]
|
|
|
|
to_assign = [ ((int_t, int_t), bool ),
|
|
((float, float), bool ),
|
|
((bool, bool), bool ),
|
|
((str, str), bool ),
|
|
((minizinc_internal.VarSet, minizinc_internal.VarSet), bool)]
|
|
args_ret_dict['lt'] = to_assign
|
|
args_ret_dict['le'] = to_assign
|
|
args_ret_dict['gt'] = to_assign
|
|
args_ret_dict['ge'] = to_assign
|
|
args_ret_dict['eq'] = to_assign
|
|
args_ret_dict['ne'] = to_assign
|
|
|
|
|
|
|
|
args_ret_dict['in'] = [ ((int_t, minizinc_internal.VarSet), bool) ]
|
|
|
|
|
|
to_assign = [ ((bool, bool), bool) ]
|
|
args_ret_dict['or'] = to_assign
|
|
args_ret_dict['and'] = to_assign
|
|
args_ret_dict['xor'] = to_assign
|
|
|
|
args_ret_dict['abort'] = [ ((), bool)]
|
|
to_assign = [ ((int_t,), int_t),
|
|
((float,), float) ]
|
|
args_ret_dict['abs'] = to_assign
|
|
args_ret_dict['neg'] = to_assign
|
|
args_ret_dict['pos'] = to_assign
|
|
args_ret_dict['invert'] = to_assign
|
|
|
|
args_ret_dict['array1d'] = [ (None, [int_t]) ] #the function has checked its argument already
|
|
args_ret_dict['array2d'] = [ (None, [int_t, int_t]) ]
|
|
args_ret_dict['array3d'] = [ (None, [int_t, int_t, int_t]) ]
|
|
args_ret_dict['array4d'] = [ (None, [int_t, int_t, int_t, int_t])]
|
|
args_ret_dict['array5d'] = [ (None, [int_t, int_t, int_t, int_t, int_t])]
|
|
args_ret_dict['array6d'] = [ (None, [int_t, int_t, int_t, int_t, int_t, int_t])]
|
|
|
|
to_assign = [ ((float,), float) ]
|
|
args_ret_dict['sin'] = to_assign
|
|
args_ret_dict['cos'] = to_assign
|
|
args_ret_dict['tan'] = to_assign
|
|
args_ret_dict['asin'] = to_assign
|
|
args_ret_dict['acos'] = to_assign
|
|
args_ret_dict['atan'] = to_assign
|
|
args_ret_dict['sinh'] = to_assign
|
|
args_ret_dict['cosh'] = to_assign
|
|
args_ret_dict['tanh'] = to_assign
|
|
args_ret_dict['asinh'] = to_assign
|
|
args_ret_dict['acosh'] = to_assign
|
|
args_ret_dict['atanh'] = to_assign
|
|
args_ret_dict['sqrt'] = to_assign
|
|
args_ret_dict['ln'] = to_assign
|
|
args_ret_dict['log2'] = to_assign
|
|
args_ret_dict['log10'] = to_assign
|
|
args_ret_dict['exp'] = to_assign
|
|
|
|
args_ret_dict['log'] = [ ((float, float), float) ]
|
|
|
|
|
|
args_ret_dict['assert'] = [ ((bool, str), bool) ]
|
|
args_ret_dict['bool2int'] = [ ((bool,), int_t) ]
|
|
# XXX what to do with cardinality?
|
|
args_ret_dict['card'] = None
|
|
|
|
to_assign = [ ((float,), int_t) ]
|
|
args_ret_dict['ceil'] = to_assign
|
|
args_ret_dict['floor'] = to_assign
|
|
args_ret_dict['round'] = to_assign
|
|
|
|
to_assign = [ ((int_t,), float) ]
|
|
args_ret_dict['int2float'] = to_assign
|
|
# XXX consider remove
|
|
args_ret_dict['concat'] = None
|
|
|
|
|
|
to_assign = [ ((int_t, int_t), int_t),
|
|
((float, float), float),
|
|
(([int_t],), int_t),
|
|
(([float],), float) ]
|
|
args_ret_dict['min'] = to_assign
|
|
args_ret_dict['max'] = to_assign
|
|
|
|
to_assign = [ (([int_t], ), int_t),
|
|
(([float], ), float) ]
|
|
args_ret_dict['product'] = to_assign
|
|
args_ret_dict['sum'] = to_assign
|
|
|
|
|
|
del to_assign
|
|
|
|
|
|
|
|
class Add(BinOp):
|
|
def __init__(self, *vars):
|
|
BinOp.__init__(self, vars, 0, args_ret_dict['add'], '+')
|
|
|
|
def get_symbol(self):
|
|
return '+'
|
|
|
|
def get_value(self):
|
|
lhs = self.evaluate(self.vars[0])
|
|
rhs = self.evaluate(self.vars[1])
|
|
if isinstance(rhs, str):
|
|
lhs = str(lhs)
|
|
elif isinstance(lhs, str):
|
|
rhs = str(rhs)
|
|
return lhs + rhs
|
|
|
|
class Sub(BinOp):
|
|
def __init__(self, *vars):
|
|
BinOp.__init__(self, vars, 1, args_ret_dict['sub'], '-')
|
|
|
|
def get_symbol(self):
|
|
return '-'
|
|
|
|
def get_value(self):
|
|
return self.evaluate(self.vars[0]) - self.evaluate(self.vars[1])
|
|
|
|
class Mul(BinOp):
|
|
|
|
def __init__(self, *vars):
|
|
BinOp.__init__(self, vars, 2, args_ret_dict['mul'], '*')
|
|
|
|
def get_symbol(self):
|
|
return '*'
|
|
|
|
def get_value(self):
|
|
return self.evaluate(self.vars[0]) * self.evaluate(self.vars[1])
|
|
|
|
class Div(BinOp):
|
|
|
|
def __init__(self, *vars) :
|
|
BinOp.__init__(self, vars, 3, args_ret_dict['div'], '/')
|
|
|
|
def get_symbol(self):
|
|
return '/'
|
|
|
|
def get_value(self):
|
|
return self.evaluate(self.vars[0]) / self.evaluate(self.vars[1])
|
|
|
|
class FloorDiv(BinOp):
|
|
|
|
def __init__(self, *vars) :
|
|
BinOp.__init__(self, vars, 4, args_ret_dict['floordiv'], '//')
|
|
|
|
def get_symbol(self):
|
|
return '//'
|
|
|
|
def get_value(self):
|
|
return self.evaluate(self.vars[0]) // self.evaluate(self.vars[1])
|
|
|
|
|
|
class Mod(BinOp):
|
|
|
|
def __init__(self, *vars):
|
|
BinOp.__init__(self, vars, 5, args_ret_dict['mod'], '%')
|
|
|
|
def get_symbol(self):
|
|
return '%'
|
|
|
|
def get_value(self):
|
|
return self.evaluate(self.vars[0]) % self.evaluate(self.vars[1])
|
|
|
|
|
|
class Lt(BinOp):
|
|
|
|
def __init__(self, *vars):
|
|
BinOp.__init__(self, vars, 6, args_ret_dict['lt'], '<')
|
|
|
|
def get_symbol(self):
|
|
return '<'
|
|
|
|
def get_value(self):
|
|
return self.evaluate(self.vars[0]) < self.evaluate(self.vars[1])
|
|
|
|
class Le(BinOp):
|
|
|
|
def __init__(self, *vars):
|
|
BinOp.__init__(self, vars, 7, args_ret_dict['le'], '<=')
|
|
|
|
def get_symbol(self):
|
|
return '<='
|
|
|
|
def get_value(self):
|
|
return self.evaluate(self.vars[0]) <= self.evaluate(self.vars[1])
|
|
|
|
class Gt(BinOp):
|
|
|
|
def __init__(self, *vars):
|
|
BinOp.__init__(self, vars, 8, args_ret_dict['gt'], '>')
|
|
|
|
def get_symbol(self):
|
|
return '>'
|
|
|
|
def get_value(self):
|
|
return self.evaluate(self.vars[0]) > self.evaluate(self.vars[1])
|
|
|
|
class Ge(BinOp):
|
|
|
|
def __init__(self, *vars):
|
|
BinOp.__init__(self, vars, 9, args_ret_dict['ge'], '>=')
|
|
|
|
def get_symbol(self):
|
|
return '>='
|
|
|
|
def get_value(self):
|
|
return self.evaluate(self.vars[0]) >= self.evaluate(self.vars[1])
|
|
|
|
|
|
class Eq(BinOp):
|
|
|
|
def __init__(self, *vars):
|
|
BinOp.__init__(self, vars, 10, args_ret_dict['eq'], '==')
|
|
|
|
def get_symbol(self):
|
|
return '=='
|
|
|
|
def get_value(self):
|
|
return self.evaluate(self.vars[0]) == self.evaluate(self.vars[1])
|
|
|
|
class Ne(BinOp):
|
|
|
|
def __init__(self, *vars):
|
|
BinOp.__init__(self, vars, 11, args_ret_dict['ne'], '!=')
|
|
|
|
def get_symbol(self):
|
|
return '!='
|
|
|
|
def get_value(self):
|
|
return self.evaluate(self.vars[0]) != self.evaluate(self.vars[1])
|
|
|
|
class In(BinOp):
|
|
|
|
def __init__(self, *vars):
|
|
BinOp.__init__(self, vars, 12, args_ret_dict['in'], 'in')
|
|
|
|
def get_symbol(self):
|
|
return 'in'
|
|
|
|
def get_value(self):
|
|
return self.evaluate(self.vars[0]) in self.evaluate(self.vars[1])
|
|
|
|
def __nonzero__(self):
|
|
return self
|
|
|
|
|
|
class Or(BinOp):
|
|
|
|
def __init__(self, *vars):
|
|
BinOp.__init__(self, vars, 23, args_ret_dict['or'], 'or')
|
|
|
|
def get_symbol(self):
|
|
return 'or'
|
|
|
|
def get_value(self):
|
|
return self.evaluate(self.vars[0]) or self.evaluate(self.vars[1])
|
|
|
|
class And(BinOp):
|
|
|
|
def __init__(self, *vars):
|
|
BinOp.__init__(self, vars, 24, args_ret_dict['and'], 'and')
|
|
|
|
def get_symbol(self):
|
|
return '&'
|
|
|
|
def get_value(self):
|
|
return self.evaluate(self.vars[0]) & self.evaluate(self.vars[1])
|
|
|
|
class Xor(BinOp):
|
|
|
|
def __init__(self, *vars):
|
|
BinOp.__init__(self, vars, 25, args_ret_dict['xor'], 'xor')
|
|
|
|
def get_symbol(self):
|
|
return 'xor'
|
|
|
|
def get_value(self):
|
|
return bool(self.evaluate(self.vars[0])) != bool(self.evaluate(self.vars[1]))
|
|
|
|
class Pow(Call):
|
|
def __init__(self, *vars):
|
|
Call.__init__(self, vars, "pow", args_ret_dict['pow'], '^')
|
|
|
|
def get_symbol(self):
|
|
return '**'
|
|
|
|
def get_value(self):
|
|
return self.evaluate(self.vars[0]) ** self.evaluate(self.vars[1])
|
|
|
|
class Abort(Call):
|
|
def __init__(self, *vars):
|
|
Call.__init__(self, vars, "abort", args_ret_dict['abort'], 'abort')
|
|
|
|
class Abs(Call):
|
|
def __init__(self, *vars):
|
|
Call.__init__(self, vars, "abs", args_ret_dict['abs'], 'abs')
|
|
|
|
|
|
class Array1d(Call):
|
|
def __init__(self, dim1, array):
|
|
Call.__init__(self,(dim1, array),"array1d", args_ret_dict['array1d'], 'array1d')
|
|
|
|
class Array2d(Call):
|
|
def __init__(self, dim1, dim2, array):
|
|
Call.__init__(self, (dim1, dim2, array), "array2d", args_ret_dict['array2d'], 'array2d')
|
|
|
|
class Array3d(Call):
|
|
def __init__(self, dim1, dim2, dim3, array):
|
|
Call.__init__(self,[dim1, dim2, dim3, array],"array3d", args_ret_dict['array3d'], 'array3d')
|
|
|
|
class Array4d(Call):
|
|
def __init__(self, dim1, dim2, dim3, dim4, array):
|
|
Call.__init__(self,[dim1, dim2, dim3, dim4, array],"array4d", args_ret_dict['array4d'], 'array4d')
|
|
|
|
class Array5d(Call):
|
|
def __init__(self, dim1, dim2, dim3, dim4, dim5, array):
|
|
Call.__init__(self,[dim1, dim2, dim3, dim4, dim5, array],"array5d", args_ret_dict['array5d'], 'array5d')
|
|
|
|
class Array6d(Call):
|
|
def __init__(self, dim1, dim2, dim3, dim4, dim5, dim6, array):
|
|
Call.__init__(self,[dim1, dim2, dim3, dim4, dim5, dim6, array],"array6d", args_ret_dict['array6d'], 'array6d')
|
|
|
|
class Acos(Call):
|
|
def __init__(self, var):
|
|
Call.__init__(self, (var,), "acos", args_ret_dict['acos'], 'acos')
|
|
|
|
class Acosh(Call):
|
|
def __init__(self, var):
|
|
Call.__init__(self, (var,), "acosh", args_ret_dict['acosh'], 'acosh')
|
|
|
|
class Asin(Call):
|
|
def __init__(self, var):
|
|
Call.__init__(self, (var,), "asin", args_ret_dict['asin'], 'asin')
|
|
|
|
class Asinh(Call):
|
|
def __init__(self, var):
|
|
Call.__init__(self, (var,), "asinh", args_ret_dict['asinh'], 'asinh')
|
|
|
|
class Atan(Call):
|
|
def __init__(self, var):
|
|
Call.__init__(self, (var,), "atan", args_ret_dict['atan'], 'atan')
|
|
|
|
class Atanh(Call):
|
|
def __init__(self, var):
|
|
Call.__init__(self, (var,), "atanh", args_ret_dict['atanh'], 'atanh')
|
|
|
|
class Assert(Call):
|
|
def __init__(self, constraint, message):
|
|
Call.__init__(self, (constraint, message), "assert", args_ret_dict['assert'], 'assert')
|
|
|
|
class Bool2Int(Call):
|
|
def __init__(self, var):
|
|
Call.__init__(self, (var,), "bool2int", args_ret_dict['bool2int'], 'bool2int')
|
|
|
|
class Card(Call):
|
|
def __init__(self, var):
|
|
Call.__init__(self, (var,), "card", args_ret_dict['card'], 'card')
|
|
|
|
class Ceil(Call):
|
|
def __init__(self, var):
|
|
Call.__init__(self, (var,), "ceil", args_ret_dict['ceil'], 'ceil')
|
|
|
|
class Concat(Call):
|
|
def __init__(self, var):
|
|
Call.__init__(self, (var,), "concat",)
|
|
|
|
class Cos(Call):
|
|
def __init__(self, var):
|
|
Call.__init__(self, (var,), "cos", args_ret_dict['cos'], 'cos')
|
|
|
|
class Cosh(Call):
|
|
def __init__(self, var):
|
|
Call.__init__(self, (var,), "cosh", args_ret_dict['cosh'], 'cosh')
|
|
|
|
class Dom(Call):
|
|
def __init__(self, var):
|
|
Call.__init__(self,[var],"dom")
|
|
|
|
class Dom_Array(Call):
|
|
def __init__(self, var):
|
|
Call.__init__(self,[var],"dom_array")
|
|
|
|
class Dom_Size(Call):
|
|
def __init__(self, var):
|
|
Call.__init__(self,[var],"dom_size")
|
|
|
|
class Fix(Call):
|
|
def __init__(self, var):
|
|
Call.__init__(self,[var],"fix")
|
|
|
|
class Floor(Call):
|
|
def __init__(self, var):
|
|
Call.__init__(self, (var,),"floor", args_ret_dict['floor'], 'floor')
|
|
|
|
class Exp(Call):
|
|
def __init__(self, var):
|
|
Call.__init__(self, (var,),"exp", args_ret_dict['exp'], 'exp')
|
|
|
|
class Int2Float(Call):
|
|
def __init__(self, var):
|
|
Call.__init__(self, (var,),"int2float", args_ret_dict['int2float'], 'int2float')
|
|
|
|
class Is_Fixed(Call):
|
|
def __init__(self, var):
|
|
Call.__init__(self,[var],"is_fixed")
|
|
|
|
class Join(Call):
|
|
def __init__(self, var):
|
|
Call.__init__(self,[var],"join")
|
|
|
|
class Lb(Call):
|
|
def __init__(self, var):
|
|
Call.__init__(self,[var],"lb")
|
|
|
|
class Lb_array(Call):
|
|
def __init__(self, var):
|
|
Call.__init__(self,[var],"lb_array")
|
|
|
|
class Length(Call):
|
|
def __init__(self, var):
|
|
Call.__init__(self,[var],"length")
|
|
|
|
class Ln(Call):
|
|
def __init__(self, var):
|
|
Call.__init__(self, (var,),"ln", args_ret_dict['ln'], 'ln')
|
|
|
|
class Log(Call):
|
|
def __init__(self, var1, var2):
|
|
Call.__init__(self, (var1, var2),"log", args_ret_dict['log'], 'log')
|
|
|
|
class Log2(Call):
|
|
def __init__(self, var):
|
|
Call.__init__(self, (var,), "log2", args_ret_dict['log2'], 'log2')
|
|
|
|
class Log10(Call):
|
|
def __init__(self, var):
|
|
Call.__init__(self, (var,), "log10", args_ret_dict['log10'], 'log10')
|
|
|
|
class Min(Call):
|
|
def __init__(self, var):
|
|
Call.__init__(self, (var,), "min", args_ret_dict(['min']), 'min')
|
|
|
|
class Max(Call):
|
|
def __init__(self, var):
|
|
Call.__init__(self, (var,), "max", args_ret_dict(['max']), 'max')
|
|
|
|
class Product(Call):
|
|
def __init__(self, var):
|
|
Call.__init__(self, (var, ),"product", args_ret_dict['product'], 'product')
|
|
|
|
class Round(Call):
|
|
def __init__(self, var):
|
|
Call.__init__(self, (var, ),"round", args_ret_dict['round'], 'round')
|
|
|
|
class Set2array(Call):
|
|
def __init__(self, var):
|
|
Call.__init__(self,[var],"set2array")
|
|
|
|
class Sin(Call):
|
|
def __init__(self, var):
|
|
Call.__init__(self, (var, ),"sin", args_ret_dict['sin'], 'sin')
|
|
|
|
class Sinh(Call):
|
|
def __init__(self, var):
|
|
Call.__init__(self, (var, ),"sinh", args_ret_dict['sinh'], 'sinh')
|
|
|
|
class Sqrt(Call):
|
|
def __init__(self, var):
|
|
Call.__init__(self, (var, ),"sqrt", args_ret_dict['sqrt'], 'sqrt')
|
|
|
|
class Sum(Call):
|
|
def __init__(self, var):
|
|
Call.__init__(self, (var, ),"sum", args_ret_dict['sum'], 'sum')
|
|
|
|
class Tan(Call):
|
|
def __init__(self, var):
|
|
Call.__init__(self, (var, ),"tan", args_ret_dict['tan'], 'tan')
|
|
|
|
class Tanh(Call):
|
|
def __init__(self, var):
|
|
Call.__init__(self, (var, ),"tanh", args_ret_dict['tanh'], 'tanh')
|
|
|
|
class Trace(Call):
|
|
def __init__(self, var):
|
|
Call.__init__(self,[var],"trace")
|
|
|
|
class Ub(Call):
|
|
def __init__(self, var):
|
|
Call.__init__(self,[var],"ub")
|
|
|
|
class Ub_Array(Call):
|
|
def __init__(self, var):
|
|
Call.__init__(self,[var],"ub_array")
|
|
|
|
|
|
class Neg(UnOp):
|
|
def __init__(self, var):
|
|
UnOp.__init__(self, (var, ), 2, args_ret_dict['neg'], 'neg')
|
|
|
|
class Pos(UnOp):
|
|
def __init__(self, var):
|
|
UnOp.__init__(self, (var, ), 1, args_ret_dict['pos'], 'pos')
|
|
|
|
class Invert(Predicate):
|
|
def __init__(self, vars):
|
|
UnOp.__init__(self, (var, ), 0, args_ret_dict['invert'], 'invert')
|
|
|
|
class Id(Expression):
|
|
def __init__(self, name, model_list = None):
|
|
self.name = name
|
|
self.model_list = model_list
|
|
self.type = minizinc_internal.Annotation
|
|
|
|
|
|
# Temporary container for Variable Declaration
|
|
class Declaration(Expression):
|
|
def __init__(self, model):
|
|
if not isinstance(model, Model):
|
|
raise TypeError('Warning: First argument must be a Model Object')
|
|
Expression.__init__(self, model)
|
|
self.name = '"' + str(id(self)) + '"'
|
|
self.solve_counter = -1
|
|
self.next_counter = -1
|
|
self.value = None
|
|
|
|
def get_value(self):
|
|
if self.solve_counter == self.model.solve_counter and self.next_counter == self.model.next_counter:
|
|
return self.value
|
|
self.solve_counter = self.model.solve_counter
|
|
self.next_counter = self.model.next_counter
|
|
self.value = self.model.mznsolver.get_value(self.name)
|
|
return self.value
|
|
|
|
def __str__(self):
|
|
return str(self.get_value())
|
|
|
|
def __repr__(self):
|
|
return 'A Minizinc ' + self.__class__.__name__ + ' with the value of ' + self.__str__()
|
|
|
|
|
|
class Construct(Declaration):
|
|
def __init__(self, model, arg1):
|
|
Declaration.__init__(self, model)
|
|
self.type = self.eval_type(arg1)
|
|
self.has_minizinc_objects = False
|
|
|
|
def unwrap(arg):
|
|
if isinstance(arg, Expression):
|
|
self.has_minizinc_objects = True
|
|
return arg.obj
|
|
elif type(arg) in (list, tuple):
|
|
ret = []
|
|
for val in arg:
|
|
ret.append(unwrap(val))
|
|
return ret
|
|
elif type(arg) in python_types:
|
|
return arg
|
|
else:
|
|
raise TypeError('Unexpected type: argument should be a single/list/tuple of MiniZinc objects or Python basic types')
|
|
|
|
try:
|
|
self.obj = model.mznmodel.Declaration(self.name, unwrap(arg1))
|
|
except:
|
|
print sys.exc_info()[0]
|
|
raise
|
|
|
|
if self.has_minizinc_objects:
|
|
self.value = arg1
|
|
else:
|
|
self.wrapped_value = arg1
|
|
self.class_name = 'Construct'
|
|
|
|
'''
|
|
imagine we have:
|
|
a = Variable(1,100) undefined
|
|
b = Variable(1,100) undefined
|
|
|
|
c = Construct([a,b]) [ undefined, undefined ]
|
|
when the model is solved, c's value should be changed
|
|
'''
|
|
|
|
def get_value(self):
|
|
if self.has_minizinc_objects:
|
|
def get_value_helper(arg):
|
|
if isinstance(arg, Expression):
|
|
return arg.get_value()
|
|
elif type(arg) is list:
|
|
ret = []
|
|
for val in arg:
|
|
ret.append(get_value_helper(val))
|
|
return ret
|
|
elif type(arg) in python_types:
|
|
return arg
|
|
else:
|
|
raise TypeError('Internal error: Unexpected type')
|
|
if not (self.solve_counter == self.model.solve_counter and self.next_counter == self.obj.next_counter):
|
|
self.value = get_value_helper(self.wrapped_value)
|
|
return self.value
|
|
|
|
|
|
|
|
|
|
class Variable(Declaration):
|
|
def __init__(self, model, arg1=None, arg2=None):
|
|
Declaration.__init__(self, model)
|
|
lb, ub = False, True
|
|
if arg1 is not None:
|
|
typearg1 = type(arg1)
|
|
if arg2 is None:
|
|
if typearg1 is Set:
|
|
lb = arg1
|
|
ub = None
|
|
elif typearg1 in (list,tuple):
|
|
if len(arg1) != 2:
|
|
raise ValueError('Requires a list or tuple of exactly 2 numbers')
|
|
lb,ub = sorted(arg1)[0,1]
|
|
else:
|
|
ub = arg1 - 1
|
|
lb = typearg1(lb)
|
|
else:
|
|
lb,ub = arg1, arg2
|
|
|
|
typelb, typeub = type(lb), type(ub)
|
|
if not typelb is Set:
|
|
if typelb not in (bool, float, ) and typelb not in integer_types and not isinstance(typelb, Declaration):
|
|
raise TypeError('Lower bound must be a boolean, an int, a float or a set')
|
|
if typeub not in (bool, float, ) and typeub not in integer_types and not isinstance(typelb, Declaration):
|
|
raise TypeError('Upper bound must be a boolean, an int or a float')
|
|
if typelb != typeub:
|
|
raise TypeError('Upper bound an dlower bound is of different type')
|
|
if lb > ub:
|
|
raise ValueError('Lower bound cannot be greater than upper bound')
|
|
|
|
self.dim_list = []
|
|
|
|
if typelb is bool:
|
|
self.obj = model.mznmodel.Declaration(self.name, 10, [])
|
|
self.type = bool
|
|
elif typelb in integer_types:
|
|
self.obj = model.mznmodel.Declaration(self.name, 9, [], lb, ub)
|
|
self.type = int_t
|
|
elif typelb is float:
|
|
self.obj = model.mznmodel.Declaration(self.name, 11, [], lb, ub)
|
|
self.type = float
|
|
elif typelb is Set:
|
|
self.obj = model.mznmodel.Declaration(self.name, 9, [], lb.obj)
|
|
self.type = int_t
|
|
else:
|
|
raise TypeError('Internal: Unexpected type')
|
|
|
|
self.class_name = 'Variable'
|
|
|
|
class VariableConstruct(Variable, Construct):
|
|
def __init__(self, model, arg1, arg2 = None):
|
|
Construct.__init__(self, model, arg1, arg2)
|
|
|
|
class Array(Variable):
|
|
def __init__(self, model, argopt1, argopt2, *args):
|
|
Declaration.__init__(self, model)
|
|
dim_list = []
|
|
lb = None
|
|
ub = None
|
|
|
|
def add_to_dim_list(i):
|
|
if type(i) is int:
|
|
if i > 0:
|
|
dim_list.append([0,i-1])
|
|
else:
|
|
raise TypeError('Single value must be a positive integer')
|
|
elif type(i) is list:
|
|
if type(i[0]) in integer_types and type(i[-1]) in integer_types:
|
|
dim_list.append([ i[0],i[-1]] )
|
|
else:
|
|
raise TypeError('Range boundaries must be integers')
|
|
elif isinstance(i, Set):
|
|
if i.continuous():
|
|
dim_list.append([i.min(), i.max()])
|
|
else:
|
|
raise TypeError('Array ranges must be continuous')
|
|
else:
|
|
raise TypeError('Unknown type')
|
|
|
|
if type(argopt1) is Set:
|
|
lb = argopt1
|
|
ub = None
|
|
add_to_dim_list(argopt2)
|
|
elif type(argopt1) is bool and type(argopt2) is bool:
|
|
lb = argopt1
|
|
ub = argopt2
|
|
elif type(argopt2) not in integer_types:
|
|
if type(argopt1) not in integer_types:
|
|
raise TypeError('Range values must be integers')
|
|
lb = 0
|
|
ub = argopt1 - 1
|
|
add_to_dim_list(argopt2)
|
|
else:
|
|
if type(argopt1) not in integer_types or type(argopt2) not in integer_types:
|
|
raise TypeError('Lower bound and upper bound must be integers')
|
|
lb = argopt1
|
|
ub = argopt2
|
|
|
|
for i in args:
|
|
add_to_dim_list(i)
|
|
|
|
self.lb = lb
|
|
self.ub = ub
|
|
if dim_list == []:
|
|
raise AttributeError('Initialising an Array without dimension list')
|
|
self.dim_list = dim_list
|
|
tlb = type(argopt1)
|
|
if tlb is bool:
|
|
self.type = [bool] * len(dim_list)
|
|
self.obj = model.mznmodel.Declaration(self.name,10,dim_list,lb,ub)
|
|
elif tlb in integer_types:
|
|
self.type = [int_t] * len(dim_list)
|
|
self.obj = model.mznmodel.Declaration(self.name,9,dim_list, lb, ub)
|
|
elif tlb is float: #isinstance(lb, float):
|
|
self.type = [float] * len(dim_list)
|
|
self.obj = model.mznmodel.Declaration(self.name,11,dim_list,lb,ub)
|
|
elif tlb is Set:
|
|
self.type = [int_t] * len(dim_list)
|
|
self.obj = model.mznmodel.Declaration(self.name,9,dim_list,lb.obj)
|
|
else:
|
|
raise TypeError('Unexpected type')
|
|
|
|
self.class_name = 'Array'
|
|
|
|
def __getitem__(self, *args):
|
|
return ArrayAccess(self.model, self, args[0])
|
|
|
|
|
|
# XXX: to be rewritten later
|
|
class ArrayAccess(Array):
|
|
def __init__(self, model, array, idx):
|
|
Declaration.__init__(self, model)
|
|
if type(idx) is not tuple:
|
|
idx = [idx]
|
|
else:
|
|
idx = flatten(idx)
|
|
if len(idx) != len(array.dim_list):
|
|
raise IndexError('Requires exactly ' + str(len(self.dim_list)) + ' index values')
|
|
for i, value in enumerate(idx):
|
|
if not isinstance(value, Expression):
|
|
if value < array.dim_list[i][0] or value > array.dim_list[i][1]:
|
|
raise IndexError('Index at pos ' + str(i) + ' is out of range')
|
|
|
|
self.array = array
|
|
self.idx = idx
|
|
self.type = array.type[0]
|
|
self.value = None
|
|
self.class_name = 'Array Item'
|
|
|
|
def get_value(self):
|
|
if hasattr(self, 'solve_counter'):
|
|
if self.solve_counter == self.model.solve_counter and self.next_counter == self.model.next_counter:
|
|
return self.value
|
|
self.solve_counter = self.model.solve_counter
|
|
self.next_counter = self.model.next_counter
|
|
arrayvalue = self.array.get_value()
|
|
if arrayvalue is None:
|
|
return None
|
|
else:
|
|
for i,value in enumerate(self.idx):
|
|
arrayvalue = arrayvalue[value - self.array.dim_list[i][0]]
|
|
self.value = arrayvalue
|
|
return self.value
|
|
return self.value
|
|
|
|
class ArrayConstruct(Array, Construct):
|
|
def __init__(self, model, arg1, arg2 = None):
|
|
Construct.__init__(self, model, arg1, arg2)
|
|
|
|
|
|
class Set(Declaration):
|
|
# Set is model independent and can be reused in multiple models
|
|
# Thus, Set.model = None
|
|
def __init__(self, *args):
|
|
self.model = None
|
|
self.name = '"' + str(id(self)) + '"'
|
|
'''
|
|
lb, ub = None, None
|
|
set_list = None
|
|
|
|
if argopt2 is not None:
|
|
lb,ub = argopt1, argopt2
|
|
else:
|
|
if type(argopt1) is list:
|
|
set_list = argopt1
|
|
else:
|
|
ub = argopt1 - 1
|
|
lb = 0
|
|
|
|
if set_list is None:
|
|
if not (type(lb) in integer_types and type(ub) in integer_types):
|
|
raise TypeError('Lower bound and upper bound must be integers')
|
|
set_list = [[lb, ub]]
|
|
'''
|
|
self.obj = minizinc_internal.Set(*args)
|
|
self.type = minizinc_internal.Set
|
|
self.class_name = 'Set'
|
|
|
|
def push(self, *args):
|
|
self.obj.push(*args)
|
|
|
|
def clear(self):
|
|
self.obj.clear()
|
|
|
|
def continuous(self):
|
|
return self.obj.continuous()
|
|
|
|
def min(self):
|
|
return self.obj.min()
|
|
|
|
def max(self):
|
|
return self.obj.max()
|
|
|
|
def get_value(self):
|
|
return self.obj
|
|
|
|
def __iter__(self):
|
|
return self.obj.__iter__()
|
|
|
|
def __contains__(self, val):
|
|
return self.obj.contains(val)
|
|
|
|
class VarSet(Variable):
|
|
def __init__(self, model, argopt1, argopt2 = None):
|
|
self.model = model
|
|
self.name = '"' + str(id(self)) + '"'
|
|
|
|
lb, ub = None, None
|
|
set_list = None
|
|
if argopt2 is not None:
|
|
lb,ub = argopt1, argopt2
|
|
else:
|
|
if type(argopt1) is list:
|
|
set_list = argopt1
|
|
elif type(argopt1) is Set:
|
|
lb = argopt1.min()
|
|
ub = argopt1.max()
|
|
else:
|
|
ub = argopt1 - 1
|
|
lb = 0
|
|
|
|
if set_list is None:
|
|
if not (type(lb) in integer_types and type(ub) in integer_types):
|
|
raise TypeError('Lower bound and upper bound must be integers')
|
|
|
|
model.mznmodel.Declaration(self.name, 12, [], lb, ub)
|
|
self.type = minizinc_internal.VarSet
|
|
self.class_name = 'Var Set'
|
|
|
|
''' Python automatically evaluate a __contains__ return object to boolean
|
|
thus, we have to use separate In class instead of
|
|
for i in VarSet
|
|
def __contains__(self, argopt):
|
|
return In([argopt, self])
|
|
'''
|
|
|
|
variable_model_dict = {}
|
|
function_model_dict = {}
|
|
name_model_dict = {}
|
|
def handlerFunctionClosure(name, args_list, model_list):
|
|
def handlerFunction(*args):
|
|
return Call(args, name, args_list, name, model_list)
|
|
return handlerFunction
|
|
|
|
def handlerFunction(name, model_list):
|
|
return Id(name, model_list)
|
|
|
|
def init(args = None, model = None):
|
|
def assign_usable_names_to_model(name, model):
|
|
if name in name_model_dict:
|
|
if model is None:
|
|
name_model_dict[name] = None
|
|
else:
|
|
name_model_dict[name].append(model)
|
|
return False
|
|
else:
|
|
if model is None:
|
|
name_model_dict[name] = None
|
|
else:
|
|
name_model_dict[name] = [model]
|
|
return True
|
|
|
|
names = minizinc_internal.retrieveNames(args)
|
|
for name, args_and_return_type_tuple in names["boolfuncs"].items():
|
|
if assign_usable_names_to_model(name, model):
|
|
setattr(predicate, name, handlerFunctionClosure(name, args_and_return_type_tuple, name_model_dict[name]))
|
|
|
|
for name, args_and_return_type_tuple in names["annfuncs"].items():
|
|
if assign_usable_names_to_model(name, model):
|
|
setattr(predicate, name, handlerFunctionClosure(name, args_and_return_type_tuple, name_model_dict[name]))
|
|
|
|
for name in names["annvars"]:
|
|
if assign_usable_names_to_model(name, model):
|
|
setattr(annotation, name, handlerFunction(name, name_model_dict[name]))
|
|
|
|
init()
|
|
|
|
class Model(object):
|
|
def __init__(self, args = None):
|
|
self.loaded = False
|
|
self.mznsolver = None
|
|
self.mznmodel = minizinc_internal.Model(args)
|
|
if args:
|
|
init(args, self)
|
|
self.solve_counter = -1
|
|
self.next_counter = -1
|
|
|
|
|
|
'''
|
|
# not used anymore
|
|
def get_name(self,var):
|
|
itemList = [var_name for var_name, var_val in self.frame if var_val is var]
|
|
if len(itemList) == 1:
|
|
return itemList[0]
|
|
elif len(itemList) == 0:
|
|
raise LookupError('Internal Error: variable name not found')
|
|
else:
|
|
raise LookupError('The object pointed to was assigned to different names')
|
|
'''
|
|
|
|
def add_recursive(self, expr):
|
|
if isinstance(expr, (tuple, list)):
|
|
for i in expr:
|
|
self.add_recursive(i)
|
|
else:
|
|
if issubclass(type(expr), Expression):
|
|
if expr.is_pre():
|
|
self.mznmodel.Constraint(self.evaluate(expr))
|
|
else:
|
|
raise(TypeError, "Unexpected Expression")
|
|
else:
|
|
self.mznmodel.Constraint(expr)
|
|
|
|
def Constraint(self, *expr):
|
|
minizinc_internal.lock()
|
|
if len(expr)>0:
|
|
self.loaded = True
|
|
#self.frame = inspect.currentframe().f_back.f_locals.items()
|
|
self.add_recursive(expr)
|
|
#del self.frame
|
|
minizinc_internal.unlock()
|
|
|
|
def evaluate(self, expr):
|
|
if not isinstance(expr, Expression):
|
|
if isinstance(expr, (list, tuple)):
|
|
for i,item in enumerate(expr):
|
|
expr[i] = self.evaluate(item)
|
|
return expr
|
|
if isinstance(expr, Id):
|
|
if expr.model_list is not None:
|
|
if not self in expr.model_list:
|
|
raise TypeError("The annotation '" + expr.name + "' does not belong to the model")
|
|
return minizinc_internal.Id(expr.name)
|
|
if isinstance(expr, Call):
|
|
variables = []
|
|
model = None
|
|
for i in expr.vars:
|
|
variables.append(self.evaluate(i))
|
|
if expr.model_list is not None:
|
|
if not self in expr.model_list:
|
|
raise TypeError("The function '" + expr.name + "' does not belong to the model")
|
|
return minizinc_internal.Call(expr.CallCode, variables, expr.type)
|
|
elif isinstance(expr, ArrayAccess):
|
|
for i,value in enumerate(expr.idx):
|
|
if isinstance(value, Expression):
|
|
expr.idx[i] = self.evaluate(value)
|
|
return minizinc_internal.at(expr.array.obj, expr.idx)
|
|
elif isinstance(expr, Declaration):
|
|
if expr.model != self:
|
|
raise TypeError("The Declaration not belongs to this model")
|
|
return expr.obj
|
|
elif isinstance(expr, BinOp):
|
|
if expr.model is not None and expr.model != self:
|
|
raise TypeError("The Declaration not belongs to this model")
|
|
lhs = self.evaluate(expr.vars[0])
|
|
rhs = self.evaluate(expr.vars[1])
|
|
return minizinc_internal.BinOp(lhs, expr.BinOpCode, rhs)
|
|
elif isinstance(expr, UnOp):
|
|
if expr.model is not None and expr.model != self:
|
|
raise TypeError("The Declaration not belongs to this model")
|
|
rhs = self.evaluate(expr.vars[0])
|
|
return minizinc_internal.UnOp(expr.UnOpCode, rhs)
|
|
else:
|
|
raise TypeError('Variable Type unspecified')
|
|
|
|
|
|
|
|
def Variable(self, argopt1=None, argopt2=None):
|
|
return Variable(self, argopt1, argopt2)
|
|
|
|
def Array(self, argopt1, argopt2, *args):
|
|
list_ = []
|
|
for i in args:
|
|
list_.append(i)
|
|
return Array(self, argopt1, argopt2, *list_)
|
|
|
|
def Set(self, *args):
|
|
return Set(*args)
|
|
|
|
def Range(self, arg1, arg2 = None):
|
|
if (arg2 is None):
|
|
return Set((0, arg1 - 1))
|
|
else:
|
|
return Set((arg1, arg2))
|
|
|
|
def VarSet(self, argopt1, argopt2 = None):
|
|
return VarSet(self, argopt1, argopt2)
|
|
|
|
def Construct(self, argopt1):
|
|
if isinstance(argopt1, list):
|
|
return ArrayConstruct(self, argopt1)
|
|
else:
|
|
return VariableConstruct(self, argopt1)
|
|
|
|
def __solve(self, code, expr, ann, data, solver, time):
|
|
minizinc_internal.lock()
|
|
|
|
if ann is not None:
|
|
if not hasattr(ann, 'type') or ann.type != minizinc_internal.Annotation:
|
|
raise TypeError('Unexpected type of annotation')
|
|
eval_ann = self.evaluate(ann)
|
|
eval_expr = self.evaluate(expr)
|
|
|
|
savedModel = self.mznmodel.copy()
|
|
|
|
# The model with declared variable cannot be deleted.
|
|
self.mznmodel, savedModel = savedModel, self.mznmodel
|
|
self.mznmodel.SolveItem(code, eval_ann, eval_expr)
|
|
if data is not None:
|
|
self.add_recursive(data)
|
|
minizinc_internal.unlock()
|
|
|
|
self.mznsolver = self.mznmodel.solve(solver = solver, time = time)
|
|
self.mznmodel = savedModel
|
|
self.solve_counter = self.solve_counter + 1
|
|
self.next_counter = -1
|
|
|
|
|
|
def satisfy(self, ann = None, data = None, solver = 'gecode', time = 0):
|
|
self.__solve(0, None, ann, data, solver, time)
|
|
def maximize(self, expr, ann = None, data = None, solver = 'gecode', time = 0):
|
|
self.__solve(2, expr, ann, data, solver, time)
|
|
def minimize(self, expr, ann = None, data = None, solver = 'gecode', time = 0):
|
|
self.__solve(1, expr, ann, data, solver, time)
|
|
def reset(self):
|
|
self.__init__()
|
|
|
|
def next(self):
|
|
if self.mznsolver is None:
|
|
raise ValueError('Model is not solved yet')
|
|
self.status = self.mznsolver.next()
|
|
self.next_counter = self.next_counter + 1
|
|
return (self.status is None)
|
|
|
|
def is_loaded(self):
|
|
return self.loaded
|
|
|
|
def is_solved(self):
|
|
return self.mznsolver != None
|
|
|
|
def set_time_limit(self, time):
|
|
self.mznmodel.set_time_limit(time)
|
|
|
|
def set_solver(self, solver):
|
|
self.mznmodel.set_solver(solver)
|
|
|
|
def _debugprint(self):
|
|
self.mznmodel.debugprint()
|
|
|