Пример #1
0
    def __new__(cls, *expressions):
        # All lists and tuples should already be unwrapped in
        # as_tensor
        if any(not isinstance(e, Expr) for e in expressions):
            error("Expecting only UFL expressions in ListTensor constructor.")

        # Get properties of the first expression
        e0 = expressions[0]
        sh = e0.ufl_shape
        fi = e0.ufl_free_indices
        fid = e0.ufl_index_dimensions

        # Obviously, each subexpression must have the same shape
        if any(sh != e.ufl_shape for e in expressions[1:]):
            error(
                "Cannot create a tensor by joining subexpressions with different shapes."
            )
        if any(fi != e.ufl_free_indices for e in expressions[1:]):
            error(
                "Cannot create a tensor where the components have different free indices."
            )
        if any(fid != e.ufl_index_dimensions for e in expressions[1:]):
            error(
                "Cannot create a tensor where the components have different free index dimensions."
            )

        # Simplify to Zero if possible
        if all(isinstance(e, Zero) for e in expressions):
            shape = (len(expressions), ) + sh
            return Zero(shape, fi, fid)

        return Operator.__new__(cls)
Пример #2
0
    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
Пример #3
0
    def __new__(cls, a, b):
        # Conversion
        a = as_ufl(a)
        b = as_ufl(b)

        # Type checking
        # TODO: Enabled workaround for nonscalar division in __div__,
        # so maybe we can keep this assertion. Some algorithms may
        # need updating.
        if not is_ufl_scalar(a):
            error("Expecting scalar nominator in Division.")
        if not is_true_ufl_scalar(b):
            error("Division by non-scalar is undefined.")
        if isinstance(b, Zero):
            error("Division by zero!")

        # Simplification
        # Simplification a/b -> a
        if isinstance(a, Zero) or (isinstance(b, ScalarValue)
                                   and b._value == 1):
            return a
        # Simplification "literal a / literal b" -> "literal value of
        # a/b". Avoiding integer division by casting to float
        if isinstance(a, ScalarValue) and isinstance(b, ScalarValue):
            return as_ufl(float(a._value) / float(b._value))
        # Simplification "a / a" -> "1"
        # if not a.ufl_free_indices and not a.ufl_shape and a == b:
        #    return as_ufl(1)

        # Construction
        self = Operator.__new__(cls)
        self._init(a, b)
        return self
Пример #4
0
    def __new__(cls, *expressions):
        # All lists and tuples should already be unwrapped in
        # as_tensor
        if any(not isinstance(e, Expr) for e in expressions):
            error("Expecting only UFL expressions in ListTensor constructor.")

        # Get properties of the first expression
        e0 = expressions[0]
        sh = e0.ufl_shape
        fi = e0.ufl_free_indices
        fid = e0.ufl_index_dimensions

        # Obviously, each subexpression must have the same shape
        if any(sh != e.ufl_shape for e in expressions[1:]):
            error("Cannot create a tensor by joining subexpressions with different shapes.")
        if any(fi != e.ufl_free_indices for e in expressions[1:]):
            error("Cannot create a tensor where the components have different free indices.")
        if any(fid != e.ufl_index_dimensions for e in expressions[1:]):
            error("Cannot create a tensor where the components have different free index dimensions.")

        # Simplify to Zero if possible
        if all(isinstance(e, Zero) for e in expressions):
            shape = (len(expressions),) + sh
            return Zero(shape, fi, fid)

        return Operator.__new__(cls)
Пример #5
0
 def __new__(cls, arg1, arg2):
     if isinstance(arg1, (RealValue, Zero)) and isinstance(
             arg2, (RealValue, Zero)):
         return FloatValue(math.atan2(float(arg1), float(arg2)))
     if isinstance(arg1,
                   (ComplexValue)) or isinstance(arg2, (ComplexValue)):
         raise TypeError("Atan2 does not support complex numbers.")
     return Operator.__new__(cls)
Пример #6
0
    def __new__(cls, expression, indices):

        # Simplify
        if isinstance(expression, Zero):
            fi, fid, sh = remove_indices(expression.ufl_free_indices,
                                         expression.ufl_index_dimensions,
                                         [ind.count() for ind in indices])
            return Zero(sh, fi, fid)

        # Construct
        return Operator.__new__(cls)
