Something went wrong. Try again.
This repository has no description
Something went wrong. Try again.
38 kB · 1415 lines
Python
at develop
123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155115611571158115911601161116211631164116511661167116811691170117111721173117411751176117711781179118011811182118311841185118611871188118911901191119211931194119511961197119811991200120112021203120412051206120712081209121012111212121312141215121612171218121912201221122212231224122512261227122812291230123112321233123412351236123712381239124012411242124312441245124612471248124912501251125212531254125512561257125812591260126112621263126412651266126712681269127012711272127312741275127612771278127912801281128212831284128512861287128812891290129112921293129412951296129712981299130013011302130313041305130613071308130913101311131213131314131513161317131813191320132113221323132413251326132713281329133013311332133313341335133613371338133913401341134213431344134513461347134813491350135113521353135413551356135713581359136013611362136313641365136613671368136913701371137213731374137513761377137813791380138113821383138413851386138713881389139013911392139313941395139613971398139914001401140214031404140514061407140814091410141114121413141414151416##@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 setminizinc.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 setminizinc.Model.Array:minizinc.Model.Construct:
* Functions *minizinc.Model.satisfyminizinc.Model.next'''
import sysimport minizinc_internalimport predicateimport 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 itemsdef 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 variabledef 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 hereclass 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 modelclass 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_assignargs_ret_dict['sub'] = to_assignargs_ret_dict['mul'] = to_assignargs_ret_dict['div'] = to_assignargs_ret_dict['floordiv'] = to_assignargs_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_assignargs_ret_dict['le'] = to_assignargs_ret_dict['gt'] = to_assignargs_ret_dict['ge'] = to_assignargs_ret_dict['eq'] = to_assignargs_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_assignargs_ret_dict['and'] = to_assignargs_ret_dict['xor'] = to_assign
args_ret_dict['abort'] = [ ((), bool)]to_assign = [ ((int_t,), int_t), ((float,), float) ]args_ret_dict['abs'] = to_assignargs_ret_dict['neg'] = to_assignargs_ret_dict['pos'] = to_assignargs_ret_dict['invert'] = to_assign
args_ret_dict['array1d'] = [ (None, [int_t]) ] #the function has checked its argument alreadyargs_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_assignargs_ret_dict['cos'] = to_assignargs_ret_dict['tan'] = to_assignargs_ret_dict['asin'] = to_assignargs_ret_dict['acos'] = to_assignargs_ret_dict['atan'] = to_assignargs_ret_dict['sinh'] = to_assignargs_ret_dict['cosh'] = to_assignargs_ret_dict['tanh'] = to_assignargs_ret_dict['asinh'] = to_assignargs_ret_dict['acosh'] = to_assignargs_ret_dict['atanh'] = to_assignargs_ret_dict['sqrt'] = to_assignargs_ret_dict['ln'] = to_assignargs_ret_dict['log2'] = to_assignargs_ret_dict['log10'] = to_assignargs_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_assignargs_ret_dict['floor'] = to_assignargs_ret_dict['round'] = to_assign
to_assign = [ ((int_t,), float) ]args_ret_dict['int2float'] = to_assign# XXX consider removeargs_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_assignargs_ret_dict['max'] = to_assign
to_assign = [ (([int_t], ), int_t), (([float], ), float) ]args_ret_dict['product'] = to_assignargs_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 Declarationclass 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 laterclass 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()