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
Integration of polynomials over 2D polygons #12673
Conversation
Hi @ArifAhmed1995. Thanks for starting to work on this. The Travis failure seems unrelated (#12697). Would you mind creating some jupyter notebook with examples (and plots) how to use this? When you create new PRs, or just want my feedback, please tag me using @certik, then I'll get an email and can comment on your work. Let me know if you have any questions. |
I'm close to getting the 2D prototype working. Once that's done I'll create the notebook and add it to the |
Perfect! |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Also a test fails -- it could be perhaps caused by the 1/2
thing, per my other comment.
sympy/integrals/intpoly.py
Outdated
s = 0 | ||
for i in point.values(): | ||
s += i ** 2 | ||
return s**(1/2) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This is a common mistake, see http://docs.sympy.org/dev/gotchas.html#python-numbers-vs-sympy-numbers, you have to use S(1)/2
.
sympy/integrals/intpoly.py
Outdated
intersect[1] - x0[gens[1]])) | ||
if is_vertex(intersect): | ||
if isinstance(expr, Expr): | ||
value += distance_origin *\ |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
space before \
70137ba
to
25a4fe1
Compare
@certik The tests should pass now. I've made the notebooks and have discussed the existing limitations of the methods therein. |
@ndotsu, here is @ArifAhmed1995 latest code. |
sympy/integrals/intpoly.py
Outdated
xl, yl = list(), list() | ||
|
||
for vertex in poly.vertices: | ||
xl.append(vertex.x) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
It would be more efficient if you use xl = list(map((lambda vertex: vertex.x), poly.vertices))
, similarly for yl
.
sympy/integrals/intpoly.py
Outdated
""" | ||
if dims is None: | ||
if isinstance(expr, Expr): | ||
dims = list(expr.free_symbols) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Can we have tuple(expr.free_symbols)
? I don't think you are using mutability of dims
.
sympy/integrals/intpoly.py
Outdated
if isinstance(expr, Expr): | ||
dims = list(expr.free_symbols) | ||
else: | ||
dims = [x, y] |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
dims = tuple([x, y])
I would say, you should use |
sympy/integrals/intpoly.py
Outdated
return () | ||
|
||
|
||
def is_vertex(ent): |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This sounds like it should be some class-level variable is_Vertex
or is_vertex
.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
But how to do it for say (2, 3)
or (1, 2, 3)
? Plus , this function may be expanded in the future.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Ah, leave it then. May be you can have it for any sequence (why just tuple?).
sympy/integrals/intpoly.py
Outdated
expr: Denotes a polynomial(SymPy expression) | ||
""" | ||
from sympy.plotting.plot import plot3d, plot | ||
gens = list(expr.free_symbols) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
no need for a list
, can work with gens = expr.free_symbols
.
sympy/integrals/intpoly.py
Outdated
else: | ||
poly_dict[1] = expr | ||
else: | ||
poly_dict = {0: expr} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
better do poly_dict[0] = expr
, instead of a complete variable re-assignment.
@gxyd Thanks for the review ! I've made all but one of the changes. |
sympy/integrals/intpoly.py
Outdated
if isinstance(expr, Expr): | ||
dims = tuple(expr.free_symbols) | ||
else: | ||
dims = (x, y) | ||
|
||
if kwargs['clockwise'] is True: |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
You can use
clockwise = kwargs.get('clockwise', True)
if clockwise:
poly = ...
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Ah yes. I've made the change locally. There's a deficiency in the clockwise sort so I'll push the total changes after correcting that.
sympy/integrals/intpoly.py
Outdated
second = (b.x - center.x) * (b.x - center.x) + (b.y - center.y) * (b.y - center.y) | ||
return -1 if first > second else 1 | ||
|
||
return Polygon(*sorted(vertices, key = cmp_to_key(compareTo))) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Looks better if you have key=cmp_to_key(...)
i.e no space. https://www.python.org/dev/peps/pep-0008/#other-recommendations
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
In general, please do not use floating point numbers, but exact numbers, I commented on the places where I noticed it.
assert polytope_integrate(Polygon(Point(0, 0), Point(0, 1), | ||
Point(1, 1), Point(1, 0)), x * y) == 1/4 | ||
assert polytope_integrate(Polygon(Point(0, 3), Point(5, 3), Point(1, 1)), | ||
6*x**2 - 40*y) == float(-935)/3 |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Why is this a floating point number? We should try to compare to an exact number, i.e., -S(935)/3
.
assert polytope_integrate(Polygon(Point(0, 0), Point(0, 2), | ||
Point(4, 0)), 1, dims=(x, y)) == 4 | ||
assert polytope_integrate(Polygon(Point(0, 0), Point(0, 1), | ||
Point(1, 1), Point(1, 0)), x * y) == 1/4 |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
1/4
-> S(1)/4
assert best_origin((2, 1), 3, l1, expr1) == (0, 3.0) | ||
assert best_origin((2, 0), 3, l2, x ** 7) == (1.5, 0) | ||
assert best_origin((0, 2), 3, l3, x ** 7) == (0, 1.5) | ||
assert best_origin((1, 1), 2, l4, x ** 7 * y ** 3) == (0, 2.0) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Should return an exact number, not a floating point.
|
||
l1 = Segment2D(Point(0, 3), Point(1, 1)) | ||
l2 = Segment2D(Point(1.5, 0), Point(1.5, 3)) | ||
l3 = Segment2D(Point(0, 1.5), Point(3, 1.5)) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
1.5 -> S(3)/2
Also there seems to be a test failure at Travis:
|
0671e50
to
1093843
Compare
@certik I updated the code. The failing test runs fine locally :
|
@certik As mentioned in my blog post there are two major issues :
Should I go ahead and modify the existing polygon class to accommodate this class of polygons ?
|
@ArifAhmed1995 I thought @ndotsu already commented on this --- but I don't see his answer now. Let me find it. Regarding the remaining Travis failure (https://travis-ci.org/sympy/sympy/jobs/244146796), that is not related to this PR. |
@certik I've added the dynamic programming algorithm. This is a scalable technique and much faster than the standard one(200 - 300 times faster for higher power polynomials). I'll work on the intersecting polygon case now. |
Thanks @gxyd for the review and @ArifAhmed1995 for fixing it. If tests pass, this is now ok to merge with me. I have one last request. The commit d76be087beba0e974a72db92d4478a2ce9582d27 adds a binary notebook (with binary images) into the git history. I would prefer if you can remove it from that commit. In general, try to learn to create logical commits, so in the past, you should have created just one commit that adds the (binary) notebook, and not to lump it with some other changes in the code. Then it would be trivial to simply remove that commit now. The same thing when you removed the binary parts of the notebook --- you lumped that change with some other changes. You can edit the commits and remove it the binary notebook. Do you know how to do that? If not, you can either learn that (I think it's a very useful skill, you use |
The dictionary representations for best origin and direction parameter(w.r.t hyperplane) are changed to tuple/list form. This is because of discrepancies arising due to {x: a, y: b} and {y: b, x: a} referring to the same object. This change may be temporary or permanent depending on how scalable and robust it proves to be for the final 2D API and the 3D use case.
1. Use map function. 2. Use S.Zero instead of Python zero. 3. Use Tuple instead of List.
intpoly(): 1.decompose(): Returned dictionary also has constant with value 0. 2.integration_reduction(): Compute dot product directly --> only one recursive call. 3.polytope_integrate(): Add support for hyperplane representation. test_intpoly(): 1. Add tests for hyperplane representation. 2. Add tests(two XFAILs) from the paper by Chen et al.(2015)
The user can enter a list of polynomials to integrate over a polytope along with a maximum degree as input. Since all the monomial integrals are calculated once and re-used, the process is faster as compared to the case where each polynomial is computed individually.
On further testing the standard algorithm performed faster than the dynamic one. However, if the terms of the polynomial are such that every monomial's partial derivatives are present previously then dynamic is faster. Therefore, it is used for the multiple case, that is when a maximum degree is supplied and the values for a list of polynomials is to be calculated.
@certik Is it fine now ? |
It's better, but the commit 6ddbad1ca551cd651414b0a0ef14fe40d8403069 still adds binary data. To make it simple, just remove the notebook from 6ddbad1ca551cd651414b0a0ef14fe40d8403069 and just add the notebook in 1bbf991bb4121060f1bce4d431226a89e70a21f2, without the binary images. |
1. Add module docstring. 2. Change main function docstring. 3. Add comment for XFAIL tests. 4. Modify decompose function, use parameter as boolean 5. Modify hyperplane_parameters Add notebook
@certik This is done now, I hope. I will work on the intersecting polygon issue for one more day and then start on the 3D use-case. If the intersecting issue isn't solved today, I'll come back to it some other time. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This looks good, +1 from me. Thanks for fixing everything @ArifAhmed1995.
Arif,
The intersecting polygon case should work as is on the examples in the
paper - no special treatment is needed so long as the code works for any
nonconvex polygon (algorithm only `sees` the edges of the polygon).
…-suku.
On 7/8/17 11:38 PM, Arif Ahmed wrote:
@certik <https://github.com/certik> This is done now, I hope. I will
work on the intersecting polygon issue for one more day and then start
on the 3D use-case. If the intersecting issue isn't solved today, I'll
come back to it some other time.
—
You are receiving this because you were mentioned.
Reply to this email directly, view it on GitHub
<#12673 (comment)>, or
mute the thread
<https://github.com/notifications/unsubscribe-auth/AbwYKgmwNjhLpg35hTMu3__KLn89EGXRks5sL_bYgaJpZM4Nmzx0>.
--
N. Sukumar, Professor Work Phone: (530)754-6415
Department of Civil & Environmental Engg. FAX : (530)752-7872
3159 Ghausi Hall, One Shields Avenue E-mail: nsukumar@ucdavis.edu
University of California *GO BLAZERS*
Davis, CA 95616 WEB: http://dilbert.engr.ucdavis.edu/~suku
|
@ndotsu Yes, it will work once the It's not an issue with the current implementation but with the |
Okay, very good. In case you have not already, do take a look at
Section 5.4 in the paper for a discussion on this case.
On 7/9/17 11:02 AM, Arif Ahmed wrote:
@ndotsu <https://github.com/ndotsu> Yes, it will work once the
|Polygon| class in SymPy can handle intersecting polygons without
explicitly supplying those intersection points as input. I'm working
on it right now.
—
You are receiving this because you were mentioned.
Reply to this email directly, view it on GitHub
<#12673 (comment)>, or
mute the thread
<https://github.com/notifications/unsubscribe-auth/AbwYKmPd92DdCXaNho_INj5wMWvlPGgFks5sMJdBgaJpZM4Nmzx0>.
--
N. Sukumar, Professor Work Phone: (530)754-6415
Department of Civil & Environmental Engg. FAX : (530)752-7872
3159 Ghausi Hall, One Shields Avenue E-mail: nsukumar@ucdavis.edu
University of California *GO BLAZERS*
Davis, CA 95616 WEB: http://dilbert.engr.ucdavis.edu/~suku
|
Module for integrating uni/bivariate polynomials over 2-polytopes.