Skip to content

Commit

Permalink
Cleanup and improvements in expr module after introduction of integra…
Browse files Browse the repository at this point in the history
…l() (#54)

* Fix bug in custom 'expand' function:

When expanding an Add expression, this function was erroneously removing
the Number term from the sum.

* Fix bugs in 'is_linear_expression' function:

- Function was erroneously ignoring interface integrals;
- Function did not expand expressions before comparison.

* Add linearity check to LinearForm's constructor:

- When constructing a LinearForm from an expression, we verify that this
  is linear w.r.t. the given arguments, otherwise an exception is raised;
- The above behavior is now verified in a unit test;
- Moreover, the obsolete function 'is_linear_form' was removed.

* Remove obsolete function 'is_linear_form' from sympde.expr.basic:

Accordingly, LinearExpr's constructor uses 'is_linear_expression'.
Moreover, LinearExpr's constructor always checks linearity of input.

* Fix bug in unit tests: integrals of integrals.

* Implement math properties of Poisson's bracket:

- DONE: bilinearity and Leibniz's rule;
- TODO: anticommutativity and Jacobi identity.

* Add linearity checks to BilinearForm's constructor:

- When constructing a BilinearForm from an expression, we verify that this
  is linear w.r.t. trial and test functions, otherwise an exception is raised;
- The above behavior is now verified in a unit test;
- Moreover, the obsolete function 'is_bilinear_form' was removed.

* Poisson's bracket: add anti-commutativity, and some tests.

* [codacy] Remove some unused imports.

* Remove obsolete class 'BilinearExpr'.

* Remove output files generated by unit tests.

* [codacy] Remove unused imports.

* [codacy] Use '_' for dummy variables.

* [codacy] Remove more unused variables and imports.

* Check arguments number in Poisson bracket constructor.

* Reorder Poisson's bracket's arguments using 'str' instead of 'hash'.

* Add (failing) unit tests: LinearForm w/ indexed VectorTestFunction.

* Fix linearity check for expressions w/ indexed VectorTestFunction.

* Add extensive unit tests (failing) for vector products.

* Implement properties of vector products (dot, cross, inner, outer).

* Add workaround for Cross' anti-symmetry to FEEC compiler.

* Remove obsolete function Field and classes Unknown/VectorUnknown.

Moreover:

- Add 'projection_of' property to [Scalar|Vector]TestFunction;

- In FEEC compiler, identify proxy fields with elements of
  [Scalar|Vector]FunctionSpace of undefined kind, instead of
  [Scalar|Vector]Field (which is deprecated).

* [codacy] Remove unused imports.

* Update version.
  • Loading branch information
yguclu authored and ratnania committed Oct 28, 2019
1 parent 3415645 commit 8796094
Show file tree
Hide file tree
Showing 15 changed files with 753 additions and 906 deletions.
506 changes: 250 additions & 256 deletions sympde/calculus/core.py

Large diffs are not rendered by default.

146 changes: 146 additions & 0 deletions sympde/calculus/tests/test_calculus.py
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,121 @@
from sympde.topology import ProductSpace
from sympde.topology import element_of, elements_of

#==============================================================================
@pytest.mark.parametrize('dim', [1, 2, 3])
def test_Dot(dim):

domain = Domain('Omega', dim=dim)
W = VectorFunctionSpace('W', domain)
a, b, c = elements_of(W, names='a, b, c')
r = Constant('r')

# Commutativity (symmetry)
assert dot(a, b) == dot(b, a)

# Bilinearity: vector addition
assert dot(a, b + c) == dot(a, b) + dot(a, c)
assert dot(a + b, c) == dot(a, c) + dot(b, c)

# Bilinearity: scalar multiplication
assert dot(a, r * b) == r * dot(a, b)
assert dot(r * a, b) == r * dot(a, b)

# Special case: null vector
assert dot(a, 0) == 0
assert dot(0, a) == 0

# Special case: two arguments are the same
assert dot(a, a).is_real
assert dot(a, a).is_positive

# TODO: check exceptions

#==============================================================================
@pytest.mark.parametrize('dim', [1, 2, 3])
def test_Cross(dim):

domain = Domain('Omega', dim=dim)
W = VectorFunctionSpace('W', domain)
a, b, c = elements_of(W, names='a, b, c')
r = Constant('r')

# Anti-commutativity (anti-symmetry)
assert cross(a, b) == -cross(b, a)

# Bilinearity: vector addition
assert cross(a, b + c) == cross(a, b) + cross(a, c)
assert cross(a + b, c) == cross(a, c) + cross(b, c)

# Bilinearity: scalar multiplication
assert cross(a, r * b) == r * cross(a, b)
assert cross(r * a, b) == r * cross(a, b)

# Special case: null vector
assert cross(a, 0) == 0
assert cross(0, a) == 0

# Special case: two arguments are the same
assert cross(a, a) == 0

# TODO: check exceptions

#==============================================================================
@pytest.mark.parametrize('dim', [1, 2, 3])
def test_Inner(dim):

domain = Domain('Omega', dim=dim)
W = VectorFunctionSpace('W', domain)
a, b, c = elements_of(W, names='a, b, c')
r = Constant('r')

# Commutativity
assert inner(a, b) == inner(b, a)

# Bilinearity: vector addition
assert inner(a, b + c) == inner(a, b) + inner(a, c)
assert inner(a + b, c) == inner(a, c) + inner(b, c)

# Bilinearity: scalar multiplication
assert inner(a, r * b) == r * inner(a, b)
assert inner(r * a, b) == r * inner(a, b)

# Special case: null vector
assert inner(a, 0) == 0
assert inner(0, a) == 0

# Special case: two arguments are the same
assert inner(a, a).is_real
assert inner(a, a).is_positive

# TODO: check exceptions

#==============================================================================
@pytest.mark.parametrize('dim', [1, 2, 3])
def test_Outer(dim):

domain = Domain('Omega', dim=dim)
W = VectorFunctionSpace('W', domain)
a, b, c = elements_of(W, names='a, b, c')
r = Constant('r')

# Not commutative
assert outer(a, b) != outer(b, a)

# Bilinearity: vector addition
assert outer(a, b + c) == outer(a, b) + outer(a, c)
assert outer(a + b, c) == outer(a, c) + outer(b, c)

# Bilinearity: scalar multiplication
assert outer(a, r * b) == r * outer(a, b)
assert outer(r * a, b) == r * outer(a, b)

# Special case: null vector
assert outer(a, 0) == 0
assert outer(0, a) == 0

# TODO: check exceptions

#==============================================================================
def test_zero_derivative():

Expand Down Expand Up @@ -69,6 +184,27 @@ def test_zero_derivative():
assert convect(G, Rational(6, 7)) == 0 # sympy Rational
assert convect(G, Constant('a')) == 0 # sympde Constant

# Poisson's bracket in 2D
domain = Domain('Omega', dim=2)
V = ScalarFunctionSpace('V', domain)
u = element_of(V, name='V')

assert bracket(u, 1) == 0 # native int
assert bracket(u, 2.3) == 0 # native float
assert bracket(u, 4+5j) == 0 # native complex
assert bracket(u, Integer(1)) == 0 # sympy Integer
assert bracket(u, Float(2.3)) == 0 # sympy Float
assert bracket(u, Rational(6, 7)) == 0 # sympy Rational
assert bracket(u, Constant('a')) == 0 # sympde Constant

assert bracket(1 , u) == 0 # native int
assert bracket(2.3 , u) == 0 # native float
assert bracket(4+5j , u) == 0 # native complex
assert bracket(Integer(1) , u) == 0 # sympy Integer
assert bracket(Float(2.3) , u) == 0 # sympy Float
assert bracket(Rational(6, 7), u) == 0 # sympy Rational
assert bracket(Constant('a') , u) == 0 # sympde Constant

#==============================================================================
def test_calculus_2d_1():
domain = Domain('Omega', dim=2)
Expand Down Expand Up @@ -126,6 +262,16 @@ def test_calculus_2d_1():
assert( rot(alpha*F + beta*G) == alpha*rot(F) + beta*rot(G) )
# ...

# ... Poisson's bracket properties
assert bracket(alpha * f, g) == alpha * bracket(f, g)
assert bracket(f, alpha * g) == alpha * bracket(f, g)
assert bracket(f + h, g) == bracket(f, g) + bracket(h, g)
assert bracket(f, g + h) == bracket(f, g) + bracket(f, h)
assert bracket(f, f) == 0
assert bracket(f, g) == -bracket(g, f)
assert bracket(f, g * h) == g * bracket(f, h) + bracket(f, g) * h
# ...

#==============================================================================
def test_calculus_2d_2():
domain = Domain('Omega', dim=2)
Expand Down
83 changes: 4 additions & 79 deletions sympde/expr/basic.py
Original file line number Diff line number Diff line change
@@ -1,65 +1,14 @@
# coding: utf-8

from itertools import groupby

from sympy.core import Basic
from sympy.core import Symbol
from sympy.core import Function
from sympy.simplify.simplify import simplify
from sympy import collect
from sympy.series.order import Order
from sympy.core import Expr, Add, Mul, Pow
from sympy import S
from sympy.core import Expr
from sympy.core.containers import Tuple
from sympy import Indexed, IndexedBase, Matrix, ImmutableDenseMatrix
from sympy import expand
from sympy import Integer, Float
from sympy.core.expr import AtomicExpr
from sympy.physics.quantum import TensorProduct
from sympy.series.series import series
from sympy.core.compatibility import is_sequence

from sympde.core.basic import _coeffs_registery
from sympde.core.basic import CalculusFunction
from sympde.core.basic import Constant
from sympde.core.algebra import (Dot_1d,
Dot_2d, Inner_2d, Cross_2d,
Dot_3d, Inner_3d, Cross_3d)
from sympde.core.utils import random_string

from sympde.calculus import Dot, Inner, Cross
from sympde.calculus import Grad, Rot, Curl, Div
from sympde.calculus import Bracket
from sympde.calculus import Laplace
from sympde.calculus.core import _generic_ops

from sympde.topology import BasicDomain, Domain, MappedDomain, Union, Interval
from sympde.topology import BoundaryVector, NormalVector, TangentVector, Boundary
from sympde.topology.derivatives import _partial_derivatives
from sympde.topology.derivatives import partial_derivative_as_symbol
from sympde.topology.derivatives import sort_partial_derivatives
from sympde.topology.derivatives import get_atom_derivatives
from sympde.topology.derivatives import dx, dy, dz
from sympde.topology.derivatives import (Grad_1d, Div_1d,
Grad_2d, Curl_2d, Rot_2d, Div_2d,
Grad_3d, Curl_3d, Div_3d)
from sympde.topology.derivatives import Bracket_2d
from sympde.topology.derivatives import Laplace_1d, Laplace_2d, Laplace_3d
from sympde.topology.derivatives import Hessian_1d, Hessian_2d, Hessian_3d
from sympde.topology.space import BasicFunctionSpace

from sympde.core.basic import Constant
from sympde.topology.space import ScalarFunctionSpace,VectorFunctionSpace
from sympde.topology.space import ProductSpace
from sympde.topology.space import ScalarTestFunction
from sympde.topology.space import VectorTestFunction
from sympde.topology.space import IndexedTestTrial
from sympde.topology.space import Unknown, VectorUnknown
from sympde.topology.space import Trace
from sympde.topology.space import ScalarField, VectorField, IndexedVectorField
from sympde.topology.measure import CanonicalMeasure
from sympde.topology.measure import CartesianMeasure
from sympde.topology.measure import Measure


from sympde.topology.space import ScalarField, VectorField

#==============================================================================
def _sanitize_arguments(arguments, is_bilinear=False, is_linear=False):
Expand Down Expand Up @@ -116,30 +65,6 @@ def _sanitize_arguments(arguments, is_bilinear=False, is_linear=False):

return args

#==============================================================================
def is_linear_form(expr, args):
"""checks if an expression is linear with respect to the given arguments."""
# ...
test_functions = _sanitize_arguments(args, expr, is_linear=True)
# TODO is it ok to do this?
test_functions = test_functions[0]

if isinstance(test_functions, (ScalarTestFunction, VectorTestFunction)):
test_functions = [test_functions]

elif isinstance(test_functions, (tuple, list, Tuple)):
test_functions = list(*test_functions)
# ...

# ...
if not is_linear_expression(expr, test_functions):
msg = ' Expression is not linear w.r.t [{}]'.format(test_functions)
raise UnconsistentLinearExpressionError(msg)
# ...

return True


#==============================================================================
class BasicExpr(Expr):
is_Function = True
Expand Down
78 changes: 26 additions & 52 deletions sympde/expr/evaluation.py
Original file line number Diff line number Diff line change
@@ -1,85 +1,59 @@
# coding: utf-8

from itertools import groupby
from itertools import product

from sympy.core import Basic
from sympy.core import Symbol
from sympy.core import Function
from sympy.simplify.simplify import simplify
from sympy import collect
from sympy.series.order import Order
from sympy.core import Expr, Add, Mul, Pow
from sympy import S
from sympy.core.containers import Tuple
from sympy import Indexed, IndexedBase, Matrix, ImmutableDenseMatrix
from sympy import Indexed, Matrix, ImmutableDenseMatrix
from sympy import expand
from sympy import Integer, Float
from sympy.core import Basic
from sympy.core import Add, Mul, Pow
from sympy.core.expr import AtomicExpr
from sympy.physics.quantum import TensorProduct
from sympy.series.series import series
from sympy.core.containers import Tuple
from sympy.simplify.simplify import simplify

from sympde.core.basic import _coeffs_registery
from sympde.core.basic import CalculusFunction
from sympde.core.basic import Constant
from sympde.core.algebra import (Dot_1d,
Dot_2d, Inner_2d, Cross_2d,
Dot_3d, Inner_3d, Cross_3d)
Dot_2d, Inner_2d, Cross_2d,
Dot_3d, Inner_3d, Cross_3d)
from sympde.core.utils import random_string

