Implementation of class to represent a parametric region in space#19472
Conversation
The class ParametricRegion represents a parametric region in space. Objects of this class will used to perform vector/scalar integration.
|
✅ Hi, I am the SymPy bot (v160). I'm here to help you write a release notes entry. Please read the guide on how to write release notes. Your release notes are in good order. Here is what the release notes will look like: This will be added to https://github.com/sympy/sympy/wiki/Release-Notes-for-1.7. Note: This comment will be updated with the latest check if you edit the pull request. You need to reload the page to see it. Click here to see the pull request description that was parsed.
Update The release notes on the wiki have been updated. |
🟠Hi, I am the SymPy bot (v160). I've noticed that some of your commits add or delete files. Since this is sometimes done unintentionally, I wanted to alert you about it. This is an experimental feature of SymPy Bot. If you have any feedback on it, please comment at sympy/sympy-bot#75. The following commits add new files: If these files were added/deleted on purpose, you can ignore this message. |
| >>> from sympy.vector import CoordSys3D, ParametricRegion | ||
| >>> r, theta = symbols("r theta") | ||
| >>> C = CoordSys3D('C') | ||
| >>> circle = ParametricRegion(C, r*cos(theta), r*sin(theta), (theta, 0, 2*pi)) |
There was a problem hiding this comment.
Is the parametric region defined within a CoordSys3D object? Can this be made optional? It's easier to use if you don't have to define too many objects.
There was a problem hiding this comment.
Yes, It will be easier if a user does not have to pass the CoordSys3D object. But we need to determine base scalars otherwise the definition of a parametric region is incomplete. A parametric representation is just defining base scalars in terms of some parameters.
We can avoid passing the CoordSys3D object if we use the base scalars of the vector/scalar field which needs to be integrated. So, if a user does not pass a CoordSys3D object, then SymPy will use the base scalars of the vector/scalar field used for integration.
C = CoordSys3D('C')
R = C.locate_new('R', 3*C.i + 4*C.j + 5*C.k)
p = ParametricRegion(t, t**2, (t, 0, 1))
ParametricIntegral(C.x*C.y*C.z*C.i, p) # Define p in terms of C.x, C.y and C.z
ParametricIntegral(R.x*R.y, p) # Define p in terms of R.x, R.y and R.z There was a problem hiding this comment.
What about using a convention similar to Lambda?
Subclasses of basic should use __new__ instead of __init__ Also, removed check for length of defintion
| >>> r, theta = symbols("r theta") | ||
| >>> circle = ParametricRegion(r*cos(theta), r*sin(theta), (theta, 0, 2*pi)) | ||
| """ | ||
| def __new__(cls, *args, system=None): |
There was a problem hiding this comment.
What about defining some precise signature? *args is a bit ambiguous.
There was a problem hiding this comment.
Yes, *arg is ambiguous. I used so we can define base scalars and bounds without nesting them in a tuple.
There was a problem hiding this comment.
what about def __new__(cls, parameters_or_coordsys, mapping_tuple, **kwargs): ?
There was a problem hiding this comment.
ParametricRegion((r, theta), (r*cos(theta), r*sin(theta)), r=(0,1), theta=(0, pi))
ParametricRegion(C, (C.y, 3, -3), C.y=(4,6))I don't think the User should pass a tuple of parameters or CoordSys3d object.
We can easily determine the parameters using key values of the dictionary.
But we should also add an optional parameter for specifying the base scalars(see discussion above on CoordSys3D object) if a user does not want to user base scalars of the scalar/vector field. You mentioned using some lambda convention. Please explain that part.
What about this API @Upabjojr ?
def __new__(cls, system=None, mapping_tuple, **kwargs): Example
ParametricRegion(((r*cos(theta), r*sin(theta)), r=(0,1), theta=(0, pi))
ParametricRegion(system=C, (C.y, 3, -3), C.y=(4,6)) There was a problem hiding this comment.
r=(0, 1), theta=(0, pi) is not very intuitive, what about a dict of bounds?
What about this:
ParametricRegion((r, theta), (r*cos(theta), r*sin(theta)), limits={r: (0,1), theta: (0, pi)})
ParametricRegion(C, (C.y, 3, -3), limits={C.y: (4,6)}) You mentioned using some lambda convention. Please explain that part.
Define variable tuple, then mapping tuple.
There was a problem hiding this comment.
I am still not sure why a user needs to pass a tuple specifying parameters. SymPy can determine them using the dict of bounds. Will it be more intuitive for users?
ParametricRegion((r*cos(theta), r*sin(theta)), limits={r: (0,1), theta: (0, pi)})There was a problem hiding this comment.
Well, a dict does not have an order, while a tuple does. Plus, it's the same definition of lambdas:
lambda r, theta: (r*cos(theta), r*sin(theta))There was a problem hiding this comment.
+1 for passing parameter_tuple then.
There was a problem hiding this comment.
@Upabjojr What are your thoughts on the system parameter?
As discussed above, We have two options:
- Assume that the mapping of param region is to base vectors of the scalar/vector field.
p = ParametricRegion((r, theta), (r*cos(theta), r*sin(theta)), limits={r: (0,1), theta: (0, pi)})
Integral(C.x**2*C.y, p)
# C.x = r*cos(theta), C.y = r*sin(theta), C.z = C.z
Integral(R.x*R.y*R.z, p)
# R.x = r*cos(theta), R.y = r*sin(theta), R.z = R.z- The other option is to allow users if they wish to specify the coordinate system.
p = ParametricRegion((r, theta), (r*cos(theta), r*sin(theta)), limits={r: (0,1), theta: (0, pi)}, system = C)
Integral(R.x*R.y*R.z, p)
# C.x = r*cos(theta), C.y = r*sin(theta), C.z = C.z|
|
||
| def test_parametricregion(): | ||
|
|
||
| point = ParametricRegion(3, 4) |
There was a problem hiding this comment.
What about ParametricRegion((), (3, 4)) to define a point? That is... first argument is the tuple of parameters (in this case an empty tuple), second one the mapping.
I think this would be more intuitive. What do you think?
There was a problem hiding this comment.
@Upabjojr How will we get the definition of base scalars in terms of parameters? Also, if we fix the number of arguments to 2, we have to use nested tuples to define the bounds for more than 2 parameters
ParametricRegion((r, theta), ((r, 0, 2), (theta, 0, pi))There was a problem hiding this comment.
What about:
ParametricRegion(((r, 0, 2), (theta, 0, pi)), (r*cos(theta), r*sin(theta)))?
There was a problem hiding this comment.
I just want to have a simple API... my fear is that too many parameters will make this class difficult to use.
There was a problem hiding this comment.
This one looks good to me. It is still not very simple but we have to keep some minimum parameters. They are essential for defining a parametric region.
There was a problem hiding this comment.
It's the same concept for integrals:
Integral(x, x) # ==> indefinite
Integral(x, (x, 0, 10)) # ==> definiteIf you have a better API idea, you're welcome to suggest.
| assert point.bounds == [] | ||
| assert point.system == None | ||
|
|
||
| l = ParametricRegion(C.y, (C.y, -3, 3), system=C) |
There was a problem hiding this comment.
Maybe we could have either ParametricRegion((y,), (y, -3, 3)) or ParametricRegion(C, (C.y, -3, 3)).
That is, if the first argument is a tuple, then it's assumed to be a list of variable-parameters. If it is a CoordSys3D object, then use its scalars as parameters.
This means that ParametricRegion would always take 2 arguments when called. What do you think of this API?
There was a problem hiding this comment.
That is, if the first argument is a tuple, then it's assumed to be a list of variable-parameters. If it is a CoordSys3D object, then use its scalars as parameters.
Yes, this API looks simple and easy but
I am not able to understand what this region represents.
ParametricRegion(C, (C.y, -3, 3))For me, ParametricRegion(C.y, (C.y, -3, 3), system=C) represents the line y=x where y varies from -3 to 3. Does this represent the same region?
There was a problem hiding this comment.
For me,
ParametricRegion(C.y, (C.y, -3, 3), system=C)represents the line y=x where y varies from -3 to 3. Does this represent the same region?
Oh, I see. With ParametricRegion(C, (C.y, -3, 3)) I think of the line y = -3 and z = 3, with C.y being the parameter varying along the x-axis (x-axis because it's in the first position).
There was a problem hiding this comment.
line y = -3 and z = 3, with C.y being the parameter varying along the x-axis
I think we can define this region without using the coordinate scalar. How is this different from
ParametricRegion((t), (t, -3, 3))There was a problem hiding this comment.
(t) is not a tuple, (t,) is. Unfortunately Python has some strange syntax.
There was a problem hiding this comment.
Okay, I somehow didn't noticed this. Then, to make it easier for users, we can put a condition like
if not isinstance(parameters, tuple):
parameters = (parameters,)
if not isinstance(definition, tuple):
definition = (definition,)A similar situation if a user wants to define a definition tuple of length 1.
Or maybe we can raise some value error when the user does pass a tuple.
|
Also have a look at the image |
Yes, some parts of it can be used in this class. |
|
Tests keep falling. |
|
If you fix the tests, I will merge this. |
|
OK, I will fix the test and improve the docstring. |
…failing tests of core/test/test_args
Codecov Report
@@ Coverage Diff @@
## master #19472 +/- ##
=============================================
+ Coverage 75.656% 75.677% +0.020%
=============================================
Files 652 654 +2
Lines 169794 169934 +140
Branches 40086 40068 -18
=============================================
+ Hits 128460 128601 +141
Misses 35721 35721
+ Partials 5613 5612 -1 |
| assert ellipse.limits == {t: (0, 8)} | ||
|
|
||
| cylinder = ParametricRegion((r, theta, C.z), (cos(theta), r*sin(theta), C.z), {theta: (0, 2*pi), C.z: (0, 4)}) | ||
| assert cylinder.parameters == (r, theta, C.z) |
There was a problem hiding this comment.
I see you have introduced parameters_or_coordsys only because you have to deal with coordinate systems C, but as you mix coordinate scalars and ordinary symbols in this way, you can always specify the region regardless of the ambient space of the coordinate systems and it loses no generality to use ordinary symbols like x, y, z everywhere in place of coordinate systems.
And also what would be the necessary reason to pass C in place of (C.x, C.y, C.z) if they are implicitly converted any way?
There was a problem hiding this comment.
And also what would be the necessary reason to pass
Cin place of(C.x, C.y, C.z)if they are implicitly converted any way?
Shortcut?
There was a problem hiding this comment.
it loses no generality to use ordinary symbols like x, y, z everywhere in place of coordinate systems.
Yes, I agree. I think we can replace base scalars with any variable. Suppose we want to represent a rectangle:
ParametricRegion(C, (C.x, C.y), {C.x: (1, 2), C.y: (3, 5)})We can write equiavalently write this as
ParametricRegion((x, y), (x, y), {x: (1, 2), y: (3, 5)})
# C.x = x, C.y = y, C.z = C.zThere was a problem hiding this comment.
Just to make this explicit,
When we define the definition tuple ..suppose (r*cos(theta), r*(sin(theta), r*sin(phi)), this implies
C.x = r*cos(theta), C.y = r*(sin(theta), C.y = r*sin(phi)
These base scalars are assumed. They may be determined from the base scalars of the vector/scalar field for integration.
The only reason I think we may need a coordinate system variable other than for shortcut is when one needs to specify base scalars (instead of using base scalars of the vector/scalar field).
p = ParametricRegion((r, theta), (r*cos(theta), r*sin(theta)), limits={r: (0,1), theta: (0, pi)})
Integral(C.x**2*C.y, p)
# C.x = r*cos(theta), C.y = r*sin(theta), C.z = C.z
Integral(R.x*R.y*R.z, p)
# R.x = r*cos(theta), R.y = r*sin(theta), R.z = R.z
There was a problem hiding this comment.
What happens if it is Integral(R.x*C.y, p)?
Perhaps, p can have its own base scalars rather than implicitly connecting to some coordinate system scalars that are passed on?
There was a problem hiding this comment.
p can have its own base scalars rather than implicitly connecting to some coordinate system scalars that are passed on?
Yes, I am in favor of this. But there should be some relationship between the coordinate system of vector/scalar field and the coordinate system of the parametric region. For calculating the integral, we need to replace base scalars in the field with parameters. This requires some connection between them.
@Upabjojr What do you think?
There was a problem hiding this comment.
My original thought was just to use parameters. Mixing parameters and base scalars in the tests is a bit strange, but it's OK with me.
There was a problem hiding this comment.
I think for the tests, we can leave them as it is. But for users, it should be preferred to not mix them.
There was a problem hiding this comment.
What happens if it is Integral(R.x*C.y, p)?
We have to raise some kind of error if the parametric region is not associated with base scalars and depend on base scalars of the field.
|
@Upabjojr I think we can merge this PR. For now, we can assume that the parametric region has the same base scalars as that of the scalar/vector field. We can raise an error if the coordinate system of the field cannot be determined. |
Added an implementation of ParamRegion class.
References to other Issues or PRs
#19320
Brief description of what is fixed or changed
An object of the ParametricRegion class should represent a parametric region in space. This object can then be used to perform scalar/vector integration over parametric regions.
Other comments
Release Notes