def test_int(self): f1 = as_ufl(1) f2 = as_ufl(1.0) f3 = IntValue(1) f4 = IntValue(1.0) f5 = 3 - IntValue(1) - 1 f6 = 3 * IntValue(2) / 6 assert f1 == f1 self.assertNotEqual(f1, f2) # IntValue vs FloatValue, == compares representations! assert f1 == f3 assert f1 == f4 assert f1 == f5 assert f2 == f6 # Division produces a FloatValue
class IDiv(AugmentedAssignment): """A UFL `/=` operator.""" _symbol = "/=" _ast = ast.IDiv _identity = IntValue(1) __slots__ = ()
class IMul(AugmentedAssignment): """A UFL `*=` operator.""" _symbol = "*=" _ast = ast.IMul _identity = IntValue(1) __slots__ = ()
def __new__(cls, a, b): # Conversion a = as_ufl(a) b = as_ufl(b) # Type checking if not is_true_ufl_scalar(a): error("Cannot take the power of a non-scalar expression %s." % ufl_err_str(a)) if not is_true_ufl_scalar(b): error("Cannot raise an expression to a non-scalar power %s." % ufl_err_str(b)) # Simplification if isinstance(a, ScalarValue) and isinstance(b, ScalarValue): return as_ufl(a._value**b._value) if isinstance(b, Zero): return IntValue(1) if isinstance(a, Zero) and isinstance(b, ScalarValue): if isinstance(b, ComplexValue): error("Cannot raise zero to a complex power.") bf = float(b) if bf < 0: error("Division by zero, cannot raise 0 to a negative power.") else: return zero() if isinstance(b, ScalarValue) and b._value == 1: return a # Construction self = Operator.__new__(cls) self._init(a, b) return self
def _make_ones_diff(self, o): ufl_assert(o.shape() == self._var_shape, "This is only used by VariableDerivative, yes?") # Define a scalar value with the right indices # (kind of cumbersome this... any simpler way?) sh = o.shape() fi = o.free_indices() idims = dict(o.index_dimensions()) if self._var_free_indices: # Currently assuming only one free variable index i, = self._var_free_indices if i not in idims: fi = unique_indices(fi + (i, )) idims[i] = self._var_index_dimensions[i] # Create a 1 with index annotations one = IntValue(1, (), fi, idims) res = None if sh == (): return one elif len(sh) == 1: # FIXME: If sh == (1,), I think this will get the wrong shape? # I think we should make sure sh=(1,...,1) is always converted to () early. fp = Identity(sh[0]) else: ind1 = () ind2 = () for d in sh: i, j = indices(2) dij = Identity(d)[i, j] if res is None: res = dij else: res *= dij ind1 += (i, ) ind2 += (j, ) fp = as_tensor(res, ind1 + ind2) # Apply index annotations if fi: fp *= one return fp
def __new__(cls, a, b): a = as_ufl(a) b = as_ufl(b) if not is_true_ufl_scalar(a): error("Cannot take the power of a non-scalar expression.") if not is_true_ufl_scalar(b): error("Cannot raise an expression to a non-scalar power.") if isinstance(a, ScalarValue) and isinstance(b, ScalarValue): return as_ufl(a._value ** b._value) if a == 0 and isinstance(b, ScalarValue): bf = float(b) if bf < 0: error("Division by zero, annot raise 0 to a negative power.") else: return zero() if b == 1: return a if b == 0: return IntValue(1) # construct and initialize a new Power object self = AlgebraOperator.__new__(cls) self._init(a, b) return self
def __new__(cls, *operands): # Make sure everything is an Expr operands = [as_ufl(o) for o in operands] # Make sure everything is scalar #ufl_assert(not any(o.shape() for o in operands), # "Product can only represent products of scalars.") if any(o.shape() for o in operands): error("Product can only represent products of scalars.") # No operands? Return one. if not operands: return IntValue(1) # Got one operand only? Just return it. if len(operands) == 1: return operands[0] # Got any zeros? Return zero. if any(isinstance(o, Zero) for o in operands): free_indices = unique_indices(tuple(chain(*(o.free_indices() for o in operands)))) index_dimensions = subdict(mergedicts([o.index_dimensions() for o in operands]), free_indices) return Zero((), free_indices, index_dimensions) # Merge scalars, but keep nonscalars sorted scalars = [] nonscalars = [] for o in operands: if isinstance(o, ScalarValue): scalars.append(o) else: nonscalars.append(o) if scalars: # merge scalars p = as_ufl(product(s._value for s in scalars)) # only scalars? if not nonscalars: return p # merged scalar is unity? if p == 1: scalars = [] # Left with one nonscalar operand only after merging scalars? if len(nonscalars) == 1: return nonscalars[0] else: scalars = [p] # Sort operands in a canonical order (NB! This is fragile! Small changes here can have large effects.) operands = scalars + sorted_expr(nonscalars) # Replace n-repeated operands foo with foo**n newoperands = [] op, nop = operands[0], 1 for o in operands[1:] + [None]: if o == op: # op is repeated, count number of repetitions nop += 1 else: if nop == 1: # op is not repeated newoperands.append(op) elif op.free_indices(): # We can't simplify products to powers if the operands has # free indices, because of complications in differentiation. # op repeated, but has free indices, so we don't simplify newoperands.extend([op]*nop) else: # op repeated, make it a power newoperands.append(op**nop) # Reset op as o op, nop = o, 1 operands = newoperands # Left with one operand only after simplifications? if len(operands) == 1: return operands[0] # Construct and initialize a new Product object self = AlgebraOperator.__new__(cls) self._init(*operands) return self
def _tensor(self, key, indices): tensor = ExprTensor(self._shape(key)) tensor[indices] = IntValue(1) return {key: tensor}