def _eval_evalf(self, prec): c, m = self.as_coeff_Mul() if c is S.NegativeOne: if m.is_Mul: rv = -AssocOp._eval_evalf(m, prec) else: mnew = m._eval_evalf(prec) if mnew is not None: m = mnew rv = -m else: rv = AssocOp._eval_evalf(self, prec) if rv.is_number: return rv.expand() return rv
def __new__(cls, *args, **kwargs): evaluate = kwargs.get('evaluate', True) if not args: return VectorZero() args = list(map(sympify, args)) # If for any reasons we create VecAdd(0), I want 0 to be returned. # Skipping this check, VectorZero() will be returned instead if len(args) == 1 and args[0] == S.Zero: return S.Zero if evaluate: # remove instances of S.Zero and VectorZero args = [ a for a in args if not (isinstance(a, VectorZero) or (a == S.Zero) or (a == Vector.zero)) ] if len(args) == 0: return VectorZero() elif len(args) == 1: # doesn't make any sense to have 1 argument in VecAdd if # evaluate=True return args[0] obj = AssocOp.__new__(cls, *args, evaluate=evaluate) obj = _sanitize_args(obj) # print("VecAdd OBJ", obj.func, obj) if not isinstance(obj, cls): return obj # are there any scalars or vectors? any_vectors = any([a.is_Vector for a in obj.args]) all_vectors = all([a.is_Vector for a in obj.args]) # addition of mixed scalars and vectors is not supported. # If there are scalars in the addition, either all arguments # are scalars (hence not a vector expression) or there are # mixed arguments, hence throw an error obj.is_Vector = all_vectors if (any_vectors and (not all_vectors)): asd = obj.args[1] print("####", asd.is_Vector, asd.args) print("####", [a.is_Vector for a in asd.args]) for a in postorder_traversal(asd): print(a.func, a.is_Vector, a) raise TypeError("VecAdd: Mix of Vector and Scalar symbols:\n\t" + "\n\t".join( str(a.func) + ", " + str(a.is_Vector) + ", " + str(a) for a in obj.args)) return obj
def matches(self, expr, repl_dict={}): expr = sympify(expr) if self.is_commutative and expr.is_commutative: return AssocOp._matches_commutative(self, expr, repl_dict) elif self.is_commutative is not expr.is_commutative: return None c1, nc1 = self.args_cnc() c2, nc2 = expr.args_cnc() repl_dict = repl_dict.copy() if c1: if not c2: c2 = [1] a = Mul(*c1) if isinstance(a, AssocOp): repl_dict = a._matches_commutative(Mul(*c2), repl_dict) else: repl_dict = a.matches(Mul(*c2), repl_dict) if repl_dict: a = Mul(*nc1) if isinstance(a, Mul): repl_dict = a._matches(Mul(*nc2), repl_dict) else: repl_dict = a.matches(Mul(*nc2), repl_dict) return repl_dict or None
def matches(self, expr, repl_dict={}, old=False): return AssocOp._matches_commutative(self, expr, repl_dict, old)
def __new__(cls, *args, **kwargs): evaluate = kwargs.get('evaluate', True) print("VecMul __new__", args) if not args: # it makes sense to return VectorOne, after all we are talking # about VecMul. However, this would play against us when using # expand(), because we would have multiplications of multiple # vectors (one of which, VectorOne). # Hence, better to return S.One. return S.One args = list(map(sympify, args)) if len(args) == 1: # doesn't make any sense to have 1 argument in VecAdd if # evaluate=True return args[0] # # TODO: look through args (which are unprocessed as of now) for # # (a & nabla) * x (where x can be a scalar field or a vector field) # dot, field = None, None # skip_idx = [] # dot_field = [] # for i in range(len(args) - 1): # if isinstance(args[i], VecDot) and isinstance(args[i].args[1], Nabla): # dot = args[i] # field = args[i + 1] # skip_idx.extend([i, i + 1]) vectors = [a.is_Vector for a in args] if vectors.count(True) > 1: raise TypeError( "Multiplication of vector quantities not supported\n\t" + "\n\t".join(str(a.func) + ", " + str(a) for a in args)) # remove instances of S.One args = [a for a in args if a is not cls.identity] if len(args) == 0: return S.One if len(args) == 1: return args[0] if evaluate: # check if any vector is present args_is_vector = [a.is_Vector for a in args] if any([a == S.Zero for a in args]): if any(args_is_vector): return VectorZero() return S.Zero if any([(isinstance(a, VectorZero) or (a == Vector.zero)) for a in args]): return VectorZero() if (all([not isinstance(a, VectorExpr) for a in args]) and any([not isinstance(a, Vector) for a in args]) and len(args) > 1): return reduce(mul, args) # return _prod(args) print("\t pre AssocOp.__new__", args) obj = AssocOp.__new__(cls, *args, evaluate=evaluate) obj = _sanitize_args(obj) print("\t post AssocOp.__new__", obj.func) for a in obj.args: print("\t\t", a.func, a.is_Vector, a) # obj = obj.func._exec_constructor_postprocessors(obj) # At this point, obj might not be of type VecMul. We must return # otherwise the next checks are going to be applied. # Example #1: VecMul(3, a + b) -> VecAdd(3 * a, 3 * b) # Example #2: # C = CoordSys3D("C") # vn1 = C.i + 2 * C.j + 3 * C.k # vn2 = x * C.i + y * C.j + z * C.k # VecMul(3, VecDot(vn1, vn2)).doit() -> Add(x, 2 * y, 3 * z) if not isinstance(obj, VecMul): return obj vectors = [a.is_Vector for a in obj.args] cvectors = vectors.count(True) obj.is_Vector = cvectors > 0 if cvectors > 1: raise TypeError( "VecMul: Multiplication of vector quantities not supported\n\t" + "\n\t".join( str(a.func) + ", " + str(a.is_Vector) + ", " + str(a) for a in obj.args)) return obj