def setUp(self): self.t = tensor.Tensor('t') self.tf = tensor.TensorFunction('tf') self.a = sympy.Dummy('a') self.b = sympy.Dummy('b') self.x, self.y, self.z = sympy.symbols('x,y,z') self.f = sympy.Function('f')
def symbol(self, name): if name in self.symbols: return self.symbols[name] prefix = ( not self.prefix_exclude and name in self.prefix_include or not self.prefix_include and name not in self.prefix_exclude ) and self.prefix or '' suffix = ( not self.suffix_exclude and name in self.suffix_include or not self.suffix_include and name not in self.suffix_exclude ) and self.suffix or '' if isinstance(name, integer_types): # all integers are currently treated as dummy variables fullname = prefix + str(name) + suffix symbol = sympy.Dummy(fullname) else: fullname = prefix + name + suffix if self.dummies is True or name in self.dummies: symbol = sympy.Dummy(fullname) else: symbol = sympy.Symbol(fullname) self.symbols[name] = symbol self.symbolnames[symbol] = name # XXX needed? return symbol
def power_rule(derivative): expr, symbol = derivative.expr, derivative.symbol base, exp = expr.as_base_exp() if not base.has(symbol): if isinstance(exp, sympy.Symbol): return ExpRule(expr, base, expr, symbol) else: u = sympy.Dummy() f = base ** u return ChainRule( ExpRule(f, base, f, u), exp, u, diff_steps(exp, symbol), expr, symbol ) elif not exp.has(symbol): if isinstance(base, sympy.Symbol): return PowerRule(base, exp, expr, symbol) else: u = sympy.Dummy() f = u ** exp return ChainRule( PowerRule(u, exp, f, u), base, u, diff_steps(base, symbol), expr, symbol ) else: return DontKnowRule(expr, symbol)
def functional_derivative(functional, v): r"""Computes functional derivative of functional with respect to v using Euler-Lagrange equation .. math :: \frac{\delta F}{\delta v} = \frac{\partial F}{\partial v} - \nabla \cdot \frac{\partial F}{\partial \nabla v} - assumes that gradients are represented by Diff() node - Diff(Diff(r)) represents the divergence of r - the constants parameter is a list with symbols not affected by the derivative. This is used for simplification of the derivative terms. """ diffs = functional.atoms(Diff) bulk_substitutions = {d: sp.Dummy() for d in diffs} bulk_substitutions_inverse = {v: k for k, v in bulk_substitutions.items()} non_diff_part = functional.subs(bulk_substitutions) partial_f_partial_v = sp.diff(non_diff_part, v).subs(bulk_substitutions_inverse) gradient_part = 0 for diff_obj in diffs: if diff_obj.args[0] != v: continue dummy = sp.Dummy() partial_f_partial_grad_v = functional.subs(diff_obj, dummy).diff(dummy).subs( dummy, diff_obj) gradient_part += Diff(partial_f_partial_grad_v, target=diff_obj.target, superscript=diff_obj.superscript) result = partial_f_partial_v - gradient_part return result
def test_imports(): from eqpy.dummies import x1, y1 as why1 assert x1 is not sympy.Dummy('x1') assert why1 is not sympy.Dummy('y1') assert eqpy.dummies.x1 is not x1 assert isinstance(x1, sympy.Dummy) assert isinstance(why1, sympy.Dummy) from eqpy.dummies import y1 assert y1 is not why1
def maxwell_construction(eos, tolerance=1e-4): """Numerical Maxwell construction to find ρ_gas and ρ_liquid for a given equation of state. Args: eos: equation of state, that has only one symbol (the density) in it tolerance: internally a bisection algorithm is used to find pressure such that areas below and above are equal. The tolerance parameter refers to the pressure. If the integral is smaller than the tolerance the bisection algorithm is stopped. Returns: (gas density, liquid density) """ dofs = eos.atoms(sp.Symbol) assert len(dofs) == 1 density = dofs.pop() v = sp.Dummy() eos = eos.subs(density, 1 / v) # pre-compute integral once - then it is evaluated in every bisection iteration symbolic_offset = sp.Dummy(real=True) integral = sp.integrate(sp.nsimplify(eos + symbolic_offset), v) upper_bound, lower_bound = sp.Dummy(real=True), sp.Dummy(real=True) symbolic_deviation = integral.subs(v, upper_bound) - integral.subs(v, lower_bound) get_deviation = sp.lambdify((lower_bound, upper_bound, symbolic_offset), symbolic_deviation) critical_points = sp.solve(sp.diff(eos, v)) critical_points = [remove_small_floats(e, 1e-14) for e in critical_points] critical_points = [e for e in critical_points if e.is_real] *_, v_min, v_max = critical_points assert sp.diff(eos, v, v).subs(v, v_min) > 0 assert sp.diff(eos, v, v).subs(v, v_max) < 0 assert sp.limit(eos, v, sp.oo) == 0 # shift has to be negative, since equation of state approaches zero for v -> oo shift_min, shift_max = -eos.subs(v, v_max), 0 c = (shift_max + shift_min) / 2 deviation = tolerance * 2 while abs(deviation) > tolerance: solve_res = sp.solve(eos + c) solve_res = [remove_small_floats(e, 1e-14) for e in solve_res] zeros = sorted([e for e in solve_res if e.is_real]) integral_bounds = (zeros[-3], zeros[-1]) deviation = get_deviation(float(integral_bounds[0]), float(integral_bounds[1]), float(c)) if deviation > 0: shift_max = c else: shift_min = c c = (shift_max + shift_min) / 2 return 1 / integral_bounds[1], 1 / integral_bounds[0]
def substitution_rule(integral): integrand, symbol = integral u_var = sympy.Dummy("u") substitutions = find_substitutions(integrand, symbol, u_var) if substitutions: ways = [] for u_func, c, substituted in substitutions: subrule = integral_steps(substituted / c, u_var) if contains_dont_know(subrule): continue if sympy.simplify(c - 1) != 0: subrule = ConstantTimesRule(c, substituted / c, subrule, substituted, symbol) ways.append(URule(u_var, u_func, c, subrule, integrand, symbol)) if len(ways) > 1: return AlternativeRule(ways, integrand, symbol) elif ways: return ways[0] elif integrand.has(sympy.exp): u_func = sympy.exp(symbol) c = 1 substituted = integrand / u_func.diff(symbol) substituted = substituted.subs(u_func, u_var) if symbol not in substituted.free_symbols: return URule(u_var, u_func, c, integral_steps(substituted, u_var), integrand, symbol)
def __init__(self, dims): """Constructs a shape whose i-th dim is dims[i]. Each dim can be one of the following types: integer: represents the dimension is a known and fixed. string: represents the dimension is an unknown and a sympy dummy symbol is used to represent it. Also note that contents of strings only matter for logging/printing. Even if the same string is given on multiple dimensions, it doesn't mean that they are the same. sympy expression: represents a dimension which possibly depends on dimensions of other shapes. Args: dims: A list of either integer, string or sympy.Symbol. """ self._shape = [] for x in dims: assert x is not None, str(dims) if isinstance(x, six.string_types): # NOTE: Dummy(x) creates a unique symbol. I.e., the value of x has no # meaning except for printing, etc. self._shape.append(sympy.Dummy(x, integer=True)) else: # Converts x to a sympy type. E.g., int to sympy.Integer. self._shape.append(sympy.sympify(x)) self._size = sympy.prod(self._shape)
def complete_the_squares_in_exp(expr: sp.Expr, symbols_to_complete: Sequence[sp.Symbol]): """Completes squares in arguments of exponential which makes them simpler to integrate. Very useful for integrating Maxwell-Boltzmann equilibria and its moment generating function """ dummies = [sp.Dummy() for _ in symbols_to_complete] def visit(term): if term.func == sp.exp: exp_arg = term.args[0] for symbol_to_complete, dummy in zip(symbols_to_complete, dummies): exp_arg, substitution = complete_the_square( exp_arg, symbol_to_complete, dummy) return sp.exp(sp.expand(exp_arg)) else: param_list = [visit(a) for a in term.args] if not param_list: return term else: return term.func(*param_list) result = visit(expr) for s, d in zip(symbols_to_complete, dummies): result = result.subs(d, s) return result
def check_analytic(self, w=None, silent=False): if w is None: f = self.w_sympy elif type(w) == str: f = self.w_sympy = self.evaluate(w) else: f = self.w_sympy reps = defaultdict(lambda: sym.Dummy(real=True)) f = f.replace(lambda x: x.is_Float, lambda x: reps[x]) u = sym.re(f) v = sym.im(f) cond1 = sym.diff(u, x) - sym.diff(v, y) cond2 = sym.diff(u, y) + sym.diff(v, x) if sym.simplify(cond1) == 0 and sym.simplify(cond2) == 0: if silent is False: print('The function is conformal, angles are preserved :)') out = True else: if silent is False: print( 'The function is not conformal, angles are not preserved ...' ) out = False return out
def generate_position_vector_func(In_frame, origin, point, dynamic_variables): ''' retuns the position of the point on reference_frame in inertial reference frame (In_frame) as a fucntion of dynamic_variables ''' # finding the vector of point in respect to In_frame point_vector = point.pos_from(origin) point_vector_x = point_vector.dot(In_frame.x) point_vector_y = point_vector.dot(In_frame.y) # substituting dummy variables instead of dynamic_variables # couse there are funcitons of times and they couldn't be unpacked # like a normal sm.symbols as args for the funtions dummy_symbols = [sm.Dummy() for i in dynamic_variables] dummy_dict = dict(zip(dynamic_variables, dummy_symbols)) point_vector_dummy = [ point_vector_x.subs(dummy_dict), point_vector_y.subs(dummy_dict) ] # lamdify the point vector point_vector_func = [ sm.lambdify(dummy_symbols, point_vector_component, modules='numpy') for point_vector_component in point_vector_dummy ] return point_vector_func
def trig_substitution_rule(integral): integrand, symbol = integral A = sympy.Wild('a', exclude=[0, symbol]) B = sympy.Wild('b', exclude=[0, symbol]) theta = sympy.Dummy("theta") target_pattern = A + B*symbol**2 matches = integrand.find(target_pattern) for expr in matches: match = expr.match(target_pattern) a = match.get(A, ZERO) b = match.get(B, ZERO) a_positive = ((a.is_number and a > 0) or a.is_positive) b_positive = ((b.is_number and b > 0) or b.is_positive) a_negative = ((a.is_number and a < 0) or a.is_negative) b_negative = ((b.is_number and b < 0) or b.is_negative) x_func = None if a_positive and b_positive: # a**2 + b*x**2. Assume sec(theta) > 0, -pi/2 < theta < pi/2 x_func = (sympy.sqrt(a)/sympy.sqrt(b)) * sympy.tan(theta) # Do not restrict the domain: tan(theta) takes on any real # value on the interval -pi/2 < theta < pi/2 so x takes on # any value restriction = True elif a_positive and b_negative: # a**2 - b*x**2. Assume cos(theta) > 0, -pi/2 < theta < pi/2 constant = sympy.sqrt(a)/sympy.sqrt(-b) x_func = constant * sympy.sin(theta) restriction = sympy.And(symbol > -constant, symbol < constant) elif a_negative and b_positive: # b*x**2 - a**2. Assume sin(theta) > 0, 0 < theta < pi constant = sympy.sqrt(-a)/sympy.sqrt(b) x_func = constant * sympy.sec(theta) restriction = sympy.And(symbol > -constant, symbol < constant) if x_func: # Manually simplify sqrt(trig(theta)**2) to trig(theta) # Valid due to assumed domain restriction substitutions = {} for f in [sympy.sin, sympy.cos, sympy.tan, sympy.sec, sympy.csc, sympy.cot]: substitutions[sympy.sqrt(f(theta)**2)] = f(theta) substitutions[sympy.sqrt(f(theta)**(-2))] = 1/f(theta) replaced = integrand.subs(symbol, x_func).trigsimp() replaced = replaced.subs(substitutions) if not replaced.has(symbol): replaced *= manual_diff(x_func, theta) replaced = replaced.trigsimp() secants = replaced.find(1/sympy.cos(theta)) if secants: replaced = replaced.xreplace({ 1/sympy.cos(theta): sympy.sec(theta) }) substep = integral_steps(replaced, theta) if not contains_dont_know(substep): return TrigSubstitutionRule( theta, x_func, replaced, substep, restriction, integrand, symbol)
def test_renameDummyIndex(self): A=tensor.Tensor('A') B=tensor.Tensor('B') a=sympy.Dummy('a') b,c,d=sympy.symbols('b,c,d') exp = A(a,b,c)*B(b,c) - A(a,c,d)*B(c,d) self.assertEqual(renameDummyIndex(exp),0)
def __init__(self, dim, time_step=TypedSymbol("time_step", np.uint32), offsets=(0, 0, 0), keys=None): if keys is None: keys = (0, ) * self._num_keys if len(keys) != self._num_keys: raise ValueError("Provided {} keys but need {}".format( len(keys), self._num_keys)) if len(offsets) != 3: raise ValueError("Provided {} offsets but need {}".format( len(offsets), 3)) self.result_symbols = tuple( TypedSymbol(sp.Dummy().name, self._data_type) for _ in range(self._num_vars)) symbols_read = [s for s in keys if isinstance(s, sp.Symbol)] super().__init__("", symbols_read=symbols_read, symbols_defined=self.result_symbols) self._time_step = time_step self._offsets = offsets self.headers = ['"{}_rand.h"'.format(self._name)] self.keys = tuple(keys) self._args = sp.sympify((dim, time_step, keys)) self._dim = dim
def callable_matrices(dynamic, eom, consts): """Take the equations of motion and make the mass matrix and forcing vector callable so we can simulate the system. Parameters ---------- Returns ------- """ # dummy symbols used for dynamamic variables dyn_symbols = dynamic['q'] + dynamic['u'] dummy_symbols = [sym.Dummy() for i in dyn_symbols] dummy_dict = dict(zip(dyn_symbols, dummy_symbols)) # substitute dummy symbols into mass matrix and forcing vector kd_dict = eom['kane'].kindiffdict() # solved kinematical differential equations F = eom['forcing'].subs(kd_dict).subs(dummy_dict) # substitute into the forcing vector M = eom['mass'].subs(kd_dict).subs(dummy_dict) # substitute into the mass matrix # callable matrices F_func = sym.lambdify(consts['names'] + dummy_symbols, F) M_func = sym.lambdify(consts['names'] + dummy_symbols, M) # partially evaluate matrices to run faster (maybe 15% or so) ffunc = functools.partial(F_func, *consts['vals']) mfunc = functools.partial(M_func, *consts['vals']) return F_func, M_func, ffunc, mfunc, dummy_dict
def test_attributes(): x2 = eqpy.dummies.x2 assert x2 is not sympy.Dummy('x2') assert raises(AttributeError, lambda: eqpy.dummies.__dunder_should_fail__) assert isinstance(x2, sympy.Dummy) ex2 = eqpy.dummies.x2 assert x2 is not ex2
def make_inverse_trig(RuleClass, base_exp, a, sign_a, b, sign_b): u_var = sympy.Dummy("u") current_base = base current_symbol = symbol constant = u_func = u_constant = substep = None factored = integrand if a != 1: constant = a**base_exp current_base = sign_a + sign_b * (b / a) * current_symbol**2 factored = current_base**base_exp if (b / a) != 1: u_func = sympy.sqrt(b / a) * symbol u_constant = sympy.sqrt(a / b) current_symbol = u_var current_base = sign_a + sign_b * current_symbol**2 substep = RuleClass(current_base**base_exp, current_symbol) if u_func is not None: if u_constant != 1 and substep is not None: substep = ConstantTimesRule( u_constant, current_base**base_exp, substep, u_constant * current_base**base_exp, symbol) substep = URule(u_var, u_func, u_constant, substep, factored, symbol) if constant is not None and substep is not None: substep = ConstantTimesRule(constant, factored, substep, integrand, symbol) return substep
def apply(self, m, b, evaluation): 'LinearSolve[m_, b_]' matrix = matrix_data(m) if matrix is None: return if not b.has_form('List', None): return if len(b.leaves) != len(matrix): return evaluation.message('LinearSolve', 'lslc') system = [mm + [v] for mm, v in zip(matrix, b.leaves)] system = to_sympy_matrix(system) if system is None: return syms = [ sympy.Dummy('LinearSolve_var%d' % k) for k in range(system.cols - 1) ] sol = sympy.solve_linear_system(system, *syms) if sol: # substitute 0 for variables that are not in result dictionary free_vars = dict( (sym, sympy.Integer(0)) for sym in syms if sym not in sol) sol.update(free_vars) sol = [(sol[sym] if sym in free_vars else sol[sym].subs(free_vars)) for sym in syms] return from_sympy(sol) else: return evaluation.message('LinearSolve', 'nosol')
def root_mul_rule(integral): integrand, symbol = integral a = sympy.Wild('a', exclude=[symbol]) b = sympy.Wild('b', exclude=[symbol]) c = sympy.Wild('c') match = integrand.match(sympy.sqrt(a * symbol + b) * c) if not match: return a, b, c = match[a], match[b], match[c] d = sympy.Wild('d', exclude=[symbol]) e = sympy.Wild('e', exclude=[symbol]) f = sympy.Wild('f') recursion_test = c.match(sympy.sqrt(d * symbol + e) * f) if recursion_test: return u = sympy.Dummy('u') u_func = sympy.sqrt(a * symbol + b) integrand = integrand.subs(u_func, u) integrand = integrand.subs(symbol, (u**2 - b) / a) integrand = integrand * 2 * u / a next_step = integral_steps(integrand, u) if next_step: return URule(u, u_func, None, next_step, integrand, symbol)
def makeExponentialFuncArgumentSquares(expr, variablesToCompleteSquares): """Completes squares in arguments of exponential which makes them simpler to integrate Very useful for integrating Maxwell-Boltzmann and its moment generating function""" expr = sp.simplify(expr) dim = len(variablesToCompleteSquares) dummies = [sp.Dummy() for i in range(dim)] def visit(term): if term.func == sp.exp: expArg = term.args[0] for i in range(dim): expArg, substitution = completeTheSquare( expArg, variablesToCompleteSquares[i], dummies[i]) return sp.exp(sp.expand(expArg)) else: paramList = [visit(a) for a in term.args] if not paramList: return term else: return term.func(*paramList) result = visit(expr) for i in range(dim): result = result.subs(dummies[i], variablesToCompleteSquares[i]) return result
def _baseobjective_from_callable(self, func, objective_type=MinimizeModel): """ symfit works with BaseObjective subclasses internally. If a custom objective is provided, we wrap it into a BaseObjective, MinimizeModel by default. :param func: Callable. If already an instance of BaseObjective, it is returned immediately. If not, it is turned into a BaseObjective of type ``objective_type``. :param objective_type: :return: """ if isinstance(func, BaseObjective) or ( hasattr(func, '__self__') and isinstance(func.__self__, BaseObjective)): # The latter condition is added to make sure .eval_jacobian methods # are still considered correct, and not doubly wrapped. return func else: if isinstance(func, BaseModel): model = func else: # Minimize the provided custom objective instead. We therefore # wrap it into a CallableNumericalModel, thats what they are for y = sympy.Dummy() model = CallableNumericalModel( {y: func}, connectivity_mapping={y: set(self.parameters)}) return objective_type(model, data={})
def compute_ab(f): c = sp.Dummy(positive=True) sqrt_f = sp.sqrt(f(c)) max_sqrt_f = max(sqrt_f.subs(c, 0), sqrt_f.subs(c, sp.Rational(1, 2)), sqrt_f.subs(c, 1)) sqrt_int = sp.integrate(sqrt_f, (c, 0, 1)) return max_sqrt_f / sqrt_int, 1 / (2 * max_sqrt_f * sqrt_int)
def _parts_rule(integrand, symbol): # LIATE rule: # log, inverse trig, algebraic (polynomial), trigonometric, exponential def pull_out_polys(integrand): integrand = integrand.together() polys = [arg for arg in integrand.args if arg.is_polynomial(symbol)] if polys: u = sympy.Mul(*polys) dv = integrand / u return u, dv def pull_out_u(*functions): def pull_out_u_rl(integrand): if any([integrand.has(f) for f in functions]): args = [ arg for arg in integrand.args if any( isinstance(arg, cls) for cls in functions) ] if args: u = reduce(lambda a, b: a * b, args) dv = integrand / u return u, dv return pull_out_u_rl liate_rules = [ pull_out_u(sympy.log), pull_out_u(sympy.atan), pull_out_polys, pull_out_u(sympy.sin, sympy.cos), pull_out_u(sympy.exp) ] dummy = sympy.Dummy("temporary") # we can integrate log(x) and atan(x) by setting dv = 1 if isinstance(integrand, sympy.log) or isinstance(integrand, sympy.atan): integrand = dummy * integrand for index, rule in enumerate(liate_rules): result = rule(integrand) if result: u, dv = result # Don't pick u to be a constant if possible if symbol not in u.free_symbols and not u.has(dummy): return u = u.subs(dummy, 1) dv = dv.subs(dummy, 1) for rule in liate_rules[index + 1:]: r = rule(integrand) # make sure dv is amenable to integration if r and r[0].subs(dummy, 1) == dv: du = u.diff(symbol) v_step = integral_steps(dv, symbol) v = _manualintegrate(v_step) return u, dv, v, du, v_step
def substitution_rule(integral): integrand, symbol = integral u_var = sympy.Dummy("u") substitutions = find_substitutions(integrand, symbol, u_var) if substitutions: ways = [] for u_func, c, substituted in substitutions: subrule = integral_steps(substituted, u_var) if contains_dont_know(subrule): continue if sympy.simplify(c - 1) != 0: _, denom = c.as_numer_denom() if subrule: subrule = ConstantTimesRule(c, substituted, subrule, substituted, u_var) if denom.free_symbols: piecewise = [] could_be_zero = [] if isinstance(denom, sympy.Mul): could_be_zero = denom.args else: could_be_zero.append(denom) for expr in could_be_zero: if not fuzzy_not(expr.is_zero): substep = integral_steps(integrand.subs(expr, 0), symbol) if substep: piecewise.append(( substep, sympy.Eq(expr, 0) )) piecewise.append((subrule, True)) subrule = PiecewiseRule(piecewise, substituted, symbol) ways.append(URule(u_var, u_func, c, subrule, integrand, symbol)) if len(ways) > 1: return AlternativeRule(ways, integrand, symbol) elif ways: return ways[0] elif integrand.has(sympy.exp): u_func = sympy.exp(symbol) c = 1 substituted = integrand / u_func.diff(symbol) substituted = substituted.subs(u_func, u_var) if symbol not in substituted.free_symbols: return URule(u_var, u_func, c, integral_steps(substituted, u_var), integrand, symbol)
def nc_coeffs(poly, var, max_deg=10, order='increasing'): """Returns a list of the coeffs w.r.t. var (expecting a monovariate polynomial) sympy.Poly can not handle non-commutative variables. This function mitigates that problem. :param poly: :param var: :param max_deg: maximum degree to look for :param order: increasing / decreasing :return: list of coeffs Caveat: This function expects all factors of `var` to be in one place. Terms like a*x*b*x**2 will not be handled correctly. """ # TODO: elegant way to find out the degree # TODO: use nc_degree (after performance-testing) # workarround: pass the maximum expected degree as kwarg if poly == 0: return [sp.sympify(0)] * (max_deg + 1) D0 = sp.Dummy('D0') poly = sp.sympify(poly).expand() + D0 # ensure class add if not isinstance(poly, sp.Add): msg = "Expected sp.Add. Got %s" % type(poly) raise TypeError(msg) res = [] # special case: 0-th power of var coeff = 0 for a in poly.args: if not a.has(var): coeff += a res.append(coeff.subs(D0, 0)) # special case: 1st power of var if max_deg >= 1: coeff = poly.diff(var).subs(var, 0) res.append(coeff) # powers > 1: for i in range(2, max_deg + 1): coeff = 0 for a in poly.args: if a.has(var**(i)): term = a.subs(var, 1) coeff += term res.append(coeff) if order == "decreasing": res.reverse() return res
def exp_rule(derivative): expr, symbol = derivative exp = expr.args[0] if isinstance(exp, sympy.Symbol): return ExpRule(expr, sympy.E, expr, symbol) else: u = sympy.Dummy() f = sympy.exp(u) return ChainRule(ExpRule(f, sympy.E, f, u), exp, u, diff_steps(exp, symbol), expr, symbol)
def __init__(self, value, error=0, symbol="x"): """ :param value: Değer :param error: Belirsizlik (default=0) :param symbol: Sembol (default="x") """ self.value = value self.error = abs(error) self.symbol = sp.Dummy(symbol) self.builder = Builder()
def cosine_law(lengths, angles, index): (c, a, b), gamma = lengths[index:] + lengths[:index], angles[index] x, find_angle = sympy.Dummy("x"), not bool(gamma) gamma, c = gamma or x, c or x equation = sympy.Eq(c ** 2, a ** 2 + b ** 2 - 2 * a * b * sympy.cos(gamma)) domain = sympy.Interval.open(0, sympy.pi if find_angle else sympy.oo) sol = [x for x in sympy.solve(equation) if x in domain] if not sol: raise ValueError( "The lengths and angles must satisfy the law of cosines" ) locals()["angles" if find_angle else "lengths"][index] = sol[0]
def log_rule(derivative): expr, symbol = derivative arg = expr.args[0] if len(expr.args) == 2: base = expr.args[1] else: base = sympy.E if isinstance(arg, sympy.Symbol): return LogRule(arg, base, expr, symbol) else: u = sympy.Dummy() return ChainRule(LogRule(u, base, sympy.log(u, base), u), arg, u, diff_steps(arg, symbol), expr, symbol)
def _construct_symbolic_lyapunov_solution_matrix(dim): numEquations = dim * (dim + 1) / 2 X = np.zeros((dim, dim)) counter = itertools.count() for k in xrange(dim): next_symbols = [ sympy.Dummy('x%d' % counter.next()) for i in range(dim - k) ] X = X + np.diag(next_symbols, k) if k > 0: X = X + np.diag(next_symbols, -k) return X