Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

WIP : Vector module #2208

Closed
wants to merge 62 commits into from
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
62 commits
Select commit Hold shift + click to select a range
5a86cbd
Started off with the project. CoordSys super class been worked on,
Jun 23, 2013
ea4f464
More conversion methods, helpers addded
Jun 24, 2013
b18c234
Added Vector, VectAdd, VectMul
Jun 25, 2013
ef7f16b
Added some more helpers for the separate method
Jul 2, 2013
0ede0a9
Corrected separate functions to return dict
Jul 2, 2013
3a9a3bb
Fixed some typos, a few helpers
Jul 2, 2013
38616f5
Added arithmatic methods, some more helpers.
Jul 4, 2013
07cdc4b
Merge remote-tracking branch 'upstream/master' into vector
Jul 4, 2013
8c69063
Changed the design so that base scalar and base vectors cannot be
Jul 11, 2013
d109843
Merge remote-tracking branch 'upstream/master' into vector
Jul 11, 2013
f9cd6f8
Added some more helpers for `express` method.
Jul 15, 2013
58e8212
Merge remote-tracking branch 'upstream/master' into vector
Jul 15, 2013
9dccbef
Position is now a vector. Some basic funcitonality is working.
Jul 23, 2013
4edc216
Merge remote-tracking branch 'upstream/master' into vector
Jul 23, 2013
5437537
Corrected many small errors, bugs. Added ZeroVector
Jul 24, 2013
41653d3
Merge remote-tracking branch 'upstream/master' into vector
Jul 24, 2013
df4dc80
Fixed some methods
Jul 25, 2013
d175318
Started to clean up vector.py
gilbertgede Jul 22, 2013
8c75640
Changes to BaseScalar
gilbertgede Jul 22, 2013
9151bd0
Removed extraneous function in Vector
gilbertgede Jul 22, 2013
2303c97
Introduced BaseVector class.
gilbertgede Jul 22, 2013
5c07b6a
Rectified certain errors
srjoglekar246 Jul 23, 2013
bf92b9f
Changed the implementation of many methods. Also, changed the separat…
Jul 28, 2013
80b1e19
Merge branch 'vector' into vector_temp
Jul 28, 2013
2cf396a
Made several changes to the express method. Added some helpers of
Aug 5, 2013
58a1900
Merge remote-tracking branch 'upstream/master' into vector
Aug 5, 2013
d7a0529
Merge remote-tracking branch 'upstream/master' into vector
Aug 5, 2013
74b103c
Merge remote-tracking branch 'origin/vector' into vector
Aug 6, 2013
c20ca69
Added more helpers for the express method
Aug 9, 2013
3deb413
Added helpers for changing base vectors and for base scalars.
Aug 9, 2013
4adeb0b
Completed express - testing remains.
Aug 10, 2013
4a0abbb
Merge remote-tracking branch 'upstream/master' into vector
Aug 10, 2013
2aac647
Added a grad method. Added a few helpers.
Aug 12, 2013
2113754
Merge remote-tracking branch 'upstream/master' into vector
Aug 12, 2013
e1767cd
Added a method for cross product of vectors along with requied helpers.
Aug 13, 2013
2f90523
Added methods for div, curl, laplacian with some minor changes.
Aug 14, 2013
ae81fe0
Added the paramregion.py file. Started working on the ParamRegion class.
Aug 15, 2013
03b6afd
Renamed param_region.py to integrate.py
Aug 17, 2013
3af44d8
Added differentiation method for vector. Did some work on Surface
Aug 19, 2013
0461abe
Started performing tests.
Aug 21, 2013
15cd547
Merge remote-tracking branch 'upstream/master' into vector
Aug 21, 2013
aff8d75
Fixed several bugs in the testing.
Aug 26, 2013
a7bcb78
Changed args to be ()
Aug 28, 2013
28cb657
Added _hashable_content to BaseScalar and BaseVector.
Aug 29, 2013
bd79374
Added some temporary hacks to make things work for a test.
Sep 2, 2013
047c772
Initial version of express method now works.\
Sep 2, 2013
73fee43
Express method is finally working.
Sep 6, 2013
2f4e1e3
The dot and cross methods work now.
Sep 8, 2013
2e9f9b6
Merge remote-tracking branch 'upstream/master' into vector
Sep 8, 2013
e202558
The orientation methods are working now.
Sep 8, 2013
e2e02c2
Added docstrings and doctests.
Sep 18, 2013
e5be839
Merge remote-tracking branch 'upstream/master' into vector
Sep 18, 2013
bdfcc78
Added more docsrtings and doctests. Corrected the orientnew method.
Sep 19, 2013
4606ac5
Added more docstrings and doctests.
Sep 21, 2013
c8ff5dd
Merge remote-tracking branch 'upstream/master' into vector
Sep 21, 2013
07f810c
Made some changes to posnew method
Oct 3, 2013
d75be68
Added a flag in the definition of CoordSys.
Oct 4, 2013
0a0cfd7
Merge remote-tracking branch 'upstream/master' into vector
Oct 4, 2013
5b10aa8
Divergence now working.
Oct 7, 2013
e742bbb
Merge remote-tracking branch 'upstream/master' into vector
Oct 14, 2013
6211d3e
The grad method is now working.
Oct 14, 2013
f36c3e0
Curl of a vector is now working correctly.
Oct 28, 2013
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions sympy/core/basic.py
Original file line number Diff line number Diff line change
Expand Up @@ -70,6 +70,7 @@ class Basic(with_metaclass(ManagedProperties)):
is_Boolean = False
is_Not = False
is_Matrix = False
is_Vector = False
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Why do you need this?

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I see that @srjoglekar246 said:

