def hinge_bf_to_factor(bf, bf_var): knot = bf.get_knot() if bf.get_reverse(): factor = Max(0, RealNumber(knot) - bf_var) else: factor = Max(0, bf_var - RealNumber(knot)) return factor
def smoothed_hinge_bf_to_factor(bf, bf_var): knot = RealNumber(bf.get_knot()) knot_minus = RealNumber(bf.get_knot_minus()) knot_plus = RealNumber(bf.get_knot_plus()) r = RealNumber(bf.get_r()) p = RealNumber(bf.get_p()) if bf.get_reverse(): lower_p = (-(bf_var - knot)), (bf_var <= knot_minus) upper_p = (0, bf_var >= knot_plus) left_exp = Mul(p, Pow((bf_var - knot_plus), 2)) right_exp = Mul(r, Pow((bf_var - knot_plus), 3)) middle_b = And(knot_minus < bf_var, bf_var < knot_plus) middle_exp = (Add(left_exp, right_exp), middle_b) piecewise = Piecewise(lower_p, upper_p, middle_exp) factor = piecewise else: lower_p = (0, bf_var <= knot_minus) upper_p = (bf_var - knot, bf_var >= knot_plus) left_exp = Mul(p, Pow((bf_var - knot_minus), 2)) right_exp = Mul(r, Pow((bf_var - knot_minus), 3)) middle_b = And(knot_minus < bf_var, bf_var < knot_plus) middle_exp = (Add(left_exp, right_exp), middle_b) piecewise = Piecewise(lower_p, upper_p, middle_exp) factor = piecewise return factor
def _add_switches(self, reactions): logger.info("Adding switches.") y_vars = list() switches = list() self._exchanges = list() for reaction in reactions: if reaction.id.startswith('DM_'): # demand reactions don't need integer switches self._exchanges.append(reaction) continue y = self.model.solver.interface.Variable('y_' + reaction.id, lb=0, ub=1, type='binary') y_vars.append(y) # The following is a complicated but efficient way to write the following constraints # switch_lb = self.model.solver.interface.Constraint(y * reaction.lower_bound - reaction.flux_expression, # name='switch_lb_' + reaction.id, ub=0) # switch_ub = self.model.solver.interface.Constraint(y * reaction.upper_bound - reaction.flux_expression, # name='switch_ub_' + reaction.id, lb=0) forward_var_term = Mul._from_args( (RealNumber(-1), reaction.forward_variable)) reverse_var_term = Mul._from_args( (RealNumber(-1), reaction.reverse_variable)) switch_lb_y_term = Mul._from_args( (RealNumber(reaction.lower_bound), y)) switch_ub_y_term = Mul._from_args( (RealNumber(reaction.upper_bound), y)) switch_lb = self.model.solver.interface.Constraint( Add._from_args( (switch_lb_y_term, forward_var_term, reverse_var_term)), name='switch_lb_' + reaction.id, ub=0, sloppy=True) switch_ub = self.model.solver.interface.Constraint( Add._from_args( (switch_ub_y_term, forward_var_term, reverse_var_term)), name='switch_ub_' + reaction.id, lb=0, sloppy=True) switches.extend([switch_lb, switch_ub]) self.model.solver.add(y_vars) self.model.solver.add(switches, sloppy=True) logger.info("Setting minimization of switch variables as objective.") self.model.objective = self.model.solver.interface.Objective( Add(*y_vars), direction='min') self._y_vars_ids = [var.name for var in y_vars]
def _print_Piecewise(self, expr): from sympy import RealNumber # this fix is to prevent sympy from printing constructs like # merge(x,0,condition) which are illegal in Fortran newargs = ((RealNumber(x) if x.is_Integer else x \ for x in y) for y in expr.args) return super(F90CodePrinter, self)._print_Piecewise(Piecewise(*newargs))
def symbolic_exp(init_state, operator, t, var_vals, rel_epsilon=1e-5): """ exp(-1j * t * operator) init_state = sum( (-1j * dt)^k / k! * operator^k init_state, k=0..n) :param init_state: :param operator: :param n: :return: """ minus_jt = -1j * RealNumber(t) current_term = init_state result = lambdify(init_state.free_symbols, init_state, "numpy")( **{str(key): var_vals[str(key)] for key in init_state.free_symbols}) # make sure the result is a numpy array result = np.array(result, copy=False) delta = np.array([np.inf]) # counter k = Integer(0) # loop till convergence while np.linalg.norm(delta.reshape(-1), np.inf) / np.linalg.norm( result.reshape(-1), np.inf) > rel_epsilon: current_term = operator(current_term) k += 1 current_term *= minus_jt / k current_term = simplify(current_term) delta = lambdify(current_term.free_symbols, current_term, "numpy")(**{ str(key): var_vals[str(key)] for key in current_term.free_symbols }) if k == 1: result = result + delta else: result += delta print(k) print(np.linalg.norm(delta.reshape(-1), np.inf)) return result
def constant_bf_to_factor(bf, bf_var): return RealNumber(1)