Пример #7
0
    def __new__(cls, expression, indices):

        # Simplify
        if isinstance(expression, Zero):
            fi, fid, sh = remove_indices(expression.ufl_free_indices,
                                         expression.ufl_index_dimensions,
                                         [ind.count() for ind in indices])
            return Zero(sh, fi, fid)

        # Construct
        return Operator.__new__(cls)
Пример #8
0
    def __new__(cls, a):
        a = as_ufl(a)

        # Simplification
        if isinstance(a, (Abs, Real, Imag, Zero)):
            return a
        if isinstance(a, Conj):
            return a.ufl_operands[0]
        if isinstance(a, ScalarValue):
            return as_ufl(a._value.conjugate())

        return Operator.__new__(cls)
Пример #9
0
    def __new__(cls, a):
        a = as_ufl(a)

        # Simplification
        if isinstance(a, (Zero, Abs)):
            return a
        if isinstance(a, Conj):
            return Abs(a.ufl_operands[0])
        if isinstance(a, ScalarValue):
            return as_ufl(abs(a._value))

        return Operator.__new__(cls)
Пример #10
0
    def __new__(cls, a):
        a = as_ufl(a)

        # Simplification
        if isinstance(a, Zero):
            return a
        if isinstance(a, (Real, Imag, Abs)):
            return Zero(a.ufl_shape, a.ufl_free_indices, a.ufl_index_dimensions)
        if isinstance(a, ScalarValue):
            return as_ufl(a.imag())

        return Operator.__new__(cls)
Пример #11
0
    def __new__(cls, a):
        a = as_ufl(a)

        # Simplification
        if isinstance(a, Conj):
            a = a.ufl_operands[0]
        if isinstance(a, Zero):
            return a
        if isinstance(a, ScalarValue):
            return as_ufl(a.real())
        if isinstance(a, Real):
            a = a.ufl_operands[0]

        return Operator.__new__(cls)
Пример #12
0
    def __new__(cls, a, b):
        # Make sure everything is an Expr
        a = as_ufl(a)
        b = as_ufl(b)

        # Assert consistent tensor properties
        sh = a.ufl_shape
        fi = a.ufl_free_indices
        fid = a.ufl_index_dimensions
        if b.ufl_shape != sh:
            error("Can't add expressions with different shapes.")
        if b.ufl_free_indices != fi:
            error("Can't add expressions with different free indices.")
        if b.ufl_index_dimensions != fid:
            error("Can't add expressions with different index dimensions.")

        # Skip adding zero
        if isinstance(a, Zero):
            return b
        elif isinstance(b, Zero):
            return a

        # Handle scalars specially and sort operands
        sa = isinstance(a, ScalarValue)
        sb = isinstance(b, ScalarValue)
        if sa and sb:
            # Apply constant propagation
            return as_ufl(a._value + b._value)
        elif sa:
            # Place scalar first
            # operands = (a, b)
            pass  # a, b = a, b
        elif sb:
            # Place scalar first
            # operands = (b, a)
            a, b = b, a
        # elif a == b:
        #    # Replace a+b with 2*foo
        #    return 2*a
        else:
            # Otherwise sort operands in a canonical order
            # operands = (b, a)
            a, b = sorted_expr((a, b))

        # construct and initialize a new Sum object
        self = Operator.__new__(cls)
        self._init(a, b)
        return self
Пример #13
0
    def __new__(cls, a, b):
        # Conversion
        a = as_ufl(a)
        b = as_ufl(b)

        # Type checking
        # Make sure everything is scalar
        if a.ufl_shape or b.ufl_shape:
            error("Product can only represent products of scalars, "
                  "got\n\t%s\nand\n\t%s" % (ufl_err_str(a), ufl_err_str(b)))

        # Simplification
        if isinstance(a, Zero) or isinstance(b, Zero):
            # Got any zeros? Return zero.
            fi, fid = merge_unique_indices(a.ufl_free_indices,
                                           a.ufl_index_dimensions,
                                           b.ufl_free_indices,
                                           b.ufl_index_dimensions)
            return Zero((), fi, fid)
        sa = isinstance(a, ScalarValue)
        sb = isinstance(b, ScalarValue)
        if sa and sb:  # const * const = const
            # FIXME: Handle free indices like with zero? I think
            # IntValue may be index annotated now?
            return as_ufl(a._value * b._value)
        elif sa:  # 1 * b = b
            if a._value == 1:
                return b
            # a, b = a, b
        elif sb:  # a * 1 = a
            if b._value == 1:
                return a
            a, b = b, a
        # elif a == b: # a * a = a**2 # TODO: Why? Maybe just remove this?
        #    if not a.ufl_free_indices:
        #        return a**2
        else:  # a * b = b * a
            # Sort operands in a semi-canonical order
            # (NB! This is fragile! Small changes here can have large effects.)
            a, b = sorted_expr((a, b))

        # Construction
        self = Operator.__new__(cls)
        self._init(a, b)
        return self