from sympde.calculus import Dot, Inner, Cross
from sympde.calculus import Grad, Rot, Curl, Div
from sympde.calculus import Bracket
from sympde.calculus import Laplace
from sympde.calculus import jump, avg, minus, plus
from sympde.calculus import Jump, Average
from sympde.calculus import NormalDerivative
from sympde.calculus import Jump
from sympde.calculus.core import _generic_ops

from sympde.topology import BasicDomain, Domain, MappedDomain, Union, Interval
from sympde.topology import BoundaryVector, NormalVector, TangentVector
from sympde.topology import Boundary, Connectivity, Interface
from sympde.topology import BasicDomain, Union, Interval
from sympde.topology import NormalVector, TangentVector
from sympde.topology import Boundary, Interface
from sympde.topology import InteriorDomain
from sympde.topology import DetJacobian
from sympde.topology import SymbolicDeterminant
from sympde.topology import LogicalExpr
from sympde.topology.space import ScalarFunctionSpace
from sympde.topology.space import ScalarTestFunction
from sympde.topology.space import VectorTestFunction
from sympde.topology.space import IndexedTestTrial
from sympde.topology.space import Trace
from sympde.topology.space import element_of
from sympde.topology.space import VectorField
from sympde.topology.derivatives import _partial_derivatives
from sympde.topology.derivatives import _logical_partial_derivatives
from sympde.topology.derivatives import partial_derivative_as_symbol
from sympde.topology.derivatives import sort_partial_derivatives
from sympde.topology.derivatives import get_atom_derivatives
from sympde.topology.derivatives import get_atom_logical_derivatives
from sympde.topology.derivatives import dx, dy, dz
from sympde.topology.derivatives import dx1, dx2, dx3
from sympde.topology.derivatives import (Grad_1d, Div_1d,
Grad_2d, Curl_2d, Rot_2d, Div_2d,
Grad_3d, Curl_3d, Div_3d)

