diff --git a/cpmpy/expressions/variables.py b/cpmpy/expressions/variables.py index 5225cf22d..acf81d63a 100644 --- a/cpmpy/expressions/variables.py +++ b/cpmpy/expressions/variables.py @@ -47,6 +47,7 @@ ============== """ import math +import uuid from collections.abc import Iterable import warnings # for deprecation warning from functools import reduce @@ -238,6 +239,7 @@ def __init__(self, lb, ub, name): self.lb = lb self.ub = ub self.name = name + self.id = uuid.uuid4() self._value = None def is_bool(self): @@ -263,9 +265,9 @@ def clear(self): def __repr__(self): return self.name - # for sets/dicts. Because names are unique, so is the str repr + # for sets/dicts. Because id's are unique, so is the str repr def __hash__(self): - return hash(self.name) + return hash(self.id) class _IntVarImpl(_NumVarImpl): @@ -286,6 +288,8 @@ def __init__(self, lb, ub, name=None): super().__init__(int(lb), int(ub), name=name) # explicit cast: can be numpy + + # special casing for intvars (and boolvars) def __abs__(self): if self.lb >= 0: diff --git a/cpmpy/solvers/exact.py b/cpmpy/solvers/exact.py index a90d73c40..e847088c1 100644 --- a/cpmpy/solvers/exact.py +++ b/cpmpy/solvers/exact.py @@ -290,7 +290,7 @@ def solver_var(self, cpm_var): return self._varmap[cpm_var] # create if it does not exist - revar = str(cpm_var) + revar = str(cpm_var) + str(cpm_var.id) if isinstance(cpm_var, _BoolVarImpl): self.xct_solver.addVariable(revar,0,1) elif isinstance(cpm_var, _IntVarImpl): diff --git a/cpmpy/solvers/gurobi.py b/cpmpy/solvers/gurobi.py index 59b0ac012..a1f35e185 100644 --- a/cpmpy/solvers/gurobi.py +++ b/cpmpy/solvers/gurobi.py @@ -185,9 +185,9 @@ def solver_var(self, cpm_var): if cpm_var not in self._varmap: from gurobipy import GRB if isinstance(cpm_var, _BoolVarImpl): - revar = self.grb_model.addVar(vtype=GRB.BINARY, name=cpm_var.name) + revar = self.grb_model.addVar(vtype=GRB.BINARY, name=cpm_var.name+str(cpm_var.id)) elif isinstance(cpm_var, _IntVarImpl): - revar = self.grb_model.addVar(cpm_var.lb, cpm_var.ub, vtype=GRB.INTEGER, name=str(cpm_var)) + revar = self.grb_model.addVar(cpm_var.lb, cpm_var.ub, vtype=GRB.INTEGER, name=cpm_var.name+str(cpm_var.id)) else: raise NotImplementedError("Not a known var {}".format(cpm_var)) self._varmap[cpm_var] = revar diff --git a/cpmpy/solvers/minizinc.py b/cpmpy/solvers/minizinc.py index 3c4a84287..16ac50a30 100644 --- a/cpmpy/solvers/minizinc.py +++ b/cpmpy/solvers/minizinc.py @@ -335,15 +335,13 @@ def solver_var(self, cpm_var) -> str: # we assume all variables are user variables (because no transforms) self.user_vars.add(cpm_var) # clean the varname - varname = cpm_var.name - mzn_var = varname.replace(',', '_').replace('.', '_').replace(' ', '_').replace('[', '_').replace(']', '') + varname = cpm_var.name + str(cpm_var.id) + mzn_var = varname.replace(',', '_').replace('.', '_').replace(' ', '_').replace('[', '_').replace(']', '').replace('-','_') #test if the name is a valid minizinc identifier if not self.mzn_name_pattern.search(mzn_var): raise MinizincNameException("Minizinc only accept names with alphabetic characters, digits and underscores. " - "First character must be an alphabetic character") - if mzn_var in self.keywords: - raise MinizincNameException(f"This variable name is a disallowed keyword in MiniZinc: {mzn_var}") + "First character must be an alphabetic character" + mzn_var) if isinstance(cpm_var, _BoolVarImpl): self.mzn_model.add_string(f"var bool: {mzn_var};\n") diff --git a/cpmpy/solvers/ortools.py b/cpmpy/solvers/ortools.py index 30a8af276..acb1d6074 100644 --- a/cpmpy/solvers/ortools.py +++ b/cpmpy/solvers/ortools.py @@ -243,9 +243,9 @@ def solver_var(self, cpm_var): # create if it does not exist if cpm_var not in self._varmap: if isinstance(cpm_var, _BoolVarImpl): - revar = self.ort_model.NewBoolVar(str(cpm_var)) + revar = self.ort_model.NewBoolVar(str(cpm_var)+str(cpm_var.id)) elif isinstance(cpm_var, _IntVarImpl): - revar = self.ort_model.NewIntVar(cpm_var.lb, cpm_var.ub, str(cpm_var)) + revar = self.ort_model.NewIntVar(cpm_var.lb, cpm_var.ub, str(cpm_var)+str(cpm_var.id)) else: raise NotImplementedError("Not a known var {}".format(cpm_var)) self._varmap[cpm_var] = revar diff --git a/cpmpy/solvers/pysat.py b/cpmpy/solvers/pysat.py index 3047881d6..57fa4f006 100644 --- a/cpmpy/solvers/pysat.py +++ b/cpmpy/solvers/pysat.py @@ -206,9 +206,9 @@ def solver_var(self, cpm_var): # work directly on var inside the view if isinstance(cpm_var, NegBoolView): # just a view, get actual var identifier, return -id - return -self.pysat_vpool.id(cpm_var._bv.name) + return -self.pysat_vpool.id(cpm_var._bv.name + str(cpm_var.id)) elif isinstance(cpm_var, _BoolVarImpl): - return self.pysat_vpool.id(cpm_var.name) + return self.pysat_vpool.id(cpm_var.name + str(cpm_var.id)) else: raise NotImplementedError(f"CPM_pysat: variable {cpm_var} not supported") diff --git a/cpmpy/solvers/z3.py b/cpmpy/solvers/z3.py index 97684257c..60408667e 100644 --- a/cpmpy/solvers/z3.py +++ b/cpmpy/solvers/z3.py @@ -195,9 +195,9 @@ def solver_var(self, cpm_var): # we assume al variables are user variables (because nested expressions) self.user_vars.add(cpm_var) if isinstance(cpm_var, _BoolVarImpl): - revar = z3.Bool(str(cpm_var)) + revar = z3.Bool(str(cpm_var) + str(cpm_var.id)) elif isinstance(cpm_var, _IntVarImpl): - revar = z3.Int(str(cpm_var)) + revar = z3.Int(str(cpm_var) + str(cpm_var.id)) # set bounds self.z3_solver.add(revar >= cpm_var.lb) self.z3_solver.add(revar <= cpm_var.ub)