def _expand_bounds(self, keys, var_bound, default_bound, size, true_if_lb): ''' Converts raw bounds data (either LB or UB) to CPLEX-compatible bounds list. If lbs is None, this is the default, return []. If lbs is [] take the default again. If it is a number, build a list of size <size> with this number. If it is a list, use it if size ok (check numbers??), else try it as a function over keys. ''' if var_bound is None: # default lb is zero, default ub is infinity return [] elif is_number(var_bound): self._checker.typecheck_num(var_bound, caller='in variable bound') if true_if_lb: if var_bound == default_bound: return [] else: return [float(var_bound)] * size else: # ub if var_bound >= default_bound: return [] else: return [float(var_bound)] * size elif is_ordered_sequence(var_bound): nb_bounds = len(var_bound) if nb_bounds < size: # see how we can use defaults for those missing bounds self.fatal( "Variable bounds list is too small, expecting: %d, got: %d" % (size, nb_bounds)) else: return self._check_bounds(size, var_bound, default_bound, true_if_lb) elif is_iterator(var_bound): # unfold the iterator, as CPLEX needs a list return list(var_bound) elif isinstance(var_bound, dict): dict_bounds = [var_bound.get(k, default_bound) for k in keys] return self._check_bounds(size, dict_bounds, default_bound, true_if_lb) else: # try a function? try: fn_bounds = [var_bound(k) for k in keys] return self._check_bounds(size, fn_bounds, default_bound, true_if_lb) except TypeError: self._bad_bounds_fatal(var_bound) except Exception as e: # pragma: no cover self.fatal( "error calling function model bounds: {0!s}, error: {1!s}", var_bound, e)
def create_cpx_bound_list(cls, bounds, size): if bounds is None: return [] elif is_number(bounds): return [bounds] * size elif is_ordered_sequence(bounds): assert size == len(bounds) return [float(bb) for bb in bounds] else: raise ValueError("Expecting number or sequence of numbers, {0!r} was passed".format(bounds))
def _to_list(cls, s, caller): if is_pandas_series(s): return s.tolist() elif is_ordered_sequence(s): return s else: docplex_fatal( '{0} requires ordered sequences: lists, numpy array or Series, got: {1}', caller, type(s)) return list(s)
def typecheck_initial_lp_stats(cls, logger, stats, stat_type, caller=None): caller_s = resolve_caller_as_string(caller) if not is_ordered_sequence(stats): logger.fatal( '{0}expects ordered sequence of {2} basis statuses, {1!r} was passed', caller_s, stats, stat_type) l_stats = list(stats) for s, stat in enumerate(l_stats): if not isinstance(stat, BasisStatus): logger.fatal( '{0}expects a sequence of {3} basis status, {1} was passed at pos {2}', caller_s, stat, s, stat_type) return l_stats
def _scal_prod_f(self, dvars, coef_fn, assume_alldifferent): if isinstance(dvars, dict) and hasattr(dvars, 'items'): var_key_iter = iteritems elif is_ordered_sequence(dvars): var_key_iter = enumerate else: var_key_iter = None self._model.fatal('Model.dotf expects either a dictionary or an ordered sequence of variables, an instance of {0} was passed', type(dvars)) if assume_alldifferent: return self._scal_prod_f_alldifferent(dvars, coef_fn, var_key_iter) else: return self._scal_prod_f_gen(dvars, coef_fn, var_key_iter=var_key_iter)
def check_ordered_sequence(self, arg, caller, accept_iterator=True): # in some cases, we need an ordered sequence, if not the code won't crash # but may do unexpected things if not (is_ordered_sequence(arg) or (accept_iterator and is_iterator(arg))): self.fatal("{0}, got: {1!s}", caller, type(arg).__name__)
def check_ordered_sequence(self, arg, header): # in some cases, we need an ordered sequence, if not the code won't crash # but may do unexpected things if not is_ordered_sequence(arg) and not is_iterator(arg): self.fatal("{0}, got: {1!s}", header, type(arg).__name__)