from sympde.topology.derivatives import Bracket_2d
from sympde.topology.derivatives import Laplace_1d, Laplace_2d, Laplace_3d
from sympde.topology.derivatives import Hessian_1d, Hessian_2d, Hessian_3d
from sympde.topology.space import BasicFunctionSpace
from sympde.topology.space import ScalarFunctionSpace
from sympde.topology.space import ProductSpace
from sympde.topology.space import ScalarTestFunction
from sympde.topology.space import VectorTestFunction
from sympde.topology.space import IndexedTestTrial
from sympde.topology.space import Unknown, VectorUnknown
from sympde.topology.space import Trace
from sympde.topology.space import element_of
from sympde.topology.space import ScalarField, VectorField, IndexedVectorField
from sympde.topology.measure import CanonicalMeasure
from sympde.topology.measure import CartesianMeasure
from sympde.topology.measure import Measure
from sympde.topology import Mapping, DetJacobian
from sympde.topology import SymbolicDeterminant, SymbolicCovariant, SymbolicContravariant

from sympde.topology import LogicalExpr

from .basic import BasicExpr, BasicForm
from .expr import LinearExpr, BilinearExpr
from .expr import LinearForm, BilinearForm, Norm
from .equation import Equation
from .expr import DomainIntegral, BoundaryIntegral, InterfaceIntegral
from .expr import Functional
from .expr import _get_domain
from .basic import BasicExpr, BasicForm
from .expr import BilinearForm
from .expr import DomainIntegral, BoundaryIntegral, InterfaceIntegral
from .expr import Functional
from .expr import _get_domain

#==============================================================================
def is_sequence(a):
Expand Down
Loading

0 comments on commit 8796094

Please sign in to comment.