Do remember to add is_Vector to Basic

I do not see why you need this.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Since we are making it a part of the SymPy architecture, its better to do this, I think. It makes my code (as well as Prasoon's) more consistent with the rest of SymPy's handling of Basic entities, in the sense of using 'if instance.is_Something:'
Does this create any problems that we may be overlooking?

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Is there any good reason not to use isinstance? The problem is that you should not need to change the superclass when writing a new subclass.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

There isn't any problem as such, we just decided to follow convention. As I recall, for eg, is_Boolean, is_Not were added to Basic when the logic module was formed. This is just on the lines of that. We could remove the line, if you insist.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is the way it's been done in SymPy. Whether this design decision is a good one or not is beside this PR.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I do not know why these flags were added, but if you do not have a reason to write something it is better not to write it. In the same way, if you do not know why a convention is put in place do not follow it blindly. Most of those is_* flags are there as workaround for bad class structure.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It's fine to not add this. isinstance is better.


def __new__(cls, *args):
obj = object.__new__(cls)
Expand Down
5 changes: 5 additions & 0 deletions sympy/vector/__init__.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
from vector import (base_scalars, vectors, dot, cross, _all_coordinate_systems,
_separate_to_vectors, express, is_const_vect)

from vector import (BaseScalar, CoordSys, CoordSysRect, CoordSysCyl,
CoordSysSph, Vector, VectAdd, VectMul, ZeroVector, BaseVector)
218 changes: 218 additions & 0 deletions sympy/vector/integrate.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,218 @@
from sympy.core import (Basic, Expr, Symbol, symbols, sympify, diff, Pow, Mul,
Add, S)
from sympy.integrals.integrals import integrate, Integral
from sympy.vector.vector import (_all_coordinate_systems, _all_base_scalars,
_vect_add, _vect_mul, _coord_sys_scalar_list,
_has_base_scalar)
from sympy.vector.vector import (dot, cross, express, grad, div, curl,
laplacian)
from sympy.vector.vector import (BaseScalar, Vector, BaseVector, VectMul,
ZeroVector)


class ParamRegion(object):
"""
A class to represent parametric region in space
"""
def __init__(self, params, coord_sys, definition, bounds):
"""
Create a ParamRegion object to represent a parametrically defined
region in space.
params : A tuple of length <=2. Both elements of the tuple are symbols
that act as parameters.
coord_sys : an instance of subclass of the CoordSys class.
definition : a tuple of length 3. Each element corresponds to the
paramentric definition of the BaseScalars for the coord_sys
bounds : a tuple of 2 tuples. Each inner tuple has 2 elements which
act as bounds for the Symbols in params, respectively.
"""
# sanity check
if not len(params) <= 2:
raise ValueError("params should be a tuple of length 2")
if(not isinstance(params[0], Symbol) or
not isinstance(params[1], Symbol)):
raise ValueError("all elements of params should be SymPy Symbols")
if not len(definition) == 3:
raise ValueError("definition is a tuple of length 3")

# Let's call the first parameter 'u' and the second 'v'
if len(params) == 1:
self._u = params[0]
elif len(params) == 2:
self._u = params[0]
self._v = params[1]

self.coord_sys = coord_sys
self.definition = definition

@property
def u(self):
return self._u

@property
def v(self):
return self._v


class VectIntegral(object):
"""
Base class for representing different type of integrals of vector fields.
Not to be initialized directly by the user.
"""
def __init__(self, vect, param_region):
self.vect = vect
self.param_region = param_region

# More methods that are common to all vector integral classes will go here.


class LineVectIntegral(VectIntegral):
"""
A container for holding line intergrals of vector fields.
Holds the vector field and the ParamRegion objects.

Not to be initialized directly. An instance of this class is returned
by the integrate method on vectors.
"""
def __init__(self, vect, param_region, coord_sys):
# The integral must be of the type F.dl
super(LineVectIntegral, self).__init__(vect, param_region)

def eval(self):
"""
Evaluate the integral symbolically, if possible. Else, return the
LineVectIntegral object back.
"""
vect = self.vect.express(self.param_region.coord_sys)
# calculate the differential length element for coord_sys
dl = self.param_region.coord_sys.h_list
base_scalars = self.param_region.coord_sys.base_scalars
# Calculate differntials for each of the elements of dl using
# the definitions in the param_region object
# Also note that because this is a F.dl type integral, therefore,
# there is only one parameter; self.param_region.
for i in range(len(dl)):
dl[i] = diff(self.param_region.definition[i], self.param_region.u)

# Now since vect and dl are in the same coorfinates, we have:
comp = vect.components
expr = S.Zero
for i in range(len(dl)):
expr = expr + (comp[i] * dl[i])
# Now, expr has been completely express in coord_sys. We just need to
# change everything to the parametric variable, 'u'
for i, scalar in enumerate(base_scalars):
subs_dict = {scalar: self.param_region.definition[i]}
expr = expr.subs(subs_dict)

# Now, we can integrate the expression just as any regular integral
bounds = self.param_region.bounds
res = integrate(expr,
(self.param_region.u, bounds[0][0], bounds[0][1]))
if not isinstance(res, Integral):
return res
return self


class SurfaceVectIntegral(VectIntegral):
"""
A container for holding surface intergrals of vector fields.
Holds the vector field and the ParamRegion objects.

Not to be initialized directly. An instance of this class is returned
by the integrate method on vectors.
"""
def __init__(self, vect, param_region):
# The integral must be of the type F.dl
super(LineVectIntegral, self).__init__(vect, param_region)

def eval(self):
vect = self.vect.express(self.param_region.coord_sys)
# First, we need to calculate dS (differntial surface element vector)
# if r(u, v) is the position vector of any point on the surface
# normal = (d/du)r x (d/dv)r
r = ZeroVector
base_vectors = self.param_region.coord_sys.base_vectors
for i in range(len(base_vectors)):
r = r + self.param_region.definitions[i] * base_vectors[i]

r = r.expand()
r_u = r.diff(self.param_region.u)
r_v = r.diff(self.param_region.v)

# TODO : Implement normalize
n = cross(r_u, r_v)
# http://en.wikipedia.org/wiki/Surface_integral
vect_dot_n = dot(vect, n, self.param_region.coord_sys.param_region)

# Now we need to calculate double_integral( vect_dot_n du dv )
bounds = self.param_region.bounds

# Check the bounds to ascertain the order
# Case 1 : Both bounds are constants - can perform either order
# Case 2 : Bounds for u are in terms of v : integrate wrt to u first
# Case 3 : Bounds for v are in terms of u : integrate wrt to v first
case = _bounds_case(bounds, self.param_region.u, self.param_region.v)
if case == 1 or case == 2:
res = integrate(vect_dot_n,
(self.param_region.u, bounds[0][0], bounds[0][1]),
(self.param_region.v, bounds[1][0], bounds[1][1]))
if not isinstance(res, Integral):
return res
elif case == 2:
return self

if case == 1 or case == 3:
res = integrate(vect_dot_n,
(self.param_region.v, bounds[0][0], bounds[0][1]),
(self.param_region.u, bounds[1][0], bounds[1][1]))
if not isinstance(res, Integral):
return res

# Integral couldn't be evaluated
return self

def _bounds_case(bounds, u, v):
"""
Check whether the given bounds depend on variables of integration and
return the correct case.
"""
# Check bounds of u for v
lower = bounds[0][0]
upper = bounds[0][1]

atoms_lower = lower.atoms()
atoms_upper = upper.atoms()
if atoms_lower.issuperset(set([v])) or atoms_upper.issuperset(set([v])):
return 2

# Check bounds of v for u
lower = bounds[1][0]
upper = bounds[1][1]

atoms_lower = lower.atoms()
atoms_upper = upper.atoms()
if atoms_lower.issuperset(set([u])) or atoms_upper.issuperset(set([u])):
return 3

# No bounds occur in the other. Bounds are constants.
return 1

def vect_integrate(vect, param_region):
"""
Takes an object with is_Vector == True and a ParamRegion object and
retuns an instance of the appropriate subclass of VectIntegral class.
vect : an is_Vector == True object
param_region : a ParamRegion object
coord_sys : an instance of subclass of CoordSys class
"""
# First check if type of the integral
if hasattr(param_region, '_u') and not hasattr(param_region, '_v'):
# Integral is of type F.dl
obj = LineVectIntegral(vect, param_region)
elif hasattr(param_region, '_u') and hasattr(param_region, '_v'):
# Integral is a of type F.dS (surface integral)
obj = SurfaceVectIntegral(vect, param_region)
# We can also consider cases with scalar*vector type integral
# TODO: Implement the above comment
return obj
Loading