def parse(arg, logger=None, default_sense=None): if isinstance(arg, ObjectiveSense): return arg elif is_string(arg): lower_text = arg.lower() if lower_text in {"minimize", "min"}: return ObjectiveSense.Minimize elif lower_text in {"maximize", "max"}: return ObjectiveSense.Maximize elif default_sense: logger.error( "Text is not recognized as objective sense: {0}, expecting \"min\" or \"max\" - using default {1:s}", (arg, default_sense)) return default_sense elif logger: logger.fatal("Text is not recognized as objective sense: {0}, expecting ""min"" or ""max", (arg,)) else: docplex_fatal("Text is not recognized as objective sense: {0}, expecting ""min"" or ""max".format(arg)) elif is_int(arg): if arg == 1: return ObjectiveSense.Minimize elif -1 == arg: return ObjectiveSense.Maximize else: logger.fatal("cannot convert: <{}> to objective sense", (arg,)) elif arg is None: return default_sense elif logger: logger.fatal("cannot convert: <{}> to objective sense", (arg,)) else: docplex_fatal("cannot convert: <{}> to objective sense".format(arg))
def __call__(self, *args): if not args: return self._current_value elif len(args) == 1: self.set(args[0]) else: docplex_fatal('Call parameter accepts either 0 or 1 argument')
def check_as_mip_start(self, strong_check=False): """Checks that this solution is a valid MIP start. To be valid, it must have: * at least one discrete variable (integer or binary), and * the values for decision variables should be consistent with the type. Returns: Boolean: True if this solution is a valid MIP start. """ count_values = 0 count_errors = 0 m = self.model for dv, dvv in self.iter_var_values(): if dv.is_discrete() and not dv.is_generated(): count_values += 1 if not dv.accepts_value(dvv): # pragma: no cover count_errors += 1 m.warning( "Solution value {1} is outside the domain of variable {0!r}: {1}, type: {2!s}", dv, dvv, dv.vartype.short_name) if count_values == 0: docplex_fatal( "MIP start contains no discrete variable") # pragma: no cover return not count_errors if strong_check else True
def new_engine(self, agent, env, model, context=None): self._ensure_cplex_resolved(env) # compute a default engine and kwargs to use.. kwargs = {} if self._cplex_engine_type: # default is CPLEX if we have it default_engine_type = self._cplex_engine_type default_engine_name = 'cplex' else: # no CPLEX, no credentials default_engine_type = NoSolveEngine default_engine_name = 'nosolve' if has_credentials(context.solver.docloud): kwargs['docloud_context'] = context.solver.docloud if context is not None: kwargs['context'] = context engine_type = self._get_engine_type_from_agent(agent=agent, default_engine=default_engine_type, default_engine_name=default_engine_name) assert engine_type is not None try: return engine_type(model, **kwargs) except TypeError: docplex_fatal("agent: {0!s} failed to create instance from model, kwargs.", agent)
def _check_value(self, raw_value): if raw_value == self.default_value: return raw_value elif not self.accept_value(raw_value): docplex_fatal("Value {0!s} of type {2} is invalid for parameter {1}", raw_value, self.qualified_name, type(raw_value)) else: return self.transform_value(raw_value)
def check_cplex_version(self): cpx_version = self.cplex_version_as_tuple if self.has_cplex and cpx_version < (min_cplex_major, min_cplex_minor): s_min_version = "{0}.{1}".format(min_cplex_major, min_cplex_minor) docplex_fatal( "DOcplex supports Cplex from {0} up, unsupported version {1} was found" .format(s_min_version, self.cplex_version))
def _check_value(self, raw_value): if raw_value == self.default_value: return raw_value elif not self.accept_value(raw_value): docplex_fatal("Value {0!r} of type {2} is invalid for parameter '{1}'", raw_value, self.get_qualified_name(include_root=False), type(raw_value)) else: return self.transform_value(raw_value)
def static_validate_num(e, checked_num=False, infinity=1e+20): if not checked_num and not is_number(e): docplex_fatal("Expecting number, got: {0!r}".format(e)) elif -infinity <= e <= infinity: return e elif e >= infinity: return infinity else: return -infinity
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 parse(arg): # INTERNAL # noinspection PyTypeChecker for m in RelaxationMode: if arg == m or arg == m.value: return m elif is_string(arg): if arg == str(m.value) or arg.lower() == m.name.lower(): return m docplex_fatal('cannot parse this as a relaxation mode: {0!r}'.format(arg))
def __setattr__(self, attr_name, value): if attr_name.startswith("_"): self.__dict__[attr_name] = value elif hasattr(self, attr_name): attr = getattr(self, attr_name) if isinstance(attr, Parameter): # attribute is set inside param, not necessarily in engine... attr.set(value) else: docplex_fatal("No parameter with name {0} in {1}", attr_name, self.qualified_name()) else: docplex_fatal("No parameter with name {0} in {1}", attr_name, self.qualified_name())
def find_parameter(self, key): if is_int(key): pred = lambda p: p.cpx_id == key elif is_string(key): # eliminate initial '.' pred = lambda p: p.get_qualified_name(include_root=False) == key else: docplex_fatal('Parameters.find() accepts either integer code or path-like name, got: {0!r}'.format(key)) for p in self: if pred(p): return p else: return None
def _resolve_cplex(self, env): # INTERNAL if env is None: docplex_fatal("need an environment to resolve cplex, got None") if not self._is_cplex_resolved(): if env.has_cplex: from docplex.mp.cplex_engine import CplexEngine self._cplex_engine_type = CplexEngine # noinspection PyTypeChecker self._engine_types_by_agent["cplex"] = CplexEngine else: self._cplex_engine_type = None
def parse(cls, arg, do_raise=True): # INTERNAL # noinspection PyTypeChecker for m in cls: if arg == m or arg == m.value: return m elif is_string(arg): if arg == str(m.value) or arg.lower() == m.name.lower(): return m if do_raise: docplex_fatal('cannot convert this to a solve attribute: {0!r}'.format(arg)) else: return None
def parse(cls, txt, raise_on_error=True): for qm in cls: if txt == qm.name: return qm elif txt == qm.value: return qm elif txt == qm.cpx_codename: return qm else: fmt = '* cannot interpret this as a QualityMetric enum: {0!r}' if raise_on_error: docplex_fatal(fmt, txt) else: print(fmt.format(txt)) return None
def parse(cls, arg, do_raise=True): # INTERNAL # noinspection PyTypeChecker for op in cls: if arg in (op, op.value): return op elif is_string(arg): if arg == op._cplex_code \ or arg == str(op.value) \ or arg.lower() == op.name.lower(): return op # not found if do_raise: docplex_fatal('cannot convert this to a comparison type: {0!r}'.format(arg)) else: return None
def update_cplex_parameters(self, arg_params): # INTERNAL new_params = self.cplex_parameters.copy() # try a dictionary of parameter qualified names, parameter values # e.g. cplex_parameters={'mip.tolerances.mipgap': 0.01, 'timelimit': 180} try: for pk, pv in iteritems(arg_params): p = new_params.find_parameter(key=pk) if not p: docplex_fatal('Cannot find matching parameter from: {0!r}'.format(pk)) else: p.set(pv) self.cplex_parameters = new_params except (TypeError, AttributeError): docplex_fatal('Expecting CPLEX parameters or dict, got: {0!r}'.format(arg_params))
def _docplex_sum_with_seq(x_list): shared_model = None for x in x_list: try: model = x.model if not shared_model: shared_model = model else: if model != shared_model: docplex_fatal("Cannot mix objects belonging to different models") except AttributeError: pass if shared_model: return shared_model.sum(x_list) else: # try a python sum ? return sum(x_list)
def parse(arg, sos1_tokens=frozenset(['1', 'sos1']), sos2_tokens=frozenset(['2', 'sos2'])): if isinstance(arg, SOSType): return arg elif 1 == arg: return SOSType.SOS1 elif 2 == arg: return SOSType.SOS2 elif is_string(arg): arg_lower = arg.lower() if arg_lower in sos1_tokens: return SOSType.SOS1 elif arg_lower in sos2_tokens: return SOSType.SOS2 docplex_fatal("Cannot convert to SOS type: {0!s} - expecting 1|2|'sos1'|'sos2'", arg)
def _get_engine_type_from_agent(self, agent, default_engine, default_engine_name): if agent is None: return default_engine elif is_string(agent): agent_key = agent.lower() engine_type = self._engine_types_by_agent.get(agent_key) if engine_type: return engine_type elif 'cplex' == agent_key: print( '* warning: CPLEX DLL not found in path, using {0} instead' .format(default_engine_name)) return self._engine_types_by_agent.get(default_engine_name) elif '.' in agent: # assuming a qualified name, e.g. com.ibm.docplex.quantum.QuantumEngine from docplex.mp.internal.mloader import import_class try: agent_class = import_class(agent) return agent_class except ValueError as ve: print( "Cannot load agent class {0}, expecting 'cplex', 'docloud' or valid class path, error: {1}" .format(agent, str(ve))) raise ve else: docplex_fatal( "Unexpected agent name: {0}, expecting 'cplex', 'docloud' or valid class path", agent) else: # try a class type try: # noinspection PyUnresolvedReferences from inspect import isclass if isclass(agent): return agent except ImportError: if type(agent) == type: return agent # agent cannot be mapped to any class. docplex_fatal( "* unexpected agent: {0!r} -expecting 'cplex', 'docloud', class or class name", agent)
def _docplex_extract_model(e, do_raise=True): try: model = e.model return model except AttributeError: if do_raise: raise docplex_fatal("object has no model attribute: {0!s}", e) else: return None
def static_validate_num2(e, infinity=1e+20, context_msg=None): # checks for number, nans, nath.inf, and truncates to 1e+20 if not is_number(e): docplex_fatal("Not a number: {}".format(e)) elif math.isnan(e): msg = "NaN value found in expression" if context_msg is not None: try: msg = "{0}: {1}".format(context_msg(), msg) except TypeError: msg = "{0}: {1}".format(context_msg, msg) docplex_fatal(msg) elif math.isinf(e): msg = "Infinite value forbidden in expression" if context_msg is not None: try: msg = "{0}: {1}".format(context_msg(), msg) except TypeError: msg = "{0}: {1}".format(context_msg, msg) docplex_fatal(msg) elif -infinity <= e <= infinity: return e elif e >= infinity: return infinity else: return -infinity
def check_as_mip_start(self): """Checks that this solution is a valid MIP start. To be valid, it must have: * at least one discrete variable (integer or binary), and * the values for decision variables should be consistent with the type. Returns: Boolean: True if this solution is a valid MIP start. """ is_explicit = self._keep_zeros if is_explicit and not self.__var_value_map: docplex_fatal("MIP start solution is empty, provide at least one discrete variable value") discrete_vars = (dv for dv in self.iter_variables() if dv.is_discrete()) count_values = 0 count_errors = 0 for dv in discrete_vars: sol_value = self._get_var_value(dv) if not dv.accept_initial_value(sol_value): count_errors += 1 docplex_fatal("Wrong initial value for variable {0!r}: {1}, type: {2!s}", # pragma: no cover dv.name, sol_value, dv.vartype.short_name) # pragma: no cover else: count_values += 1 if is_explicit and count_values == 0: docplex_fatal("MIP start contains no discrete variable") # pragma: no cover return True
def new_engine(self, agent, env, model, context=None): self._ensure_cplex_resolved(env) # compute a default engine and kwargs to use.. kwargs = {} if self._cplex_engine_type: # CPLEX ahs been resolved and has a non-None type # default is CPLEX if we have it default_engine_type = self._cplex_engine_type default_engine_name = 'cplex' elif has_credentials(context.solver.docloud): # default is docloud default_engine_type = DOcloudEngine default_engine_name = 'docloud' else: # no CPLEX, no credentials # model.trace("CPLEX DLL not found and model has no DOcplexcloud credentials. " # "Credentials are required at solve time") default_engine_type = NoSolveEngine default_engine_name = 'nosolve' if has_credentials(context.solver.docloud): kwargs['docloud_context'] = context.solver.docloud engine_type = self._get_engine_type_from_agent( agent=agent, default_engine=default_engine_type, default_engine_name=default_engine_name) assert engine_type is not None try: return engine_type(model, **kwargs) except TypeError: docplex_fatal( "agent: {0!s} failed to create instance from model, kwargs.", agent)
def check_solution_clock(self): if not self.clock.listens_to_solution: docplex_fatal('Solution listener requires a solution clock among (Solutions,Objective|Gap), {0} was passed', self.clock)
def to_expr(self): docplex_fatal( "This KPI cannot be used as an expression: {0!r}".format(self))
def _check_successful_relaxation(self): if not self._last_relaxation_status: docplex_fatal("No relaxed solution is present")
def get_cplex(self): docplex_fatal("No cplex is available.") # pragma: no cover