Пример #14
0
 def __new__(cls, expression, multiindex):
     if isinstance(expression, Zero):
         # Zero-simplify indexed Zero objects
         shape = expression.ufl_shape
         efi = expression.ufl_free_indices
         efid = expression.ufl_index_dimensions
         fi = list(zip(efi, efid))
         for pos, ind in enumerate(multiindex._indices):
             if isinstance(ind, Index):
                 fi.append((ind.count(), shape[pos]))
         fi = unique_sorted_indices(sorted(fi))
         if fi:
             fi, fid = zip(*fi)
         else:
             fi, fid = (), ()
         return Zero(shape=(), free_indices=fi, index_dimensions=fid)
     else:
         return Operator.__new__(cls)
Пример #15
0
 def __new__(cls, expression, multiindex):
     if isinstance(expression, Zero):
         # Zero-simplify indexed Zero objects
         shape = expression.ufl_shape
         efi = expression.ufl_free_indices
         efid = expression.ufl_index_dimensions
         fi = list(zip(efi, efid))
         for pos, ind in enumerate(multiindex._indices):
             if isinstance(ind, Index):
                 fi.append((ind.count(), shape[pos]))
         fi = unique_sorted_indices(sorted(fi))
         if fi:
             fi, fid = zip(*fi)
         else:
             fi, fid = (), ()
         return Zero(shape=(), free_indices=fi, index_dimensions=fid)
     else:
         return Operator.__new__(cls)
Пример #16
0
    def __new__(cls, summand, index):
        # Error checks
        if not isinstance(summand, Expr):
            error("Expecting Expr instance, got %s" % ufl_err_str(summand))
        if not isinstance(index, MultiIndex):
            error("Expecting MultiIndex instance, got %s" % ufl_err_str(index))
        if len(index) != 1:
            error("Expecting a single Index but got %d." % len(index))

        # Simplification to zero
        if isinstance(summand, Zero):
            sh = summand.ufl_shape
            j, = index
            fi = summand.ufl_free_indices
            fid = summand.ufl_index_dimensions
            pos = fi.index(j.count())
            fi = fi[:pos] + fi[pos+1:]
            fid = fid[:pos] + fid[pos+1:]
            return Zero(sh, fi, fid)

        return Operator.__new__(cls)
Пример #17
0
    def __new__(cls, summand, index):
        # Error checks
        if not isinstance(summand, Expr):
            error("Expecting Expr instance, got %s" % ufl_err_str(summand))
        if not isinstance(index, MultiIndex):
            error("Expecting MultiIndex instance, got %s" % ufl_err_str(index))
        if len(index) != 1:
            error("Expecting a single Index but got %d." % len(index))

        # Simplification to zero
        if isinstance(summand, Zero):
            sh = summand.ufl_shape
            j, = index
            fi = summand.ufl_free_indices
            fid = summand.ufl_index_dimensions
            pos = fi.index(j.count())
            fi = fi[:pos] + fi[pos + 1:]
            fid = fid[:pos] + fid[pos + 1:]
            return Zero(sh, fi, fid)

        return Operator.__new__(cls)
Пример #18
0
 def __new__(cls, arg1, arg2):
     if isinstance(arg1, (ScalarValue, Zero)) and isinstance(
             arg2, (ScalarValue, Zero)):
         return FloatValue(math.atan2(float(arg1), float(arg2)))
     return Operator.__new__(cls)
Пример #19
0
 def __new__(cls, arg1, arg2):
     if isinstance(arg1, (RealValue, Zero)) and isinstance(arg2, (RealValue, Zero)):
         return FloatValue(math.atan2(float(arg1), float(arg2)))
     if isinstance(arg1, (ComplexValue)) or isinstance(arg2, (ComplexValue)):
         raise TypeError("Atan2 does not support complex numbers.")
     return Operator.__new__(cls)