def find_transform(x, y, limit, threshold=1e-7): """ find a integer solution to ax + b - cxy - dy = 0 this will give us the mobius transform: T(x) = y :param x: numeric constant to check :param y: numeric manipulation of constant :param limit: range to look at :param threshold: optimal solution threshold. :return MobiusTransform in case of success or None. """ x1 = x x2 = dec(1.0) x3 = -x * y x4 = -y solver = Solver('mobius', Solver.CBC_MIXED_INTEGER_PROGRAMMING) a = solver.IntVar(-limit, limit, 'a') b = solver.IntVar(-limit, limit, 'b') c = solver.IntVar(-limit, limit, 'c') d = solver.IntVar(-limit, limit, 'd') f = solver.NumVar(0, 1, 'f') solver.Add(f == (a * x1 + b * x2 + c * x3 + d * x4)) solver.Add(a * x1 + b >= 1) # don't except trivial solutions and remove some redundancy solver.Minimize(f) status = solver.Solve() if status == Solver.OPTIMAL: if abs(solver.Objective().Value()) <= threshold: res_a, res_b, res_c, res_d = int(a.solution_value()), int(b.solution_value()),\ int(c.solution_value()), int(d.solution_value()) ret = MobiusTransform( np.array([[res_a, res_b], [res_c, res_d]], dtype=object)) ret.normalize() return ret else: return None
def main(): # Create the linear solver with the GLOP backend. solver = Solver('simple_lp_program', Solver.GLOP_LINEAR_PROGRAMMING) # Create the variables x and y. x = solver.NumVar(0, 1, 'x') y = solver.NumVar(0, 2, 'y') print('Number of variables =', solver.NumVariables()) # Create a linear constraint, 0 <= x + y <= 2. ct = solver.Constraint(0, 2, 'ct') ct.SetCoefficient(x, 1) ct.SetCoefficient(y, 1) print('Number of constraints =', solver.NumConstraints()) # Create the objective function, 3 * x + y. objective = solver.Objective() objective.SetCoefficient(x, 3) objective.SetCoefficient(y, 1) objective.SetMaximization() solver.Solve() print('Solution:') print('Objective value =', objective.Value()) print('x =', x.solution_value()) print('y =', y.solution_value())
def _declare_variable(self, solver: pywraplp.Solver, nth_cycle: int, nth_index: int) -> None: return solver.NumVar( MIN_N_PHASES_FOR_SUSTAIN, MIN_N_PHASES_FOR_SUSTAIN * MAX_N_MIN_PHASES_FOR_SUSTAIN, self._get_variable_name(nth_cycle, nth_index), )
def _add_stock_variables(num_types: int, num_time_periods: int, solver: Solver) \ -> Dict[V, Variable]: """Create stock variables. A stock variable $s^t_p$ is a non-negative real variable which represents the number of items of type $t$ on stock in time period $p$. :param num_types: the number of considered types :param num_time_periods: the number of considered time periods :param solver: the underlying solver for which to built the variables :return: A dictionary mapping each stock variable to its solver variable """ stock_vars = dict() for (item_type, time_period) in product(range(num_types), range(-1, num_time_periods)): stock_vars[V(type=item_type, period=time_period)] = \ solver.NumVar(lb=0., ub=solver.infinity(), name=f's_{item_type}_{time_period}') module_logger.info(f'Created {len(stock_vars)} stock variables.') return stock_vars
def _set_coefficients(solver: pywraplp.Solver, objective_or_constraint, coefficient_part: str, line_nr: int, var_names: set): # Strip the coefficient whitespace remainder = coefficient_part.strip() if len(remainder) == 0: raise ValueError("No variables present in equation on line %d." % line_nr) # All variables found var_names_found = set() running_constant_sum = 0.0 had_at_least_one_variable = False while len(remainder) != 0: # Combination sign coefficient = 1.0 combination_sign_match = re.search(r"^[-+]", remainder) if combination_sign_match is not None: if combination_sign_match.group() == "-": coefficient = -1.0 remainder = remainder[1:].strip() # Real sign sign_match = re.search(r"^[-+]", remainder) if sign_match is not None: if sign_match.group() == "-": coefficient = coefficient * -1.0 remainder = remainder[ 1:] # There is no strip() here, as it must be directly in front of the mantissa # Mantissa and exponent mantissa_exp_match = re.search(r"^(\d+(\.\d*)?|\.\d+)([eE][-+]?\d+)?", remainder) whitespace_after = False if mantissa_exp_match is not None: coefficient = coefficient * float(mantissa_exp_match.group()) remainder = remainder[mantissa_exp_match.span()[1]:] stripped_remainder = remainder.strip() if len(remainder) != len(stripped_remainder): whitespace_after = True remainder = stripped_remainder # Variable name var_name_match = re.search(_REGEXP_SINGLE_VAR_NAME_START, remainder) if var_name_match is not None: # It must have had at least one variable had_at_least_one_variable = True # Retrieve clean variable name clean_var = var_name_match.group() var_names.add(clean_var) if clean_var in var_names_found: raise ValueError( "Variable \"%s\" found more than once on line %d." % (clean_var, line_nr)) var_names_found.add(clean_var) solver_var = solver.LookupVariable(clean_var) if solver_var is None: solver_var = solver.NumVar(-solver.infinity(), solver.infinity(), clean_var) # Set coefficient objective_or_constraint.SetCoefficient(solver_var, coefficient) # Strip what we matched remainder = remainder[var_name_match.span()[1]:] stripped_remainder = remainder.strip() whitespace_after = False if len(remainder) != len(stripped_remainder): whitespace_after = True remainder = stripped_remainder elif mantissa_exp_match is None: raise ValueError( "Cannot process remainder coefficients of \"%s\" on line %d." % (remainder, line_nr)) else: running_constant_sum += coefficient # At the end of each element there either: # (a) Must be whitespace (e.g., x1 x2 <= 10) # (b) The next combination sign (e.g., x1+x2 <= 10) # (c) Or it was the last one, as such remainder is empty (e.g., x1 <= 10) if len(remainder) != 0 and not whitespace_after and remainder[ 0:1] != "-" and remainder[0:1] != "+": raise ValueError( "Unexpected next character \"%s\" on line %d (expected whitespace or " "combination sign character)." % (remainder[0:1], line_nr)) # There must have been at least one variable if not had_at_least_one_variable: raise ValueError( "Not a single variable present in the coefficients on line %d." % line_nr) return running_constant_sum