Esempio n. 1
0
    def __init__(self, expression, indices):
        WrapperType.__init__(self)
        ufl_assert(isinstance(expression, Expr), "Expecting ufl expression.")
        ufl_assert(expression.shape() == (),
                   "Expecting scalar valued expression.")
        self._expression = expression

        ufl_assert(
            all(isinstance(i, Index) for i in indices),
            "Expecting sequence of Index objects, not %s." % repr(indices))

        dims = expression.index_dimensions()

        if not isinstance(indices, MultiIndex):  # if constructed from repr
            indices = MultiIndex(indices, subdict(dims, indices))
        self._indices = indices

        eset = set(expression.free_indices())
        iset = set(self._indices)
        freeset = eset - iset
        self._free_indices = tuple(freeset)

        missingset = iset - eset
        if missingset:
            error("Missing indices %s in expression %s." %
                  (missingset, expression))

        self._index_dimensions = dict(
            (i, dims[i]) for i in self._free_indices) or EmptyDict
        self._shape = tuple(dims[i] for i in self._indices)
 def __new__(cls, f):
     # Return zero if expression is trivially constant
     dim = f.geometric_dimension()
     if f.is_cellwise_constant():
         free_indices = f.free_indices()
         index_dimensions = subdict(f.index_dimensions(), free_indices)
         return Zero((dim,) + f.shape(), free_indices, index_dimensions)
     return CompoundDerivative.__new__(cls)
 def __new__(cls, f, v):
     # Return zero if expression is trivially independent of variable
     if isinstance(f, Terminal):
         free_indices = tuple(set(f.free_indices()) ^ set(v.free_indices()))
         index_dimensions = mergedicts([f.index_dimensions(), v.index_dimensions()])
         index_dimensions = subdict(index_dimensions, free_indices)
         return Zero(f.shape() + v.shape(), free_indices, index_dimensions)
     return Derivative.__new__(cls)
 def conditional(self, o, c, t, f):
     o = self.reuse_if_possible(o, c[0], t[0], f[0])
     if isinstance(t[1], Zero) and isinstance(f[1], Zero):
         tp = t[1] # Assuming t[1] and f[1] have the same indices here, which should be the case
         fi = tp.free_indices()
         fid = subdict(tp.index_dimensions(), fi)
         op = Zero(tp.shape(), fi, fid)
     else:
         op = conditional(c[0], 1, 0)*t[1] + conditional(c[0], 0, 1)*f[1]
     return (o, op)
 def conditional(self, o, c, t, f):
     o = self.reuse_if_possible(o, c[0], t[0], f[0])
     if isinstance(t[1], Zero) and isinstance(f[1], Zero):
         tp = t[
             1]  # Assuming t[1] and f[1] have the same indices here, which should be the case
         fi = tp.free_indices()
         fid = subdict(tp.index_dimensions(), fi)
         op = Zero(tp.shape(), fi, fid)
     else:
         op = conditional(c[0], 1, 0) * t[1] + conditional(c[0], 0,
                                                           1) * f[1]
     return (o, op)
def _getitem(self, key):
    # Analyse key, getting rid of slices and the ellipsis
    r = self.rank()
    indices, axis_indices = analyse_key(key, r)

    # Special case for foo[...] => foo
    if len(indices) == len(axis_indices):
        return self

    # Special case for simplifying ({ai}_i)[i] -> ai
    if isinstance(self, ComponentTensor):
        if tuple(indices) == tuple(self._indices):
            return self._expression

    # Index self, yielding scalar valued expressions
    a = Indexed(self, indices)

    # Make a tensor from components designated by axis indices
    if axis_indices:
        a = as_tensor(a, axis_indices)

    # TODO: Should we apply IndexSum or as_tensor first?

    # Apply sum for each repeated index
    ri = repeated_indices(self.free_indices() + indices)
    for i in ri:
        a = IndexSum(a, i)

    # Check for zero (last so we can get indices etc from a)
    if isinstance(self, Zero):
        shape = a.shape()
        fi = a.free_indices()
        idims = subdict(a.index_dimensions(), fi)
        a = Zero(shape, fi, idims)

    return a
Esempio n. 7
0
    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 _mult(a, b):
    # Discover repeated indices, which results in index sums
    ai = a.free_indices()
    bi = b.free_indices()
    ii = ai + bi
    ri = repeated_indices(ii)

    # Pick out valid non-scalar products here (dot products):
    # - matrix-matrix (A*B, M*grad(u)) => A . B
    # - matrix-vector (A*v) => A . v
    s1, s2 = a.shape(), b.shape()
    r1, r2 = len(s1), len(s2)
    if r1 == 2 and r2 in (1, 2):
        ufl_assert(not ri,
                   "Not expecting repeated indices in non-scalar product.")

        # Check for zero, simplifying early if possible
        if isinstance(a, Zero) or isinstance(b, Zero):
            shape = s1[:-1] + s2[1:]
            fi = single_indices(ii)
            idims = mergedicts((a.index_dimensions(), b.index_dimensions()))
            idims = subdict(idims, fi)
            return Zero(shape, fi, idims)

        # Return dot product in index notation
        ai = indices(a.rank() - 1)
        bi = indices(b.rank() - 1)
        k = indices(1)
        # Create an IndexSum over a Product
        s = a[ai + k] * b[k + bi]
        return as_tensor(s, ai + bi)

    elif not (r1 == 0 and r2 == 0):
        # Scalar - tensor product
        if r2 == 0:
            a, b = b, a
            s1, s2 = s2, s1

        # Check for zero, simplifying early if possible
        if isinstance(a, Zero) or isinstance(b, Zero):
            shape = s2
            fi = single_indices(ii)
            idims = mergedicts((a.index_dimensions(), b.index_dimensions()))
            idims = subdict(idims, fi)
            return Zero(shape, fi, idims)

        # Repeated indices are allowed, like in:
        #v[i]*M[i,:]

        # Apply product to scalar components
        ii = indices(b.rank())
        p = Product(a, b[ii])

        # Wrap as tensor again
        p = as_tensor(p, ii)

        # TODO: Should we apply IndexSum or as_tensor first?

        # Apply index sums
        for i in ri:
            p = IndexSum(p, i)

        return p

    # Scalar products use Product and IndexSum for implicit sums:
    p = Product(a, b)
    for i in ri:
        p = IndexSum(p, i)
    return p