def expand(self, **hints): expr = self.args[0] condition = self._condition if not is_random(expr): return expr if isinstance(expr, Add): return Add.fromiter( Expectation(a, condition=condition).expand() for a in expr.args) expand_expr = _expand(expr) if isinstance(expand_expr, Add): return Add.fromiter( Expectation(a, condition=condition).expand() for a in expand_expr.args) elif isinstance(expr, Mul): rv = [] nonrv = [] for a in expr.args: if is_random(a): rv.append(a) else: nonrv.append(a) return Mul.fromiter(nonrv) * Expectation(Mul.fromiter(rv), condition=condition) return self
def cancel_terms(sym, x_term, coef): if coef.is_Add: for arg_c in coef.args: sym = cancel_terms(sym, x_term, arg_c) else: terms = Add.make_args(sym) return Add.fromiter(t for t in terms if t != x_term*coef)
def expand(self, **hints): arg1 = self.args[0] arg2 = self.args[1] condition = self._condition if arg1 == arg2: return Variance(arg1, condition).expand() if not is_random(arg1): return S.Zero if not is_random(arg2): return S.Zero arg1, arg2 = sorted([arg1, arg2], key=default_sort_key) if isinstance(arg1, RandomSymbol) and isinstance(arg2, RandomSymbol): return Covariance(arg1, arg2, condition) coeff_rv_list1 = self._expand_single_argument(arg1.expand()) coeff_rv_list2 = self._expand_single_argument(arg2.expand()) addends = [ a * b * Covariance(*sorted([r1, r2], key=default_sort_key), condition=condition) for (a, r1) in coeff_rv_list1 for (b, r2) in coeff_rv_list2 ] return Add.fromiter(addends)
def _eval_derivative(self, x): from sympy import Add terms = [] args = list(self.args) for i in range(len(args)): factors = args[:i] + [args[i].diff(x)] + args[i+1:] terms.append(hadamard_product(*factors)) return Add.fromiter(terms)
def _print_Add(self, expr): if len(expr.args) != 2: return "add({}, {})".format( self._print(expr.args[0]), self._print(Add.fromiter(expr.args[1:]))) return "add({}, {})".format( self._print(expr.args[0]), self._print(expr.args[1]), )
def _print_Add(self, expr): if len(expr.args) != 2: return "add({}, {})".format( self._print(expr.args[0]), self._print(Add.fromiter(expr.args[1:])) ) return "add({}, {})".format( self._print(expr.args[0]), self._print(expr.args[1]), )
def expand(self, **hints): expr = self.args[0] condition = self._condition if not is_random(expr): return expr if isinstance(expr, Add): return Add.fromiter( Expectation(a, condition=condition).expand() for a in expr.args) expand_expr = _expand(expr) if isinstance(expand_expr, Add): return Add.fromiter( Expectation(a, condition=condition).expand() for a in expand_expr.args) elif isinstance(expr, (Mul, MatMul)): rv = [] nonrv = [] postnon = [] for a in expr.args: if is_random(a): if rv: rv.extend(postnon) else: nonrv.extend(postnon) postnon = [] rv.append(a) elif a.is_Matrix: postnon.append(a) else: nonrv.append(a) # In order to avoid infinite-looping (MatMul may call .doit() again), # do not rebuild if len(nonrv) == 0: return self return Mul.fromiter(nonrv) * Expectation( Mul.fromiter(rv), condition=condition) * Mul.fromiter(postnon) return self
def dot(vect1, vect2): """ Returns dot product of two vectors. Examples ======== >>> from sympy.vector import CoordSys3D >>> from sympy.vector.vector import dot >>> R = CoordSys3D('R') >>> v1 = R.i + R.j + R.k >>> v2 = R.x * R.i + R.y * R.j + R.z * R.k >>> dot(v1, v2) R.x + R.y + R.z """ if isinstance(vect1, Add): return Add.fromiter(dot(i, vect2) for i in vect1.args) if isinstance(vect2, Add): return Add.fromiter(dot(vect1, i) for i in vect2.args) if isinstance(vect1, BaseVector) and isinstance(vect2, BaseVector): if vect1._sys == vect2._sys: return S.One if vect1 == vect2 else S.Zero from .functions import express try: v = express(vect2, vect1._sys) except ValueError: return Dot(vect1, vect2) else: return dot(vect1, v) if isinstance(vect1, VectorZero) or isinstance(vect2, VectorZero): return S.Zero if isinstance(vect1, VectorMul): v1, m1 = next(iter(vect1.components.items())) return m1 * dot(v1, vect2) if isinstance(vect2, VectorMul): v2, m2 = next(iter(vect2.components.items())) return m2 * dot(vect1, v2) return Dot(vect1, vect2)
def dot(vect1, vect2): """ Returns dot product of two vectors. Examples ======== >>> from sympy.vector import CoordSys3D >>> from sympy.vector.vector import dot >>> R = CoordSys3D('R') >>> v1 = R.i + R.j + R.k >>> v2 = R.x * R.i + R.y * R.j + R.z * R.k >>> dot(v1, v2) R.x + R.y + R.z """ if isinstance(vect1, Add): return Add.fromiter(dot(i, vect2) for i in vect1.args) if isinstance(vect2, Add): return Add.fromiter(dot(vect1, i) for i in vect2.args) if isinstance(vect1, BaseVector) and isinstance(vect2, BaseVector): if vect1._sys == vect2._sys: return S.One if vect1 == vect2 else S.Zero try: from .functions import express return dot(vect1, express(vect2, vect1._sys)) except: return Dot(vect1, vect2) if isinstance(vect1, VectorZero) or isinstance(vect2, VectorZero): return S.Zero if isinstance(vect1, VectorMul): v1, m1 = next(iter(vect1.components.items())) return m1*dot(v1, vect2) if isinstance(vect2, VectorMul): v2, m2 = next(iter(vect2.components.items())) return m2*dot(vect1, v2) return Dot(vect1, vect2)
def expand(self, **hints): arg1 = self.args[0] arg2 = self.args[1] condition = self._condition if arg1 == arg2: return VarianceMatrix(arg1, condition).expand() if not is_random(arg1) or not is_random(arg2): return ZeroMatrix(*self.shape) if isinstance(arg1, RandomSymbol) and isinstance(arg2, RandomSymbol): return CrossCovarianceMatrix(arg1, arg2, condition) coeff_rv_list1 = self._expand_single_argument(arg1.expand()) coeff_rv_list2 = self._expand_single_argument(arg2.expand()) addends = [a*CrossCovarianceMatrix(r1, r2, condition=condition)*b.transpose() for (a, r1) in coeff_rv_list1 for (b, r2) in coeff_rv_list2] return Add.fromiter(addends)
def convert_to(expr, target_units): """ Convert ``expr`` to the same expression with all of its units and quantities represented as factors of ``target_units``, whenever the dimension is compatible. ``target_units`` may be a single unit/quantity, or a collection of units/quantities. Examples ======== >>> from sympy.physics.units import speed_of_light, meter, gram, second, day >>> from sympy.physics.units import mile, newton, kilogram, atomic_mass_constant >>> from sympy.physics.units import kilometer, centimeter >>> from sympy.physics.units import convert_to >>> convert_to(mile, kilometer) 25146*kilometer/15625 >>> convert_to(mile, kilometer).n() 1.609344*kilometer >>> convert_to(speed_of_light, meter/second) 299792458*meter/second >>> convert_to(day, second) 86400*second >>> 3*newton 3*newton >>> convert_to(3*newton, kilogram*meter/second**2) 3*kilogram*meter/second**2 >>> convert_to(atomic_mass_constant, gram) 1.66053904e-24*gram Conversion to multiple units: >>> convert_to(speed_of_light, [meter, second]) 299792458*meter/second >>> convert_to(3*newton, [centimeter, gram, second]) 300000*centimeter*gram/second**2 Conversion to Planck units: >>> from sympy.physics.units import gravitational_constant, hbar >>> convert_to(atomic_mass_constant, [gravitational_constant, speed_of_light, hbar]).n() 7.62950196312651e-20*gravitational_constant**(-0.5)*hbar**0.5*speed_of_light**0.5 """ if not isinstance(target_units, (collections.Iterable, Tuple)): target_units = [target_units] if isinstance(expr, Add): return Add.fromiter(convert_to(i, target_units) for i in expr.args) expr = sympify(expr) if not isinstance(expr, Quantity) and expr.has(Quantity): expr = expr.replace(lambda x: isinstance(x, Quantity), lambda x: x.convert_to(target_units)) def get_total_scale_factor(expr): if isinstance(expr, Mul): return reduce(lambda x, y: x * y, [get_total_scale_factor(i) for i in expr.args]) elif isinstance(expr, Pow): return get_total_scale_factor(expr.base) ** expr.exp elif isinstance(expr, Quantity): return expr.scale_factor return expr depmat = _get_conversion_matrix_for_expr(expr, target_units) if depmat is None: return expr expr_scale_factor = get_total_scale_factor(expr) return expr_scale_factor * Mul.fromiter((1/get_total_scale_factor(u) * u) ** p for u, p in zip(target_units, depmat))
def recurse_expr(expr, index_ranges={}): if expr.is_Mul: nonmatargs = [] pos_arg = [] pos_ind = [] dlinks = {} link_ind = [] counter = 0 args_ind = [] for arg in expr.args: retvals = recurse_expr(arg, index_ranges) assert isinstance(retvals, list) if isinstance(retvals, list): for i in retvals: args_ind.append(i) else: args_ind.append(retvals) for arg_symbol, arg_indices in args_ind: if arg_indices is None: nonmatargs.append(arg_symbol) continue if isinstance(arg_symbol, MatrixElement): arg_symbol = arg_symbol.args[0] pos_arg.append(arg_symbol) pos_ind.append(arg_indices) link_ind.append([None] * len(arg_indices)) for i, ind in enumerate(arg_indices): if ind in dlinks: other_i = dlinks[ind] link_ind[counter][i] = other_i link_ind[other_i[0]][other_i[1]] = (counter, i) dlinks[ind] = (counter, i) counter += 1 counter2 = 0 lines = {} while counter2 < len(link_ind): for i, e in enumerate(link_ind): if None in e: line_start_index = (i, e.index(None)) break cur_ind_pos = line_start_index cur_line = [] index1 = pos_ind[cur_ind_pos[0]][cur_ind_pos[1]] while True: d, r = cur_ind_pos if pos_arg[d] != 1: if r % 2 == 1: cur_line.append(transpose(pos_arg[d])) else: cur_line.append(pos_arg[d]) next_ind_pos = link_ind[d][1 - r] counter2 += 1 # Mark as visited, there will be no `None` anymore: link_ind[d] = (-1, -1) if next_ind_pos is None: index2 = pos_ind[d][1 - r] lines[(index1, index2)] = cur_line break cur_ind_pos = next_ind_pos ret_indices = list(j for i in lines for j in i) lines = { k: MatMul.fromiter(v) if len(v) != 1 else v[0] for k, v in lines.items() } return [(Mul.fromiter(nonmatargs), None)] + [(MatrixElement( a, i, j), (i, j)) for (i, j), a in lines.items()] elif expr.is_Add: res = [recurse_expr(i) for i in expr.args] d = collections.defaultdict(list) for res_addend in res: scalar = 1 for elem, indices in res_addend: if indices is None: scalar = elem continue indices = tuple(sorted(indices, key=default_sort_key)) d[indices].append(scalar * remove_matelement(elem, *indices)) scalar = 1 return [(MatrixElement(Add.fromiter(v), *k), k) for k, v in d.items()] elif isinstance(expr, KroneckerDelta): i1, i2 = expr.args return [(MatrixElement(S.One, i1, i2), (i1, i2))] elif isinstance(expr, MatrixElement): matrix_symbol, i1, i2 = expr.args if i1 in index_ranges: r1, r2 = index_ranges[i1] if r1 != 0 or matrix_symbol.shape[0] != r2 + 1: raise ValueError( "index range mismatch: {0} vs. (0, {1})".format( (r1, r2), matrix_symbol.shape[0])) if i2 in index_ranges: r1, r2 = index_ranges[i2] if r1 != 0 or matrix_symbol.shape[1] != r2 + 1: raise ValueError( "index range mismatch: {0} vs. (0, {1})".format( (r1, r2), matrix_symbol.shape[1])) if (i1 == i2) and (i1 in index_ranges): return [(trace(matrix_symbol), None)] return [(MatrixElement(matrix_symbol, i1, i2), (i1, i2))] elif isinstance(expr, Sum): return recurse_expr( expr.args[0], index_ranges={i[0]: i[1:] for i in expr.args[1:]}) else: return [(expr, None)]
def get_max_coef(sym, x_term): return Add.fromiter( get_max_coef_mul(s, x_term) for s in Add.make_args(sym) )
def divergence(vect, coord_sys=None, doit=True): """ Returns the divergence of a vector field computed wrt the base scalars of the given coordinate system. Parameters ========== vector : Vector The vector operand coord_sys : CoordSys3D The coordinate system to calculate the gradient in Deprecated since version 1.1 doit : bool If True, the result is returned after calling .doit() on each component. Else, the returned expression contains Derivative instances Examples ======== >>> from sympy.vector import CoordSys3D, divergence >>> R = CoordSys3D('R') >>> v1 = R.x*R.y*R.z * (R.i+R.j+R.k) >>> divergence(v1) R.x*R.y + R.x*R.z + R.y*R.z >>> v2 = 2*R.y*R.z*R.j >>> divergence(v2) 2*R.z """ coord_sys = _get_coord_sys_from_expr(vect, coord_sys) if len(coord_sys) == 0: return S.Zero elif len(coord_sys) == 1: if isinstance(vect, (Cross, Curl, Gradient)): return Divergence(vect) # TODO: is case of many coord systems, this gets a random one: coord_sys = next(iter(coord_sys)) i, j, k = coord_sys.base_vectors() x, y, z = coord_sys.base_scalars() h1, h2, h3 = coord_sys.lame_coefficients() vx = _diff_conditional(vect.dot(i), x, h2, h3) \ / (h1 * h2 * h3) vy = _diff_conditional(vect.dot(j), y, h3, h1) \ / (h1 * h2 * h3) vz = _diff_conditional(vect.dot(k), z, h1, h2) \ / (h1 * h2 * h3) res = vx + vy + vz if doit: return res.doit() return res else: if isinstance(vect, (Add, VectorAdd)): return Add.fromiter(divergence(i, doit=doit) for i in vect.args) elif isinstance(vect, (Mul, VectorMul)): vector = [i for i in vect.args if isinstance(i, (Vector, Cross, Gradient))][0] scalar = Mul.fromiter(i for i in vect.args if not isinstance(i, (Vector, Cross, Gradient))) res = Dot(vector, gradient(scalar)) + scalar*divergence(vector, doit=doit) if doit: return res.doit() return res elif isinstance(vect, (Cross, Curl, Gradient)): return Divergence(vect) else: raise Divergence(vect)
def recurse_expr(expr, index_ranges={}): if expr.is_Mul: nonmatargs = [] pos_arg = [] pos_ind = [] dlinks = {} link_ind = [] counter = 0 args_ind = [] for arg in expr.args: retvals = recurse_expr(arg, index_ranges) assert isinstance(retvals, list) if isinstance(retvals, list): for i in retvals: args_ind.append(i) else: args_ind.append(retvals) for arg_symbol, arg_indices in args_ind: if arg_indices is None: nonmatargs.append(arg_symbol) continue if isinstance(arg_symbol, MatrixElement): arg_symbol = arg_symbol.args[0] pos_arg.append(arg_symbol) pos_ind.append(arg_indices) link_ind.append([None]*len(arg_indices)) for i, ind in enumerate(arg_indices): if ind in dlinks: other_i = dlinks[ind] link_ind[counter][i] = other_i link_ind[other_i[0]][other_i[1]] = (counter, i) dlinks[ind] = (counter, i) counter += 1 counter2 = 0 lines = {} while counter2 < len(link_ind): for i, e in enumerate(link_ind): if None in e: line_start_index = (i, e.index(None)) break cur_ind_pos = line_start_index cur_line = [] index1 = pos_ind[cur_ind_pos[0]][cur_ind_pos[1]] while True: d, r = cur_ind_pos if pos_arg[d] != 1: if r % 2 == 1: cur_line.append(transpose(pos_arg[d])) else: cur_line.append(pos_arg[d]) next_ind_pos = link_ind[d][1-r] counter2 += 1 # Mark as visited, there will be no `None` anymore: link_ind[d] = (-1, -1) if next_ind_pos is None: index2 = pos_ind[d][1-r] lines[(index1, index2)] = cur_line break cur_ind_pos = next_ind_pos ret_indices = list(j for i in lines for j in i) lines = {k: MatMul.fromiter(v) if len(v) != 1 else v[0] for k, v in lines.items()} return [(Mul.fromiter(nonmatargs), None)] + [ (MatrixElement(a, i, j), (i, j)) for (i, j), a in lines.items() ] elif expr.is_Add: res = [recurse_expr(i) for i in expr.args] d = collections.defaultdict(list) for res_addend in res: scalar = 1 for elem, indices in res_addend: if indices is None: scalar = elem continue indices = tuple(sorted(indices, key=default_sort_key)) d[indices].append(scalar*remove_matelement(elem, *indices)) scalar = 1 return [(MatrixElement(Add.fromiter(v), *k), k) for k, v in d.items()] elif isinstance(expr, KroneckerDelta): i1, i2 = expr.args if dimensions is not None: identity = Identity(dimensions[0]) else: identity = S.One return [(MatrixElement(identity, i1, i2), (i1, i2))] elif isinstance(expr, MatrixElement): matrix_symbol, i1, i2 = expr.args if i1 in index_ranges: r1, r2 = index_ranges[i1] if r1 != 0 or matrix_symbol.shape[0] != r2+1: raise ValueError("index range mismatch: {0} vs. (0, {1})".format( (r1, r2), matrix_symbol.shape[0])) if i2 in index_ranges: r1, r2 = index_ranges[i2] if r1 != 0 or matrix_symbol.shape[1] != r2+1: raise ValueError("index range mismatch: {0} vs. (0, {1})".format( (r1, r2), matrix_symbol.shape[1])) if (i1 == i2) and (i1 in index_ranges): return [(trace(matrix_symbol), None)] return [(MatrixElement(matrix_symbol, i1, i2), (i1, i2))] elif isinstance(expr, Sum): return recurse_expr( expr.args[0], index_ranges={i[0]: i[1:] for i in expr.args[1:]} ) else: return [(expr, None)]
def convert_to(expr, target_units, unit_system="SI"): """ Convert ``expr`` to the same expression with all of its units and quantities represented as factors of ``target_units``, whenever the dimension is compatible. ``target_units`` may be a single unit/quantity, or a collection of units/quantities. Examples ======== >>> from sympy.physics.units import speed_of_light, meter, gram, second, day >>> from sympy.physics.units import mile, newton, kilogram, atomic_mass_constant >>> from sympy.physics.units import kilometer, centimeter >>> from sympy.physics.units import gravitational_constant, hbar >>> from sympy.physics.units import convert_to >>> convert_to(mile, kilometer) 25146*kilometer/15625 >>> convert_to(mile, kilometer).n() 1.609344*kilometer >>> convert_to(speed_of_light, meter/second) 299792458*meter/second >>> convert_to(day, second) 86400*second >>> 3*newton 3*newton >>> convert_to(3*newton, kilogram*meter/second**2) 3*kilogram*meter/second**2 >>> convert_to(atomic_mass_constant, gram) 1.660539060e-24*gram Conversion to multiple units: >>> convert_to(speed_of_light, [meter, second]) 299792458*meter/second >>> convert_to(3*newton, [centimeter, gram, second]) 300000*centimeter*gram/second**2 Conversion to Planck units: >>> from sympy.physics.units import gravitational_constant, hbar >>> convert_to(atomic_mass_constant, [gravitational_constant, speed_of_light, hbar]).n() 7.62963085040767e-20*gravitational_constant**(-0.5)*hbar**0.5*speed_of_light**0.5 """ from sympy.physics.units import UnitSystem unit_system = UnitSystem.get_unit_system(unit_system) if not isinstance(target_units, (Iterable, Tuple)): target_units = [target_units] if isinstance(expr, Add): return Add.fromiter( convert_to(i, target_units, unit_system) for i in expr.args) expr = sympify(expr) if not isinstance(expr, Quantity) and expr.has(Quantity): expr = expr.replace(lambda x: isinstance(x, Quantity), lambda x: x.convert_to(target_units, unit_system)) def get_total_scale_factor(expr): if isinstance(expr, Mul): return reduce(lambda x, y: x * y, [get_total_scale_factor(i) for i in expr.args]) elif isinstance(expr, Pow): return get_total_scale_factor(expr.base)**expr.exp elif isinstance(expr, Quantity): return unit_system.get_quantity_scale_factor(expr) return expr depmat = _get_conversion_matrix_for_expr(expr, target_units, unit_system) if depmat is None: return expr expr_scale_factor = get_total_scale_factor(expr) return expr_scale_factor * Mul.fromiter( (1 / get_total_scale_factor(u) * u)**p for u, p in zip(target_units, depmat))
def as_explicit(self): return Add.fromiter([arg.as_explicit() for arg in self.args])
def do_convert(self, expr, indices): if isinstance(expr, ArrayTensorProduct): cumul = list(accumulate([0] + [get_rank(arg) for arg in expr.args])) indices_grp = [indices[cumul[i]:cumul[i+1]] for i in range(len(expr.args))] return Mul.fromiter(self.do_convert(arg, ind) for arg, ind in zip(expr.args, indices_grp)) if isinstance(expr, ArrayContraction): new_indices = [None for i in range(get_rank(expr.expr))] limits = [] bottom_shape = get_shape(expr.expr) for contraction_index_grp in expr.contraction_indices: d = Dummy(f"d{self.count_dummies}") self.count_dummies += 1 dim = bottom_shape[contraction_index_grp[0]] limits.append((d, 0, dim-1)) for i in contraction_index_grp: new_indices[i] = d j = 0 for i in range(len(new_indices)): if new_indices[i] is None: new_indices[i] = indices[j] j += 1 newexpr = self.do_convert(expr.expr, new_indices) return Sum(newexpr, *limits) if isinstance(expr, ArrayDiagonal): new_indices = [None for i in range(get_rank(expr.expr))] ind_pos = expr._push_indices_down(expr.diagonal_indices, list(range(len(indices))), get_rank(expr)) for i, index in zip(ind_pos, indices): if isinstance(i, collections.abc.Iterable): for j in i: new_indices[j] = index else: new_indices[i] = index newexpr = self.do_convert(expr.expr, new_indices) return newexpr if isinstance(expr, PermuteDims): permuted_indices = _apply_permutation_to_list(expr.permutation, indices) return self.do_convert(expr.expr, permuted_indices) if isinstance(expr, ArrayAdd): return Add.fromiter(self.do_convert(arg, indices) for arg in expr.args) if isinstance(expr, _ArrayExpr): return expr.__getitem__(tuple(indices)) if isinstance(expr, ArrayElementwiseApplyFunc): return expr.function(self.do_convert(expr.expr, indices)) if isinstance(expr, Reshape): shape_up = expr.shape shape_down = get_shape(expr.expr) cumul = list(accumulate([1] + list(reversed(shape_up)), operator.mul)) one_index = Add.fromiter(i*s for i, s in zip(reversed(indices), cumul)) dest_indices = [None for _ in shape_down] c = 1 for i, e in enumerate(reversed(shape_down)): if c == 1: if i == len(shape_down) - 1: dest_indices[i] = one_index else: dest_indices[i] = one_index % e elif i == len(shape_down) - 1: dest_indices[i] = one_index // c else: dest_indices[i] = one_index // c % e c *= e dest_indices.reverse() return self.do_convert(expr.expr, dest_indices) return _get_array_element_or_slice(expr, indices)
def convert_unit_to(expr, target_units, unit_system=kamodo_unit_system, raise_errors=True): """ Same as sympy.convert_to but accepts equations and allows functions of units to pass Convert ``expr`` to the same expression with all of its units and quantities represented as factors of ``target_units``, whenever the dimension is compatible. ``target_units`` may be a single unit/quantity, or a collection of units/quantities. Examples ======== >>> from sympy.physics.units import speed_of_light, meter, gram, second, day >>> from sympy.physics.units import mile, newton, kilogram, atomic_mass_constant >>> from sympy.physics.units import kilometer, centimeter >>> from sympy.physics.units import gravitational_constant, hbar >>> from sympy.physics.units import convert_to >>> convert_to(mile, kilometer) 25146*kilometer/15625 >>> convert_to(mile, kilometer).n() 1.609344*kilometer >>> convert_to(speed_of_light, meter/second) 299792458*meter/second >>> convert_to(day, second) 86400*second >>> 3*newton 3*newton >>> convert_to(3*newton, kilogram*meter/second**2) 3*kilogram*meter/second**2 >>> convert_to(atomic_mass_constant, gram) 1.660539060e-24*gram Conversion to multiple units: >>> convert_to(speed_of_light, [meter, second]) 299792458*meter/second >>> convert_to(3*newton, [centimeter, gram, second]) 300000*centimeter*gram/second**2 Conversion to Planck units: >>> from sympy.physics.units import gravitational_constant, hbar >>> convert_to(atomic_mass_constant, [gravitational_constant, speed_of_light, hbar]).n() 7.62963085040767e-20*gravitational_constant**(-0.5)*hbar**0.5*speed_of_light**0.5 """ from sympy.physics.units import UnitSystem unit_system = UnitSystem.get_unit_system(unit_system) if not isinstance(target_units, (Iterable, Tuple)): target_units = [target_units] if hasattr(expr, 'rhs'): return Eq(convert_unit_to(expr.lhs, target_units, unit_system), convert_unit_to(expr.rhs, target_units, unit_system)) # if type(type(expr)) is UndefinedFunction: if is_function(expr): # print('undefined input expr:{}'.format(expr)) return nsimplify(expr, rational=True) if isinstance(expr, Add): return Add.fromiter( convert_unit_to(i, target_units, unit_system) for i in expr.args) expr = sympify(expr) if not isinstance(expr, Quantity) and expr.has(Quantity): try: expr = expr.replace( lambda x: isinstance(x, Quantity), lambda x: x.convert_to(target_units, unit_system)) except OSError: raise OSError('problem converting {} to {}\n{}'.format( expr, target_units, unit_system)) def get_total_scale_factor(expr): if isinstance(expr, Mul): return reduce(lambda x, y: x * y, [get_total_scale_factor(i) for i in expr.args]) elif isinstance(expr, Pow): return get_total_scale_factor(expr.base)**expr.exp elif isinstance(expr, Quantity): return unit_system.get_quantity_scale_factor(expr) return expr if expr == target_units: return expr depmat = _get_conversion_matrix_for_expr(expr, target_units, unit_system) if depmat is None: if raise_errors: raise NameError('cannot convert {} to {} {}'.format( expr, target_units, unit_system)) return nsimplify(expr, rational=True) expr_scale_factor = get_total_scale_factor(expr) result = expr_scale_factor * Mul.fromiter( (1 / get_total_scale_factor(u) * u)**p for u, p in zip(target_units, depmat)) return nsimplify(result, rational=True)
def divergence(vect, coord_sys=None, doit=True): """ Returns the divergence of a vector field computed wrt the base scalars of the given coordinate system. Parameters ========== vector : Vector The vector operand coord_sys : CoordSys3D The coordinate system to calculate the gradient in Deprecated since version 1.1 doit : bool If True, the result is returned after calling .doit() on each component. Else, the returned expression contains Derivative instances Examples ======== >>> from sympy.vector import CoordSys3D, divergence >>> R = CoordSys3D('R') >>> v1 = R.x*R.y*R.z * (R.i+R.j+R.k) >>> divergence(v1) R.x*R.y + R.x*R.z + R.y*R.z >>> v2 = 2*R.y*R.z*R.j >>> divergence(v2) 2*R.z """ coord_sys = _get_coord_sys_from_expr(vect, coord_sys) if len(coord_sys) == 0: return S.Zero elif len(coord_sys) == 1: if isinstance(vect, (Cross, Curl, Gradient)): return Divergence(vect) # TODO: is case of many coord systems, this gets a random one: coord_sys = next(iter(coord_sys)) i, j, k = coord_sys.base_vectors() x, y, z = coord_sys.base_scalars() h1, h2, h3 = coord_sys.lame_coefficients() vx = _diff_conditional(vect.dot(i), x, h2, h3) \ / (h1 * h2 * h3) vy = _diff_conditional(vect.dot(j), y, h3, h1) \ / (h1 * h2 * h3) vz = _diff_conditional(vect.dot(k), z, h1, h2) \ / (h1 * h2 * h3) res = vx + vy + vz if doit: return res.doit() return res else: if isinstance(vect, (Add, VectorAdd)): return Add.fromiter(divergence(i, doit=doit) for i in vect.args) elif isinstance(vect, (Mul, VectorMul)): vector = [ i for i in vect.args if isinstance(i, (Vector, Cross, Gradient)) ][0] scalar = Mul.fromiter( i for i in vect.args if not isinstance(i, (Vector, Cross, Gradient))) res = Dot( vector, gradient(scalar)) + scalar * divergence(vector, doit=doit) if doit: return res.doit() return res elif isinstance(vect, (Cross, Curl, Gradient)): return Divergence(vect) else: raise Divergence(vect)
def unify(expr, unit_registry, to_symbol=None, verbose=False): """adds unit conversion factors to composed functions""" if verbose: print('unify: to_symbol:', to_symbol) if hasattr(expr, 'rhs'): return Eq( expr.lhs, unify(expr.rhs, unit_registry, to_symbol=expr.lhs, verbose=verbose)) if isinstance(expr, Add): if verbose: print('unify: Adding expression: {} -> {}'.format( expr, get_expr_unit(to_symbol, unit_registry, verbose))) return Add.fromiter([ unify(arg, unit_registry, to_symbol, verbose) for arg in expr.args ]) expr_unit = get_expr_unit(expr, unit_registry, verbose) if verbose: print('unify: {} unit {}'.format(expr, expr_unit)) print('unify: {} symbols {}'.format(expr, expr.free_symbols)) print('unify: {} symbols {}'.format(to_symbol, to_symbol.free_symbols)) try: assert expr.free_symbols.issubset(to_symbol.free_symbols) except: raise NameError("{} arguments not in {}".format( expr.free_symbols, to_symbol.free_symbols)) if is_function(expr): if verbose: print('unify: function expression: {}'.format(expr)) if to_symbol is not None: if verbose: print('\nunify: to_symbol args: {}'.format(to_symbol.args)) print('unify: to_symbol free symbols: {}'.format( to_symbol.free_symbols)) print('unify: expr args: {}'.format(expr.args)) print('unify: expr free symbols: {}'.format(expr.free_symbols)) for k, v in unit_registry.items(): if isinstance(expr, type(k)): if len(k.free_symbols) > 0: if verbose: print('unify: found matching {} -> {}'.format( expr, k)) arg_units = get_arg_units(k, unit_registry) if verbose: print('unify: func units:', arg_units) print('unify: {}->{}'.format(expr.args, k.args)) expr_units = {} for arg, sym in zip(expr.args, k.args): to_unit = arg_units.get(sym) from_unit = get_expr_unit(arg, unit_registry) if (from_unit is not None) and (to_unit is not None): expr_units[arg] = convert_unit_to( arg * from_unit, to_unit, kamodo_unit_system) / to_unit expr = expr.subs(expr_units) if verbose: print('unify: replaced args', expr) expr = unify_args(expr, unit_registry, to_symbol, verbose) if (to_symbol is not None) & (expr_unit is not None): to_unit = get_expr_unit(to_symbol, unit_registry, verbose) if verbose: print('unify: to_unit {}'.format(to_unit)) expr_dimensions = get_dimensions(expr_unit) to_dimensions = get_dimensions(to_unit) if expr_dimensions.compare(to_dimensions) == 0: if verbose: print('unify: {} [{}] -> to_symbol: {}[{}]'.format( expr, expr_unit, to_symbol, to_unit)) expr = convert_unit_to(expr * expr_unit, to_unit, kamodo_unit_system) / to_unit else: if verbose: print('unify: registry:') for k, v in unit_registry.items(): print('unify:\t{} -> {}'.format(k, v)) print('compare:{}'.format( expr_dimensions.compare(to_dimensions))) error_msg = 'cannot convert {} [{}] {} to {}[{}] {}'.format( expr, expr_unit, expr_dimensions, to_symbol, to_unit, to_dimensions) print(error_msg) raise NameError(error_msg) return expr