Skip to content

Commit d91381c

Browse files
committed
support variable naming, incl array auto-indexing
1 parent c76cb92 commit d91381c

File tree

1 file changed

+43
-28
lines changed

1 file changed

+43
-28
lines changed

cpmpy/variables.py

+43-28
Original file line numberDiff line numberDiff line change
@@ -145,13 +145,14 @@ def is_var(x):
145145

146146
class NumVarImpl(Expression):
147147
"""
148-
**Continuous numerical** variable with given lowerbound and upperbound.
148+
Abstract **continuous numerical** variable with given lowerbound and upperbound.
149149
"""
150-
def __init__(self, lb, ub):
150+
def __init__(self, lb, ub, name):
151151
assert (is_num(lb) and is_num(ub))
152152
assert (lb <= ub)
153153
self.lb = lb
154154
self.ub = ub
155+
self.name = name
155156
self._value = None
156157

157158
def is_bool(self):
@@ -161,6 +162,9 @@ def is_bool(self):
161162

162163
def value(self):
163164
return self._value
165+
166+
def __repr__(self):
167+
return self.name
164168

165169
# for sets/dicts. Because names are unique, so is the str repr
166170
def __hash__(self):
@@ -172,40 +176,36 @@ class IntVarImpl(NumVarImpl):
172176
"""
173177
counter = 0
174178

175-
def __init__(self, lb, ub, setname=True):
179+
def __init__(self, lb, ub, name=None):
176180
assert is_int(lb), "IntVar lowerbound must be integer {} {}".format(type(lb),lb)
177181
assert is_int(ub), "IntVar upperbound must be integer {} {}".format(type(ub),ub)
178-
#assert (lb >= 0 and ub >= 0) # can be negative?
179-
super().__init__(int(lb), int(ub)) # explicit cast: can be numpy
180-
181-
if setname:
182-
self.name = IntVarImpl.counter
182+
183+
if name is None:
184+
name = "IV{}".format(IntVarImpl.counter)
183185
IntVarImpl.counter = IntVarImpl.counter + 1 # static counter
184-
185-
def __repr__(self):
186-
return "IV{}".format(self.name)
186+
187+
super().__init__(int(lb), int(ub), name=name) # explicit cast: can be numpy
187188

188189
class BoolVarImpl(IntVarImpl):
189190
"""
190191
**Boolean** constraint variable with given lowerbound and upperbound.
191192
"""
192193
counter = 0
193194

194-
def __init__(self, lb=0, ub=1):
195+
def __init__(self, lb=0, ub=1, name=None):
195196
assert(lb == 0 or lb == 1)
196197
assert(ub == 0 or ub == 1)
197-
IntVarImpl.__init__(self, lb, ub, setname=False)
198+
199+
if name is None:
200+
name = "BV{}".format(BoolVarImpl.counter)
201+
BoolVarImpl.counter = BoolVarImpl.counter + 1 # static counter
202+
IntVarImpl.__init__(self, lb, ub, name=name)
198203

199-
self.name = BoolVarImpl.counter
200-
BoolVarImpl.counter = BoolVarImpl.counter + 1 # static counter
201204

202205
def is_bool(self):
203206
""" is it a Boolean (return type) Operator?
204207
"""
205208
return True
206-
207-
def __repr__(self):
208-
return "BV{}".format(self.name)
209209

210210
def __invert__(self):
211211
return NegBoolView(self)
@@ -237,7 +237,7 @@ def value(self):
237237
return not self._bv.value()
238238

239239
def __repr__(self):
240-
return "~BV{}".format(self._bv.name)
240+
return "~{}".format(self._bv.name)
241241

242242
def __invert__(self):
243243
return self._bv
@@ -312,34 +312,32 @@ def sum(self, axis=None, out=None):
312312

313313

314314
# N-dimensional array of Boolean Decision Variables
315-
def BoolVar(shape=None):
315+
def BoolVar(shape=None, name=None):
316316
"""
317317
# N-dimensional array of Boolean Decision Variables
318318
"""
319319
if shape is None or shape == 1:
320-
return BoolVarImpl()
320+
return BoolVarImpl(name=name)
321321
elif shape == 0:
322322
raise NullShapeError(shape)
323-
length = np.prod(shape)
324323

325324
# create base data
326-
data = np.array([BoolVarImpl() for _ in range(length)]) # repeat new instances
325+
data = np.array([BoolVarImpl(name=_genname(name, idxs)) for idxs in np.ndindex(shape)]) # repeat new instances
327326
# insert into custom ndarray
328327
return NDVarArray(shape, dtype=object, buffer=data)
329328

330329

331-
def IntVar(lb, ub, shape=None):
330+
def IntVar(lb, ub, shape=None, name=None):
332331
"""
333332
N-dimensional array of Integer Decision Variables with lower-bound `lb` and upper-bound `ub`
334333
"""
335334
if shape is None or shape == 1:
336-
return IntVarImpl(lb,ub)
335+
return IntVarImpl(lb,ub, name=name)
337336
elif shape == 0:
338337
raise NullShapeError(shape)
339-
length = np.prod(shape)
340-
338+
341339
# create base data
342-
data = np.array([IntVarImpl(lb,ub) for _ in range(length)]) # repeat new instances
340+
data = np.array([IntVarImpl(lb,ub, name=_genname(name, idxs)) for idxs in np.ndindex(shape)]) # repeat new instances
343341
# insert into custom ndarray
344342
return NDVarArray(shape, dtype=object, buffer=data)
345343

@@ -354,3 +352,20 @@ def cparray(arr):
354352
if not isinstance(arr, np.ndarray):
355353
arr = np.array(arr)
356354
return NDVarArray(shape=arr.shape, dtype=type(arr.flat[0]), buffer=arr)
355+
356+
357+
def _genname(basename, idxs):
358+
"""
359+
Helper function to 'name' array variables
360+
- idxs: list of indices, one for every dimension of the array
361+
- basename: base name to prepend
362+
363+
if basename is 'None', then it returns None
364+
365+
output: something like "basename[0,1]"
366+
"""
367+
if basename == None:
368+
return None
369+
stridxs = ",".join(map(str,idxs))
370+
return f"{basename}[{stridxs}]" # "<name>[<idx0>,<idx1>,...]"
371+

0 commit comments

Comments
 (0)