def splitPow(expr, deep=False): if type(expr) == list or type(expr) == tuple: coeff = Mul(*[el for el in expr if el.is_number]) if coeff != 1: return [coeff] + splitPow([el for el in expr if not el.is_number], deep=deep) else: return flatten( [splitPow(el, deep=deep) for el in expr if not el.is_number]) if isinstance(expr, Pow): if not isinstance(expr.args[1], Symbol): res = expr.args[1] * [expr.args[0]] else: if isinstance(expr.args[0], Pow): return expr.args[0].args[1] * [ expr.args[0].args[0]**expr.args[1] ] return [expr] if not deep: return res return flatten([splitPow(el, deep=deep) for el in res]) if isinstance(expr, Mul): return splitPow(expr.args, deep=deep) if isinstance(expr, Trace): return [expr] else: return [expr]
def test_pauli_product(self): self.assertIsInstance(pauli_product(1), sympy.Matrix) self.assertIsInstance(pauli_product(1, 2), sympy.Matrix) self.assertListEqual(sympy.flatten(pauli_product(1)), [0, 1, 1, 0]) self.assertListEqual(sympy.flatten(pauli_product(2)), [0, -1j, 1j, 0]) self.assertListEqual(sympy.flatten(pauli_product( 1, 1)), [0, 0, 0, 1.0, 0, 0, 1.0, 0, 0, 1.0, 0, 0, 1.0, 0, 0, 0])
def Tensor(*tensor_products): """Create a new tensor""" ## First, go through and make the data nice if(len(tensor_products)==0): # Since Tensor objects are additive, the empty object should be zero return sympify(0) if(len(tensor_products)==1 and isinstance(tensor_products[0], TensorFunction)) : tensor_products = list(t_p for t_p in tensor_products[0].tensor_products if t_p!=0) elif(len(tensor_products)==1 and isinstance(tensor_products[0], TensorProductFunction)) : tensor_products = [tensor_products[0],] else: if(len(tensor_products)==1 and isinstance(tensor_products[0], list)): tensor_products = tensor_products[0] tensor_products = flatten(list(t_p for t_p in tensor_products if t_p!=0)) if(len(tensor_products)>0): rank=tensor_products[0].rank for t_p in tensor_products: if(t_p.rank != rank): raise ValueError("Cannot add rank-{0} tensor to rank-{1} tensors.".format(t_p.rank, rank)) ## Now, create the object and set its data. Because of sympy's ## caching, tensors with different data need to be created as ## classes with different names. So we just create a lighweight ## subclass with a unique name (the number at the end gets ## incremented every time we construct a tensor). global _Tensor_count ThisTensorFunction = type('TensorFunction_'+str(_Tensor_count), (TensorFunction,), {}) _Tensor_count += 1 T = ThisTensorFunction( *tuple( set( flatten( [t_p.args for t_p in tensor_products] ) ) ) ) T.tensor_products = tensor_products return T
def categorical_cross_entropy_sample(self, predicted, target): target_flatten = flatten(target) predicted_flatten = flatten(predicted) target_var = [ auto_diff.Var(name=f't_{i}', value=float(target_flatten[i])) for i in range(len(target_flatten)) ] predicted_var = [ auto_diff.Var(name=f's_{i}', value=np.maximum(1e-15, float(predicted_flatten[i]))) for i in range(len(predicted_flatten)) ] log_predicted_var = [ auto_diff.Log(pred_var) for pred_var in predicted_var ] prod_target_predicted = [ auto_diff.Mul(ti, log_pred_i) for ti, log_pred_i in zip(target_var, log_predicted_var) ] sum_ce = reduce(lambda x, y: auto_diff.Add(x, y), prod_target_predicted) sum_ce = auto_diff.Mul(auto_diff.Constant(-1), sum_ce) cost = predicted - target # cost = np.array([sum_ce.gradient(pred_var).eval() for pred_var in predicted_var]).reshape( # predicted.shape # ) return {'error': sum_ce.eval(), 'derivative_error': cost}
def run(expr): # Return semantic (rebuilt expression, factorization candidates) if expr.is_Number or expr.is_Symbol: return expr, [expr] elif q_indexed(expr) or expr.is_Atom: return expr, [] elif expr.is_Add: rebuilt, candidates = zip(*[run(arg) for arg in expr.args]) w_numbers = [ i for i in rebuilt if any(j.is_Number for j in i.args) ] wo_numbers = [i for i in rebuilt if i not in w_numbers] w_numbers = collect_const(expr.func(*w_numbers)) wo_numbers = expr.func(*wo_numbers) if aggressive is True and wo_numbers: for i in flatten(candidates): wo_numbers = collect(wo_numbers, i) rebuilt = expr.func(w_numbers, wo_numbers) return rebuilt, [] elif expr.is_Mul: rebuilt, candidates = zip(*[run(arg) for arg in expr.args]) rebuilt = collect_const(expr.func(*rebuilt)) return rebuilt, flatten(candidates) else: rebuilt, candidates = zip(*[run(arg) for arg in expr.args]) return expr.func(*rebuilt), flatten(candidates)
def test_expand(): """ Ensure that an equation is expanded correctly. """ equations = ["Eq(Der(rho,t), -c*Conservative(rhou_j,x_j))"] substitutions = [] ndim = 1 constants = ["c"] coordinate_symbol = "x" metrics = [False, False] formulas = ["Eq(u_i, rhou_i/rho)"] problem = Problem(equations, substitutions, ndim, constants, coordinate_symbol, metrics, formulas) expanded_equations = flatten(problem.get_expanded(problem.equations)) expanded_formulas = flatten(problem.get_expanded(problem.formulas)) assert len(expanded_equations) == 1 assert str(expanded_equations[0].lhs) == "Derivative(rho[x0, t], t)" assert str(expanded_equations[0].rhs) == "-c*Derivative(rhou0[x0, t], x0)" assert len(expanded_formulas) == 1 assert str(expanded_formulas[0].lhs) == "u0[x0, t]" assert str(expanded_formulas[0].rhs) == "rhou0[x0, t]/rho[x0, t]" # Test the other way of expanding equations assert expanded_equations == flatten(problem.get_expanded(problem.expand(equations))) return
def test_solve_biquadratic(): x0, y0, x1, y1, r = symbols('x0 y0 x1 y1 r') f_1 = (x - 1)**2 + (y - 1)**2 - r**2 f_2 = (x - 2)**2 + (y - 2)**2 - r**2 assert solve_poly_system([f_1, f_2], x, y) == \ [(S(3)/2 + sqrt(-1 + 2*r**2)/2, S(3)/2 - sqrt(-1 + 2*r**2)/2), (S(3)/2 - sqrt(-1 + 2*r**2)/2, S(3)/2 + sqrt(-1 + 2*r**2)/2)] f_1 = (x - 1)**2 + (y - 2)**2 - r**2 f_2 = (x - 1)**2 + (y - 1)**2 - r**2 assert solve_poly_system([f_1, f_2], x, y) == \ [(1 + sqrt(((2*r - 1)*(2*r + 1)))/2, S(3)/2), (1 - sqrt(((2*r - 1)*(2*r + 1)))/2, S(3)/2)] query = lambda expr: expr.is_Pow and expr.exp is S.Half f_1 = (x - 1 )**2 + (y - 2)**2 - r**2 f_2 = (x - x1)**2 + (y - 1)**2 - r**2 result = solve_poly_system([f_1, f_2], x, y) assert len(result) == 2 and all(len(r) == 2 for r in result) assert all(r.count(query) == 1 for r in flatten(result)) f_1 = (x - x0)**2 + (y - y0)**2 - r**2 f_2 = (x - x1)**2 + (y - y1)**2 - r**2 result = solve_poly_system([f_1, f_2], x, y) assert len(result) == 2 and all(len(r) == 2 for r in result) assert all(len(r.find(query)) == 1 for r in flatten(result))
def update_dynamics(self): eqs = dict(self.rhs()) keys = set(eqs.keys()) symvars = [getattr(self, v) for v in self.vars] if keys <= set(self.nodes): # by node dep = flatten(zip(*symvars)) expr = flatten(sym.Matrix([eqs[node] for node in self])) elif keys <= set(self.vars): # by variable dep = it.chain.from_iterable(symvars) expr = flatten(sym.Matrix([eqs[v] for v in self.vars])) else: raise ValueError( "rhs must map either nodes to rhs or variables to rhs") dep_expr = [(d, e + Zero()) for d, e in zip(dep, expr)] if any(expr == sym.nan for _, expr in dep_expr): raise ValueError( "At least one rhs expression is NaN. Missing parameters?") self._sys = SymbolicSys(dep_expr, self.t) if self.use_native: self._native_sys = native_sys[self.integrator].from_other( self._sys) self._stale_dynamics = False
def age_moment_system(self, max_order): u = self.external_inputs #X = Matrix(self.state_variables) X = self.state_vector A = self.compartmental_matrix n = self.nr_pools extended_state = list(X) former_additional_states = [1] * n extended_rhs = list(self.F) for k in range(1, max_order + 1): additional_states = [ Symbol(str(x) + '_moment_' + str(k)) for x in X ] g = [ k * former_additional_states[i] + (sum([(additional_states[j] - additional_states[i]) * A[i, j] * X[j] for j in range(n)]) - additional_states[i] * u[i]) / X[i] for i in range(n) ] former_additional_states = additional_states extended_state.append(additional_states) extended_rhs.append(g) extended_state = Matrix(flatten(extended_state)) extended_rhs = Matrix(flatten(extended_rhs)) return (extended_state, extended_rhs)
def __sub__(self, other): indmatch = [ind in other.indices for ind in self.indices] compatible = False not in indmatch final_shape = self.vals.shape value_count = len(sympy.flatten(self.vals)) vals_self = sympy.flatten(self.vals) vals_other = sympy.flatten(other.vals) vals_final = vals_self[:] inds_other = [other.indices.index(ind) for ind in self.indices] for v_index in range(value_count): enum_other = [ v_index // self.dims**((self.rank - 1) - i) % self.dims for i in inds_other ] i_other = sum([ enum_other[i] * self.dims**(self.rank - 1 - i) for i in range(self.rank) ]) vals_final[v_index] -= vals_other[i_other] new_vals = sympy.Array(vals_final, shape=final_shape) return Tensor(self.indices, new_vals)
def test_solve_biquadratic(): x0, y0, x1, y1, r = symbols('x0 y0 x1 y1 r') f_1 = (x - 1)**2 + (y - 1)**2 - r**2 f_2 = (x - 2)**2 + (y - 2)**2 - r**2 assert solve_poly_system([f_1, f_2], x, y) == \ [(S(3)/2 + (-1 + 2*r**2)**(S(1)/2)/2, S(3)/2 - (-1 + 2*r**2)**(S(1)/2)/2), (S(3)/2 - (-1 + 2*r**2)**(S(1)/2)/2, S(3)/2 + (-1 + 2*r**2)**(S(1)/2)/2)] f_1 = (x - 1)**2 + (y - 2)**2 - r**2 f_2 = (x - 1)**2 + (y - 1)**2 - r**2 assert solve_poly_system([f_1, f_2], x, y) == \ [(1 + (((2*r - 1)*(2*r + 1)))**(S(1)/2)/2, S(3)/2), (1 - (((2*r - 1)*(2*r + 1)))**(S(1)/2)/2, S(3)/2)] query = lambda expr: expr.is_Pow and expr.exp is S.Half f_1 = (x - 1)**2 + (y - 2)**2 - r**2 f_2 = (x - x1)**2 + (y - 1)**2 - r**2 result = solve_poly_system([f_1, f_2], x, y) assert len(result) == 2 and all(len(r) == 2 for r in result) assert all(r.count(query) == 1 for r in flatten(result)) f_1 = (x - x0)**2 + (y - y0)**2 - r**2 f_2 = (x - x1)**2 + (y - y1)**2 - r**2 result = solve_poly_system([f_1, f_2], x, y) assert len(result) == 2 and all(len(r) == 2 for r in result) assert all(len(r.find(query)) == 1 for r in flatten(result))
def update_state_jacobian_function(self): if not self.dim_state or self.state_equation == empty_array(): return self.state_jacobian_equation_function = self.code_generator( [dynamicsymbols._t] + sp.flatten(self.state) + sp.flatten(self.input), self.state_jacobian_equation.subs(self.constants_values), **self.code_generator_args)
def update_input_jacobian_function(self): # TODO: state-less systems should have an input/output jacobian if not self.dim_state or self.state_equation == empty_array(): return self.input_jacobian_equation_function = self.code_generator( [dynamicsymbols._t] + sp.flatten(self.state) + sp.flatten(self.input), self.input_jacobian_equation.subs(self.constants_values), **self.code_generator_args)
def test_solve_biquadratic(): x0, y0, x1, y1, r = symbols('x0 y0 x1 y1 r') f_1 = (x - 1)**2 + (y - 1)**2 - r**2 f_2 = (x - 2)**2 + (y - 2)**2 - r**2 s = sqrt(2*r**2 - 1) a = (3 - s)/2 b = (3 + s)/2 assert solve_poly_system([f_1, f_2], x, y) == [(a, b), (b, a)] f_1 = (x - 1)**2 + (y - 2)**2 - r**2 f_2 = (x - 1)**2 + (y - 1)**2 - r**2 assert solve_poly_system([f_1, f_2], x, y) == \ [(1 - sqrt(((2*r - 1)*(2*r + 1)))/2, Rational(3, 2)), (1 + sqrt(((2*r - 1)*(2*r + 1)))/2, Rational(3, 2))] query = lambda expr: expr.is_Pow and expr.exp is S.Half f_1 = (x - 1 )**2 + (y - 2)**2 - r**2 f_2 = (x - x1)**2 + (y - 1)**2 - r**2 result = solve_poly_system([f_1, f_2], x, y) assert len(result) == 2 and all(len(r) == 2 for r in result) assert all(r.count(query) == 1 for r in flatten(result)) f_1 = (x - x0)**2 + (y - y0)**2 - r**2 f_2 = (x - x1)**2 + (y - y1)**2 - r**2 result = solve_poly_system([f_1, f_2], x, y) assert len(result) == 2 and all(len(r) == 2 for r in result) assert all(len(r.find(query)) == 1 for r in flatten(result)) s1 = (x*y - y, x**2 - x) assert solve(s1) == [{x: 1}, {x: 0, y: 0}] s2 = (x*y - x, y**2 - y) assert solve(s2) == [{y: 1}, {x: 0, y: 0}] gens = (x, y) for seq in (s1, s2): (f, g), opt = parallel_poly_from_expr(seq, *gens) raises(SolveFailed, lambda: solve_biquadratic(f, g, opt)) seq = (x**2 + y**2 - 2, y**2 - 1) (f, g), opt = parallel_poly_from_expr(seq, *gens) assert solve_biquadratic(f, g, opt) == [ (-1, -1), (-1, 1), (1, -1), (1, 1)] ans = [(0, -1), (0, 1)] seq = (x**2 + y**2 - 1, y**2 - 1) (f, g), opt = parallel_poly_from_expr(seq, *gens) assert solve_biquadratic(f, g, opt) == ans seq = (x**2 + y**2 - 1, x**2 - x + y**2 - 1) (f, g), opt = parallel_poly_from_expr(seq, *gens) assert solve_biquadratic(f, g, opt) == ans
def test_solve_biquadratic(): x0, y0, x1, y1, r = symbols('x0 y0 x1 y1 r') f_1 = (x - 1)**2 + (y - 1)**2 - r**2 f_2 = (x - 2)**2 + (y - 2)**2 - r**2 s = sqrt(2*r**2 - 1) a = (3 - s)/2 b = (3 + s)/2 assert solve_poly_system([f_1, f_2], x, y) == [(a, b), (b, a)] f_1 = (x - 1)**2 + (y - 2)**2 - r**2 f_2 = (x - 1)**2 + (y - 1)**2 - r**2 assert solve_poly_system([f_1, f_2], x, y) == \ [(1 - sqrt(((2*r - 1)*(2*r + 1)))/2, S(3)/2), (1 + sqrt(((2*r - 1)*(2*r + 1)))/2, S(3)/2)] query = lambda expr: expr.is_Pow and expr.exp is S.Half f_1 = (x - 1 )**2 + (y - 2)**2 - r**2 f_2 = (x - x1)**2 + (y - 1)**2 - r**2 result = solve_poly_system([f_1, f_2], x, y) assert len(result) == 2 and all(len(r) == 2 for r in result) assert all(r.count(query) == 1 for r in flatten(result)) f_1 = (x - x0)**2 + (y - y0)**2 - r**2 f_2 = (x - x1)**2 + (y - y1)**2 - r**2 result = solve_poly_system([f_1, f_2], x, y) assert len(result) == 2 and all(len(r) == 2 for r in result) assert all(len(r.find(query)) == 1 for r in flatten(result)) s1 = (x*y - y, x**2 - x) assert solve(s1) == [{x: 1}, {x: 0, y: 0}] s2 = (x*y - x, y**2 - y) assert solve(s2) == [{y: 1}, {x: 0, y: 0}] gens = (x, y) for seq in (s1, s2): (f, g), opt = parallel_poly_from_expr(seq, *gens) raises(SolveFailed, lambda: solve_biquadratic(f, g, opt)) seq = (x**2 + y**2 - 2, y**2 - 1) (f, g), opt = parallel_poly_from_expr(seq, *gens) assert solve_biquadratic(f, g, opt) == [ (-1, -1), (-1, 1), (1, -1), (1, 1)] ans = [(0, -1), (0, 1)] seq = (x**2 + y**2 - 1, y**2 - 1) (f, g), opt = parallel_poly_from_expr(seq, *gens) assert solve_biquadratic(f, g, opt) == ans seq = (x**2 + y**2 - 1, x**2 - x + y**2 - 1) (f, g), opt = parallel_poly_from_expr(seq, *gens) assert solve_biquadratic(f, g, opt) == ans
def update_output_equation_function(self): if not self.dim_output or self.output_equation == empty_array(): return if self.dim_state: self.output_equation_function = self.code_generator( [dynamicsymbols._t] + sp.flatten(self.state), self.output_equation.subs(self.constants_values), **self.code_generator_args) else: self.output_equation_function = self.code_generator( [dynamicsymbols._t] + sp.flatten(self.input), self.output_equation.subs(self.constants_values), **self.code_generator_args)
def test_parse_from_sympy_expr(self): a, b = sympy.symbols('a, b') x1 = pauli_product(1, 0) xx = pauli_product(1, 1) expr = a * x1 + b * xx net = QubitNetwork(sympy_expr=expr) hamiltonian_matrix = net.get_matrix() self.assertListEqual( sympy.flatten(hamiltonian_matrix), sympy.flatten(sympy.Matrix([[0, 0, 1.0*a, 1.0*b], [0, 0, 1.0*b, 1.0*a], [1.0*a, 1.0*b, 0, 0], [1.0*b, 1.0*a, 0, 0]]))) self.assertEqual(net.num_qubits, 2)
def _eval_expand_basic(self, deep=True, **hints): from sympy import flatten if not deep: return self else: return Integral(self.function.expand(deep=deep, **hints),\ flatten(*self.limits))
def _print_Mul(self, expr): if expr.find(Indexed) != set() and expr.find(Pow) != set(): if not all([int(el.exp) != el.exp for el in expr.find(Pow)]): return ' '.join([self._print(el) for el in splitPow(expr)]) if isinstance(expr.args[0], Rational) and abs(expr.args[0]) != 1 and not self.baseMul: coeff = Mul(*[el for el in flatten(expr.as_coeff_mul()) if el.is_number]) return self.latex.totex(coeff, baseMul=True) + ' ' + (self._print((expr/coeff).doit()) if expr != coeff else '') if self.absReplacements and expr.find(conjugate) != set(): # Substitution x * conjugate(x) -> |x|^2 conjArgs = {} args = splitPow(expr) for el in args: if isinstance(el, conjugate) or el.is_commutative == False or el.is_real: continue else: count = min(args.count(el), args.count(conjugate(el))) if count != 0: conjArgs[el] = count if conjArgs != {}: for k,v in conjArgs.items(): for _ in range(v): args.remove(k) args.remove(conjugate(k)) args.append(Abs(k)**2) expr = Mul(*args) return super()._print_Mul(expr)
def compute_rextrap_weights(ndep, nfree=None, cfree=None): """Compute the Richardson extrapolation weights corresponding to the dependent step count sequence, given weights for the free step count sequence. :param ndep: dependent step count sequence :param nfree: free step count sequence :param cfree: free extrapolation weights """ b = sympy.zeros(len(ndep),1) b[0] = 1 ndep = sympy.Array(ndep) Vdep = _vander(ndep.applyfunc(lambda x:1/x**2),len(ndep)) if nfree is None and cfree is None: rhs = b else: if len(cfree) != len(nfree): raise ValueError('Free step count sequence length must match free weight length') nfree = sympy.Array(nfree) Vfree = _vander(nfree.applyfunc(lambda x:1/x**2),len(ndep)) cfree = sympy.Matrix(sympy.sympify(cfree)) rhs = b-Vfree*cfree return sympy.flatten(Vdep.inv()*rhs)
def system_from_matrix_DE(mat_DE, mat_var, mat_input=None, constants={}): """ Construct a symbolic DynamicalSystem using matrices. See riccati_system example. Parameters ---------- mat_DE : sympy Matrix The matrix derivative expression (right hand side) mat_var : sympy Matrix The matrix state mat_input : list-like of input expressions, optional A list-like of input expressions in the matrix differential equation constants : dict, optional Dictionary of constants substitutions. Returns ------- sys : DynamicalSystem A DynamicalSystem which can be used to numerically solve the matrix differential equation. """ vec_var = list(set(sp.flatten(mat_var.tolist()))) vec_DE = sp.Matrix.zeros(len(vec_var), 1) iterator = np.nditer(mat_DE, flags=['multi_index', 'refs_ok']) for it in iterator: i, j = iterator.multi_index idx = vec_var.index(mat_var[i, j]) vec_DE[idx] = mat_DE[i, j] sys = DynamicalSystem(vec_DE, sp.Matrix(vec_var), mat_input, constants_values=constants) return sys
def _preprocess(self, args, expr): """Preprocess args, expr to replace arguments that do not map to valid Python identifiers. Returns string form of args, and updated expr. """ from sympy import Dummy, Function, flatten, Derivative, ordered, Basic from sympy.matrices import DeferredVector # Args of type Dummy can cause name collisions with args # of type Symbol. Force dummify of everything in this # situation. dummify = self._dummify or any( isinstance(arg, Dummy) for arg in flatten(args)) argstrs = [None]*len(args) for arg, i in reversed(list(ordered(zip(args, range(len(args)))))): if iterable(arg): s, expr = self._preprocess(arg, expr) elif isinstance(arg, DeferredVector): s = str(arg) elif isinstance(arg, Basic) and arg.is_symbol: s = self._argrepr(arg) if dummify or not self._is_safe_ident(s): dummy = Dummy() s = self._argrepr(dummy) expr = self._subexpr(expr, {arg: dummy}) elif dummify or isinstance(arg, (Function, Derivative)): dummy = Dummy() s = self._argrepr(dummy) expr = self._subexpr(expr, {arg: dummy}) else: s = str(arg) argstrs[i] = s return argstrs, expr
def _congruency_class(self, irrep): l = flatten(irrep.tolist()) i = sum(l[-2:]) % 2 n = self.rank j = sum(l[:-2][::2]) + (n - 2) * l[-2] + n * l[-1] return (i, j)
def partial_trace(dm, n_qubits, subsystem): # This is the same calc. as for the tf_qc/qc.trace # First we find the last consecutive block to trace away block_end = subsystem[-1] block_start = block_end for idx in reversed(subsystem): if block_start - idx <= 1: block_start = idx else: break n_static1 = block_start # First part of static qubits n_static2 = (n_qubits - 1) - block_end # Second part of static qubits n_static = n_static1 + n_static2 n_qubits2trace = block_end - block_start + 1 # Qubits to trace away new_shape = [ 2**n_static1, 2**n_qubits2trace, 2**n_static2, 2**n_static1, 2**n_qubits2trace, 2**n_static2 ] flat_dm = sp.flatten(dm) new_dm = sp.NDimArray(flat_dm, shape=new_shape) trace_result = tensorcontraction(new_dm, (1, 4)) reshaped_result = trace_result.reshape(2**n_static, 2**n_static) # We must now recursively to the same to the lest of the subsystems idx_of_start = subsystem.index(block_start) new_subsystem = subsystem[:idx_of_start] return partial_trace(reshaped_result, n_static, new_subsystem) if len( new_subsystem) > 0 else reshaped_result.tomatrix()
def __new__(cls, iterable=None, shape=None, **kwargs): shape, flat_list = cls._handle_ndarray_creation_inputs( iterable, shape, **kwargs) shape = Tuple(*map(_sympify, shape)) loop_size = functools.reduce(lambda x, y: x * y, shape) if shape else 0 # Sparse array: if isinstance(flat_list, (dict, Dict)): sparse_array = Dict(flat_list) else: sparse_array = {} for i, el in enumerate(flatten(flat_list)): if el != 0: sparse_array[i] = _sympify(el) sparse_array = Dict(sparse_array) self = Basic.__new__(cls, sparse_array, shape, **kwargs) self._shape = shape self._rank = len(shape) self._loop_size = loop_size self._sparse_array = sparse_array return self
def hookContentFormula(self, partition, nMax): """ 1) Applies the Hook Content Formula to a semi-standard Young tableau with cells filled with the numbers 0, ...,n (repetitions are allowed) - see reference below 2) Recall that a partition {Lambda_1, Lambda_2, ...} is associated with a Young tableau where row i contains Lambda_i cells - for example the partition {4,3,1,1} of 9 yields the tableau 3) In a semi-standard Young tableau, the x_i which fill it must increase from top to bottom and must not decrease from left to right. 4) The number of semi-standard Young tableau given by the partition \[Lambda], where the cell can have any positive integer value smaller or equal to n is given by hookContentFormula(Lambda, n). 5)The application in model building of this is the following: consider a parameter M_f1f2, ... where the f_i =1,...,n are flavor indices. If Mu is known to have some symmetry (given by a partition Lambda) under a permutation of these indices, then the number of degrees of freedom in Mu is given by hookContentFormula(Lambda_n) (see examples below). """ n1 = partition[0] n2 = len(partition) inverseP = [ len([ell for ell in partition if ell >= el]) for el in range(1, n1 + 1) ] if type(nMax) != Symbol: aux = [[ Rational((nMax + i - j), partition[j - 1] + inverseP[i - 1] - (j - 1) - (i - 1) - 1) if partition[j - 1] + inverseP[i - 1] - (j - 1) - (i - 1) - 1 > 0 else 1 for j in range(1, n2 + 1) ] for i in range(1, n1 + 1)] else: aux = [[(nMax + i - j) / (partition[j - 1] + inverseP[i - 1] - (j - 1) - (i - 1) - 1) if partition[j - 1] + inverseP[i - 1] - (j - 1) - (i - 1) - 1 > 0 else 1 for j in range(1, n2 + 1)] for i in range(1, n1 + 1)] result = reduce(operator.mul, flatten(aux)) return result
def explode_term_respect_to(term, cls, deep=False, container=list): exploded = [term] # we start with the given term since we've to build a list, eventually if isinstance(term, cls): exploded = flatten(term.expand().args, cls=cls) if deep else term.args return container(exploded)
def event_variable_equation(self, event_variable_equation): assert event_variable_equation.atoms(sp.Symbol) <= set( self.constants_values.keys()) | set([dynamicsymbols._t]) self._event_variable_equation = event_variable_equation if self.dim_state: assert find_dynamicsymbols(event_variable_equation) <= \ set(self.state) self.event_variable_equation_function = self.code_generator( [dynamicsymbols._t] + sp.flatten(self.state), self._event_variable_equation.subs(self.constants_values), **self.code_generator_args) else: assert find_dynamicsymbols(event_variable_equation) <= \ set(self.input) self.event_variable_equation_function = self.code_generator( [dynamicsymbols._t] + sp.flatten(self.input), self._event_variable_equation.subs(self.constants_values), **self.code_generator_args)
def _new(cls, *args, **kwargs): shape, flat_list = cls._handle_ndarray_creation_inputs(*args, **kwargs) flat_list = flatten(flat_list) self = object.__new__(cls) self._shape = shape self._array = list(flat_list) self._rank = len(shape) self._loop_size = functools.reduce(lambda x,y: x*y, shape) if shape else 0 return self
def Tensor(*tensor_products): """Create a new tensor""" ## First, go through and make the data nice if (len(tensor_products) == 0): # Since Tensor objects are additive, the empty object should be zero return sympify(0) if (len(tensor_products) == 1 and isinstance(tensor_products[0], TensorFunction)): tensor_products = list(t_p for t_p in tensor_products[0].tensor_products if t_p != 0) elif (len(tensor_products) == 1 and isinstance(tensor_products[0], TensorProductFunction)): tensor_products = [ tensor_products[0], ] else: if (len(tensor_products) == 1 and isinstance(tensor_products[0], list)): tensor_products = tensor_products[0] tensor_products = flatten( list(t_p for t_p in tensor_products if t_p != 0)) if (len(tensor_products) > 0): rank = tensor_products[0].rank for t_p in tensor_products: if (t_p.rank != rank): raise ValueError( "Cannot add rank-{0} tensor to rank-{1} tensors.". format(t_p.rank, rank)) ## Now, create the object and set its data. Because of sympy's ## caching, tensors with different data need to be created as ## classes with different names. So we just create a lighweight ## subclass with a unique name (the number at the end gets ## incremented every time we construct a tensor). global _Tensor_count ThisTensorFunction = type('TensorFunction_' + str(_Tensor_count), (TensorFunction, ), {}) _Tensor_count += 1 T = ThisTensorFunction( *tuple(set(flatten([t_p.args for t_p in tensor_products])))) T.tensor_products = tensor_products return T
def age_moment_system(self, max_order): """Return the age moment system of the model. Args: max_order (int): The maximum order up to which the age moment system is created (1 for the mean). Returns: tuple: - extended_state (SymPy d*(max_order+1)x1-matrix): The extended state vector of the age moment system. - extended_rhs (SymPy d*(max_order+1)x1-matrix): The extended right hand side of the age moment ODE. """ u = self.external_inputs #X = Matrix(self.state_variables) X = self.state_vector B = self.compartmental_matrix n = self.nr_pools extended_state = list(X) former_additional_states = [1] * n extended_rhs = list(self.F) for k in range(1, max_order + 1): additional_states = [ Symbol(str(x) + '_moment_' + str(k)) for x in X ] g = [ k * former_additional_states[i] + (sum([(additional_states[j] - additional_states[i]) * B[i, j] * X[j] for j in range(n)]) - additional_states[i] * u[i]) / X[i] for i in range(n) ] former_additional_states = additional_states extended_state.append(additional_states) extended_rhs.append(g) extended_state = Matrix(flatten(extended_state)) extended_rhs = Matrix(flatten(extended_rhs)) return (extended_state, extended_rhs)
def flattenAdd(expr, depth=0): if not isinstance(expr, MatAdd): return expr else: ret = [] for term in [el for el in flatten(expr.as_coeff_add()) if el != 0]: ret.append(flattenAdd(term, depth=depth + 1)) if depth != 0: return ret # Simplification step res = 0 for el in flatten(ret): if res == 0: res = el else: res += el return res
def _congruency_class(self, irrep): n = self.rank if n == 8: return 0 l = flatten(irrep.tolist()) if n == 7: return (l[3] + l[5] + l[6]) % 2 if n == 6: return (l[0] - l[1] + l[3] - l[4]) % 3
def _new(cls, *args, **kwargs): shape, flat_list = cls._handle_ndarray_creation_inputs(*args, **kwargs) shape = Tuple(*map(_sympify, shape)) flat_list = flatten(flat_list) flat_list = Tuple(*flat_list) self = Basic.__new__(cls, flat_list, shape, **kwargs) self._shape = shape self._array = list(flat_list) self._rank = len(shape) self._loop_size = functools.reduce(lambda x,y: x*y, shape) if shape else 0 return self
def variables(self): """Model variables definition.""" v = super().variables ncol = self.collocation.n x = [xi.name for xi in v['x']] u = [ui.name for ui in v['u']] # Piece states and controls xp = [[f'{n}_piece_{k}' for n in x] for k in range(ncol)] up = [[f'{n}_piece_{k}' for n in u] for k in range(ncol)] additional_vars = sym2num.var.make_dict( [sym2num.var.SymbolArray('piece_len'), sym2num.var.SymbolArray('xp', xp), sym2num.var.SymbolArray('up', up), sym2num.var.SymbolArray('xp_flat', sympy.flatten(xp)), sym2num.var.SymbolArray('up_flat', sympy.flatten(up))] ) return collections.OrderedDict([*v.items(), *additional_vars.items()])
def num_rhs(X,t): # the ode solver delivers X as numpy.ndarray # however, our FL requires a tuple of arguments Xt = tuple(X) + (t,) #print('Xt', Xt) #cut_func_set #print('num_rhs', tup, Xt) Fval = FL(*Xt) #print(Fval) #pp("Fval",locals()) return flatten(Fval.tolist())
def indexed_terms_appearing_in(term, indexed, only_subscripts=False, do_traversal=False): indexed_terms_set = set() for subterm in preorder_traversal(term) if do_traversal else flatten(term.args, cls=Add): try: with bind_Mul_indexed(subterm, indexed) as (_, subscripts): indexed_terms_set.add(subscripts if only_subscripts else indexed[subscripts]) except DestructuringError: continue return list(indexed_terms_set)
def dynparms(self, parm_order=None): """Return list of RobotDef symbolic dynamic parameters.""" if not parm_order: parm_order = self._dyn_parms_order parm_order = parm_order.lower() parms = [] for i in range(0, self.dof): if parm_order == 'khalil' or parm_order == 'tensor first': # Lxx Lxy Lxz Lyy Lyz Lzz lx ly lz m parms += self.Le[i] parms += sympy.flatten(self.l[i]) parms += [self.m[i]] elif parm_order == 'siciliano' or parm_order == 'mass first': # m lx ly lz Lxx Lxy Lxz Lyy Lyz Lzz parms += [self.m[i]] parms += sympy.flatten(self.l[i]) parms += self.Le[i] else: raise Exception( 'RobotDef.Parms(): dynamic parameters order \'' + parm_order + '\' not know.') if self.driveinertiamodel == 'simplified': parms += [self.Ia[i]] if self.frictionmodel is not None: if 'viscous' in self.frictionmodel: parms += [self.fv[i]] if 'Coulomb' in self.frictionmodel: parms += [self.fc[i]] if 'offset' in self.frictionmodel: parms += [self.fo[i]] return parms
def test_scara_dh_sym_geo_kin(): pi = sympy.pi q = sympybotics.robotdef.q a1, a2, d3, d4 = sympy.symbols('a1, a2, d3, d4') scara = sympybotics.robotdef.RobotDef( 'SCARA - Spong', [( 0, a1, 0, q), (pi, a2, 0, q), ( 0, 0, q, 0), ( 0, 0, d4, q)], dh_convention='standard') scara_geo = sympybotics.geometry.Geometry(scara) scara_kin = sympybotics.kinematics.Kinematics(scara, scara_geo) cos, sin = sympy.cos, sympy.sin q1, q2, q3, q4 = sympy.flatten(scara.q) T_spong = sympy.Matrix([ [(-sin(q1)*sin(q2) + cos(q1)*cos(q2))*cos(q4) + (sin(q1)*cos(q2) + sin(q2)*cos(q1))*sin(q4), -(-sin(q1)*sin(q2) + cos(q1)*cos(q2))*sin(q4) + (sin(q1)*cos(q2) + sin(q2)*cos(q1))*cos(q4), 0, a1*cos(q1) - a2*sin(q1)*sin(q2) + a2*cos(q1)*cos(q2)], [(sin(q1)*sin(q2) - cos(q1)*cos(q2))*sin(q4) + (sin(q1)*cos(q2) + sin(q2)*cos(q1))*cos(q4), (sin(q1)*sin(q2) - cos(q1)*cos(q2))*cos(q4) - (sin(q1)*cos(q2) + sin(q2)*cos(q1))*sin(q4), 0, a1*sin(q1) + a2*sin(q1)*cos(q2) + a2*sin(q2)*cos(q1)], [0, 0, -1, -d4 - q3], [0, 0, 0, 1]]) J_spong = sympy.Matrix([[-a1*sin(q1) - a2*sin(q1)*cos(q2) - a2*sin(q2)*cos(q1), -a2*sin(q1)*cos(q2) - a2*sin(q2)*cos(q1), 0, 0], [a1*cos(q1) - a2*sin(q1)*sin(q2) + a2*cos(q1)*cos(q2), -a2*sin(q1)*sin(q2) + a2*cos(q1)*cos(q2), 0, 0], [0, 0, -1, 0], [0, 0, 0, 0], [0, 0, 0, 0], [1, 1, 0, -1]]) assert (scara_geo.T[-1] - T_spong).expand() == sympy.zeros(4) assert (scara_kin.J[-1] - J_spong).expand() == sympy.zeros(6, 4)
def condense_list_of_dicts(dicts,key): if not all([key in d for d in dicts]): raise ValueError('{key} not in every dict in list'.format(key=key)) keyvals = set([d[key] for d in dicts]) result = [] for val in keyvals: temp_dict = {} temp_dict[key] = val matching_dicts = [d for d in dicts if d[key] == val] all_keys = set(sympy.flatten([list(d.keys()) for d in matching_dicts])) for k in all_keys: if k != key: temp_dict[k] = set([d[k] for d in matching_dicts]) result.append(temp_dict) return result
def add_derivative(self, name, fname, wrt, flatten_wrt=False): # Test if we have only one wrt item if isinstance(wrt, (str, sympy.NDimArray)): wrt = (wrt,) out = self.default_function_output(fname) for wrt_array in wrt: if utils.isstr(wrt_array): wrt_array = self.variables[wrt_array] if flatten_wrt: wrt_array = sympy.flatten(wrt_array) out = sympy.derive_by_array(out, wrt_array) args = self.function_codegen_arguments(fname) deriv = function.SymbolicSubsFunction(args, out) setattr(self, name, deriv)
def sub_args(args, dummies_dict): if isinstance(args, string_types): return args elif isinstance(args, DeferredVector): return str(args) elif iterable(args): dummies = flatten([sub_args(a, dummies_dict) for a in args]) return ",".join(str(a) for a in dummies) else: # replace these with Dummy symbols if isinstance(args, (Function, Symbol, Derivative)): dummies = Dummy() dummies_dict.update({args : dummies}) return str(dummies) else: return str(args)
def TensorProduct(*input_vectors, **kwargs): if('coefficient' in kwargs and kwargs['coefficient']==0): return sympify(0) ## First, go through and make the data nice if(len(input_vectors)==0): # Since TensorProducts are multiplicative, the empty object # should be 1 (or whatever coefficient was passed, if any) return kwargs.get('coefficient', sympify(1)) if(len(input_vectors)==1 and isinstance(input_vectors[0], TensorProductFunction)) : vectors = list(input_vectors[0].vectors) coefficient = deepcopy(input_vectors[0].coefficient) symmetric = bool(input_vectors[0].symmetric) else: if(len(input_vectors)==1 and isinstance(input_vectors[0], list)): input_vectors = input_vectors[0] vectors = list(input_vectors) coefficient = deepcopy(kwargs.get('coefficient', 1)) symmetric = bool(kwargs.get('symmetric', True)) ## Now, make sure none of the input vectors are zero for v in vectors: if v==0: return sympify(0) ## Finally, create the object and set its data. Because of ## sympy's caching, tensor products with different data need to be ## created as classes with different names. So we just create a ## lighweight subclass with a unique name (the number at the end ## gets incremented every time we construct a tensor product). global _TensorProduct_count ThisTensorProductFunction = type('TensorProductFunction_'+str(_TensorProduct_count), (TensorProductFunction,), {}) _TensorProduct_count += 1 # print('About to construct a tensor with args ', # tuple( set( flatten( [v.args for v in vectors] ) ) ), # input_vectors, # kwargs, # vectors, # [v.args for v in vectors] ) TP = ThisTensorProductFunction( *tuple( set( flatten( [v.args for v in vectors] ) ) ) ) TP.vectors = vectors TP.coefficient = coefficient TP.symmetric = symmetric return TP
def test_symbols_each_char(): # XXX: Because of the way the warnings filters work, this will fail if it's # run more than once in the same session. See issue 2492. import warnings # each_char is deprecated and emits a warning. w = Symbol('w') x = Symbol('x') y = Symbol('y') z = Symbol('z') # First, test the warning warnings.filterwarnings("error") raises(SymPyDeprecationWarning, lambda: symbols('xyz', each_char=True)) raises(SymPyDeprecationWarning, lambda: symbols('xyz', each_char=False)) # now test the actual output warnings.filterwarnings("ignore") assert symbols(['wx', 'yz'], each_char=True) == [(w, x), (y, z)] assert all(w.is_Function for w in flatten( symbols(['wx', 'yz'], each_char=True, cls=Function))) assert symbols('xyz', each_char=True) == (x, y, z) assert symbols('x,', each_char=True) == (x,) assert symbols('x y z', each_char=True) == symbols( 'x,y,z', each_char=True) == (x, y, z) assert symbols('xyz', each_char=False) == Symbol('xyz') a, b = symbols('x y', each_char=False, real=True) assert a.is_real and b.is_real assert 'each_char' not in a.assumptions0 assert symbols('x0:0', each_char=False) == () assert symbols('x0:1', each_char=False) == (Symbol('x0'),) assert symbols( 'x0:3', each_char=False) == (Symbol('x0'), Symbol('x1'), Symbol('x2')) assert symbols('x:0', each_char=False) == () assert symbols('x:1', each_char=False) == (Symbol('x0'),) assert symbols( 'x:3', each_char=False) == (Symbol('x0'), Symbol('x1'), Symbol('x2')) assert symbols('x1:1', each_char=False) == () assert symbols('x1:2', each_char=False) == (Symbol('x1'),) assert symbols('x1:3', each_char=False) == (Symbol('x1'), Symbol('x2')) # Keep testing reasonably thread safe, so reset the warning warnings.filterwarnings("default", "The each_char option to symbols\(\) and var\(\) is " "deprecated. Separate symbol names by spaces or commas instead.")
def __new__(cls, *args, **kwargs): shape, flat_list = cls._handle_ndarray_creation_inputs(*args, **kwargs) self = object.__new__(cls) self._shape = shape self._rank = len(shape) self._loop_size = functools.reduce(lambda x,y: x*y, shape) if shape else 0 # Sparse array: if isinstance(flat_list, (dict, Dict)): self._sparse_array = dict(flat_list) return self self._sparse_array = {} for i, el in enumerate(flatten(flat_list)): if el != 0: self._sparse_array[i] = _sympify(el) return self
def test_symbols_each_char(): import warnings # each_char is deprecated and emits a warning. w = Symbol('w') x = Symbol('x') y = Symbol('y') z = Symbol('z') # First, test the warning (SymPyDeprecationWarning should already raises during tests) raises(SymPyDeprecationWarning, lambda: symbols('xyz', each_char=True)) raises(SymPyDeprecationWarning, lambda: symbols('xyz', each_char=False)) # now test the actual output warnings.simplefilter("ignore", SymPyDeprecationWarning) assert symbols(['wx', 'yz'], each_char=True) == [(w, x), (y, z)] assert all(w.is_Function for w in flatten( symbols(['wx', 'yz'], each_char=True, cls=Function))) assert symbols('xyz', each_char=True) == (x, y, z) assert symbols('x,', each_char=True) == (x,) assert symbols('x y z', each_char=True) == symbols( 'x,y,z', each_char=True) == (x, y, z) assert symbols('xyz', each_char=False) == Symbol('xyz') a, b = symbols('x y', each_char=False, real=True) assert a.is_real and b.is_real assert 'each_char' not in a.assumptions0 assert symbols('x0:0', each_char=False) == () assert symbols('x0:1', each_char=False) == (Symbol('x0'),) assert symbols( 'x0:3', each_char=False) == (Symbol('x0'), Symbol('x1'), Symbol('x2')) assert symbols('x:0', each_char=False) == () assert symbols('x:1', each_char=False) == (Symbol('x0'),) assert symbols( 'x:3', each_char=False) == (Symbol('x0'), Symbol('x1'), Symbol('x2')) assert symbols('x1:1', each_char=False) == () assert symbols('x1:2', each_char=False) == (Symbol('x1'),) assert symbols('x1:3', each_char=False) == (Symbol('x1'), Symbol('x2')) # Keep testing reasonably thread safe, so reset the warning warnings.simplefilter("error", SymPyDeprecationWarning)
def symbolic_coeffs_and_diffs(expr,u): ''' returns the coefficients for each term containing u or a derivative of u. Also returns the variables that derivatives of u are with respect to ''' # convert expr to a list of terms expr = expr.expand() expr = expr.as_ordered_terms() # throw out terms not containing u expr = [i for i in expr if i.has(u)] coeffs = [] diffs = [] for e in expr: # if the expression is a product then expand it into multipliers if e.is_Mul: e = sp.flatten(e.as_coeff_mul()) else: e = [sp.Integer(1),e] # find multipliers without the queried term without_u = [i for i in e if not i.has(u)] coeffs += [without_u] # find multipliers with the queried term with_u = [i for i in e if i.has(u)] if not (len(with_u) == 1): raise FormulationError( 'the term %s has multiple occurrences of %s' % (sp.prod(e),u)) base,diff = derivative_order(with_u[0]) if not (base == u): raise FormulationError( 'cannot express %s as a differential operation of %s' % (base,u)) diffs += diff, return coeffs,diffs
def _print_unpacking(self, lvalues, rvalue): """Generate argument unpacking code. This method is used when the input value is not interable, but can be indexed (see issue #14655). """ from sympy import flatten def flat_indexes(elems): n = 0 for el in elems: if iterable(el): for ndeep in flat_indexes(el): yield (n,) + ndeep else: yield (n,) n += 1 indexed = ', '.join('{}[{}]'.format(rvalue, ']['.join(map(str, ind))) for ind in flat_indexes(lvalues)) return ['[{}] = [{}]'.format(', '.join(flatten(lvalues)), indexed)]
def __new__(cls, *args, **kwargs): shape, flat_list = cls._handle_ndarray_creation_inputs(*args, **kwargs) shape = Tuple(*map(_sympify, shape)) loop_size = functools.reduce(lambda x,y: x*y, shape) if shape else 0 # Sparse array: if isinstance(flat_list, (dict, Dict)): sparse_array = Dict(flat_list) else: sparse_array = {} for i, el in enumerate(flatten(flat_list)): if el != 0: sparse_array[i] = _sympify(el) sparse_array = Dict(sparse_array) self = Basic.__new__(cls, sparse_array, shape, **kwargs) self._shape = shape self._rank = len(shape) self._loop_size = loop_size self._sparse_array = sparse_array return self
def lambdastr(args, expr, printer=None, dummify=None): """ Returns a string that can be evaluated to a lambda function. Examples ======== >>> from sympy.abc import x, y, z >>> from sympy.utilities.lambdify import lambdastr >>> lambdastr(x, x**2) 'lambda x: (x**2)' >>> lambdastr((x,y,z), [z,y,x]) 'lambda x,y,z: ([z, y, x])' Although tuples may not appear as arguments to lambda in Python 3, lambdastr will create a lambda function that will unpack the original arguments so that nested arguments can be handled: >>> lambdastr((x, (y, z)), x + y) 'lambda _0,_1: (lambda x,y,z: (x + y))(_0,_1[0],_1[1])' """ # Transforming everything to strings. from sympy.matrices import DeferredVector from sympy import Dummy, sympify, Symbol, Function, flatten, Derivative, Basic if printer is not None: if inspect.isfunction(printer): lambdarepr = printer else: if inspect.isclass(printer): lambdarepr = lambda expr: printer().doprint(expr) else: lambdarepr = lambda expr: printer.doprint(expr) else: #XXX: This has to be done here because of circular imports from sympy.printing.lambdarepr import lambdarepr def sub_args(args, dummies_dict): if isinstance(args, string_types): return args elif isinstance(args, DeferredVector): return str(args) elif iterable(args): dummies = flatten([sub_args(a, dummies_dict) for a in args]) return ",".join(str(a) for a in dummies) else: # replace these with Dummy symbols if isinstance(args, (Function, Symbol, Derivative)): dummies = Dummy() dummies_dict.update({args : dummies}) return str(dummies) else: return str(args) def sub_expr(expr, dummies_dict): try: expr = sympify(expr).xreplace(dummies_dict) except Exception: if isinstance(expr, DeferredVector): pass elif isinstance(expr, dict): k = [sub_expr(sympify(a), dummies_dict) for a in expr.keys()] v = [sub_expr(sympify(a), dummies_dict) for a in expr.values()] expr = dict(zip(k, v)) elif isinstance(expr, tuple): expr = tuple(sub_expr(sympify(a), dummies_dict) for a in expr) elif isinstance(expr, list): expr = [sub_expr(sympify(a), dummies_dict) for a in expr] return expr # Transform args def isiter(l): return iterable(l, exclude=(str, DeferredVector, NotIterable)) def flat_indexes(iterable): n = 0 for el in iterable: if isiter(el): for ndeep in flat_indexes(el): yield (n,) + ndeep else: yield (n,) n += 1 if dummify is None: dummify = any(isinstance(a, Basic) and a.atoms(Function, Derivative) for a in ( args if isiter(args) else [args])) if isiter(args) and any(isiter(i) for i in args): dum_args = [str(Dummy(str(i))) for i in range(len(args))] indexed_args = ','.join([ dum_args[ind[0]] + ''.join(["[%s]" % k for k in ind[1:]]) for ind in flat_indexes(args)]) lstr = lambdastr(flatten(args), expr, printer=printer, dummify=dummify) return 'lambda %s: (%s)(%s)' % (','.join(dum_args), lstr, indexed_args) dummies_dict = {} if dummify: args = sub_args(args, dummies_dict) else: if isinstance(args, string_types): pass elif iterable(args, exclude=DeferredVector): args = ",".join(str(a) for a in args) # Transform expr if dummify: if isinstance(expr, string_types): pass else: expr = sub_expr(expr, dummies_dict) expr = lambdarepr(expr) return "lambda %s: (%s)" % (args, expr)
def __init__(self, model, tspan=None, initials=None, param_values=None, verbose=False, **kwargs): super(ScipyOdeSimulator, self).__init__(model, tspan=tspan, initials=initials, param_values=param_values, verbose=verbose, **kwargs) # We'll need to know if we're using the Jacobian when we get to run() self._use_analytic_jacobian = kwargs.pop('use_analytic_jacobian', False) self.cleanup = kwargs.pop('cleanup', True) integrator = kwargs.pop('integrator', 'vode') compiler_mode = kwargs.pop('compiler', None) integrator_options = kwargs.pop('integrator_options', {}) cython_directives = kwargs.pop('cython_directives', self.default_cython_directives) if kwargs: raise ValueError('Unknown keyword argument(s): {}'.format( ', '.join(kwargs.keys()) )) # Generate the equations for the model pysb.bng.generate_equations(self._model, self.cleanup, self.verbose) # ODE RHS ----------------------------------------------- self._eqn_subs = {e: e.expand_expr(expand_observables=True) for e in self._model.expressions} ode_mat = sympy.Matrix(self.model.odes).subs(self._eqn_subs) if compiler_mode is None: self._compiler = self._autoselect_compiler() if self._compiler == 'python': self._logger.warning( "This system of ODEs will be evaluated in pure Python. " "This may be slow for large models. We recommend " "installing a package for compiling the ODEs to C code: " "'weave' (recommended for Python 2) or " "'cython' (recommended for Python 3). This warning can " "be suppressed by specifying compiler='python'.") self._logger.debug('Equation mode set to "%s"' % self._compiler) else: self._compiler = compiler_mode extra_compile_args = [] # Inhibit weave C compiler warnings unless log level <= EXTENDED_DEBUG. # Note that since the output goes straight to stderr rather than via the # logging system, the threshold must be lower than DEBUG or else the # Nose logcapture plugin will cause the warnings to be shown and tests # will fail due to unexpected output. if not self._logger.isEnabledFor(EXTENDED_DEBUG): extra_compile_args.append('-w') # Use lambdarepr (Python code) with Cython, otherwise use C code eqn_repr = lambdarepr if self._compiler == 'cython' else sympy.ccode if self._compiler in ('weave', 'cython'): # Prepare the string representations of the RHS equations code_eqs = '\n'.join(['ydot[%d] = %s;' % (i, eqn_repr(o)) for i, o in enumerate(ode_mat)]) code_eqs = str(self._eqn_substitutions(code_eqs)) # Allocate ydot here, once. ydot = np.zeros(len(self.model.species)) if self._compiler == 'cython': if not Cython: raise ImportError('Cython library is not installed') def rhs(t, y, p): # note that the evaluated code sets ydot as a side effect Cython.inline( code_eqs, quiet=True, cython_compiler_directives=cython_directives) return ydot with _set_cflags_no_warnings(self._logger): rhs(0.0, self.initials[0], self.param_values[0]) else: # Weave if not weave_inline: raise ImportError('Weave library is not installed') for arr_name in ('ydot', 'y', 'p'): macro = arr_name.upper() + '1' code_eqs = re.sub(r'\b%s\[(\d+)\]' % arr_name, '%s(\\1)' % macro, code_eqs) def rhs(t, y, p): # note that the evaluated code sets ydot as a side effect weave_inline(code_eqs, ['ydot', 't', 'y', 'p'], extra_compile_args=extra_compile_args) return ydot # Call rhs once just to trigger the weave C compilation step # while asserting control over distutils logging. with self._patch_distutils_logging: rhs(0.0, self.initials[0], self.param_values[0]) elif self._compiler in ('theano', 'python'): self._symbols = sympy.symbols(','.join('__s%d' % sp_id for sp_id in range(len( self.model.species))) + ',') + tuple(model.parameters) if self._compiler == 'theano': if theano is None: raise ImportError('Theano library is not installed') code_eqs_py = theano_function( self._symbols, [o if not o.is_zero else theano.tensor.zeros(1) for o in ode_mat], on_unused_input='ignore' ) else: code_eqs_py = sympy.lambdify(self._symbols, sympy.flatten(ode_mat)) def rhs(t, y, p): return code_eqs_py(*itertools.chain(y, p)) else: raise ValueError('Unknown compiler_mode: %s' % self._compiler) # JACOBIAN ----------------------------------------------- # We'll keep the code for putting together the matrix in Sympy # in case we want to do manipulations of the matrix later (e.g., to # put together the sensitivity matrix) jac_fn = None if self._use_analytic_jacobian: species_symbols = [sympy.Symbol('__s%d' % i) for i in range(len(self._model.species))] jac_matrix = ode_mat.jacobian(species_symbols) if self._compiler == 'theano': jac_eqs_py = theano_function( self._symbols, [j if not j.is_zero else theano.tensor.zeros(1) for j in jac_matrix], on_unused_input='ignore' ) def jacobian(t, y, p): jacmat = np.asarray(jac_eqs_py(*itertools.chain(y, p))) jacmat.shape = (len(self.model.odes), len(self.model.species)) return jacmat elif self._compiler in ('weave', 'cython'): # Prepare the stringified Jacobian equations. jac_eqs_list = [] for i in range(jac_matrix.shape[0]): for j in range(jac_matrix.shape[1]): entry = jac_matrix[i, j] # Skip zero entries in the Jacobian if entry == 0: continue jac_eq_str = 'jac[%d, %d] = %s;' % ( i, j, eqn_repr(entry)) jac_eqs_list.append(jac_eq_str) jac_eqs = str(self._eqn_substitutions('\n'.join(jac_eqs_list))) # Allocate jac array here, once, and initialize to zeros. jac = np.zeros( (len(self._model.odes), len(self._model.species))) if self._compiler == 'weave': # Substitute array refs with calls to the JAC1 macro jac_eqs = re.sub(r'\bjac\[(\d+), (\d+)\]', r'JAC2(\1, \2)', jac_eqs) # Substitute calls to the Y1 and P1 macros for arr_name in ('y', 'p'): macro = arr_name.upper() + '1' jac_eqs = re.sub(r'\b%s\[(\d+)\]' % arr_name, '%s(\\1)' % macro, jac_eqs) def jacobian(t, y, p): weave_inline(jac_eqs, ['jac', 't', 'y', 'p'], extra_compile_args=extra_compile_args) return jac # Manage distutils logging, as above for rhs. with self._patch_distutils_logging: jacobian(0.0, self.initials[0], self.param_values[0]) else: def jacobian(t, y, p): Cython.inline( jac_eqs, quiet=True, cython_compiler_directives=cython_directives) return jac with _set_cflags_no_warnings(self._logger): jacobian(0.0, self.initials[0], self.param_values[0]) else: jac_eqs_py = sympy.lambdify(self._symbols, jac_matrix, "numpy") def jacobian(t, y, p): return jac_eqs_py(*itertools.chain(y, p)) jac_fn = jacobian # build integrator options list from our defaults and any kwargs # passed to this function options = {} if self.default_integrator_options.get(integrator): options.update( self.default_integrator_options[integrator]) # default options options.update(integrator_options) # overwrite # defaults self.opts = options # Integrator if integrator == 'lsoda': # lsoda is accessed via scipy.integrate.odeint which, # as a function, # requires that we pass its args at the point of call. Thus we need # to stash stuff like the rhs and jacobian functions in self so we # can pass them in later. self.integrator = integrator # lsoda's rhs and jacobian function arguments are in a different # order to other integrators, so we define these shims that swizzle # the argument order appropriately. self.func = lambda t, y, p: rhs(y, t, p) if jac_fn is None: self.jac_fn = None else: self.jac_fn = lambda t, y, p: jac_fn(y, t, p) else: # The scipy.integrate.ode integrators on the other hand are object # oriented and hold the functions and such internally. Once we set # up the integrator object we only need to retain a reference to it # and can forget about the other bits. self.integrator = scipy.integrate.ode(rhs, jac=jac_fn) with warnings.catch_warnings(): warnings.filterwarnings('error', 'No integrator name match') self.integrator.set_integrator(integrator, **options)