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

solvers: Fixed NoneType Error #18324

Merged
merged 3 commits into from
Feb 5, 2020
Merged

solvers: Fixed NoneType Error #18324

merged 3 commits into from
Feb 5, 2020

Conversation

sachin-4099
Copy link
Contributor

@sachin-4099 sachin-4099 commented Jan 13, 2020

Fixes #17882
Closes #18026

Brief description of what is fixed or changed:

Fixes an error in solvers.solvers.unrad() where it would return a TypeError: cannot unpack non-iterable NoneType object

Unrad() now returns the simplified numerator even when there are radicals left in the denominator, but since the numerator is free of radicals it seems logical to return the simplified numerator.

Example:

1) eq = -8*x**2/(9*(x**2 - 1)**(S(4)/3)) + 4/(3*(x**2 - 1)**(S(1)/3))
   a, b = unrad(eq)
OR
2) solveset(-8*x**2/(9*(x**2 - 1)**(S(4)/3)) + 4/(3*(x**2 - 1)**(S(1)/3)), x, S.Complexes)

Used to return: TypeError: cannot unpack non-iterable NoneType object

Now returns: 1) (4*x**2 - 12, []) and 2) FiniteSet(sqrt(3), -sqrt(3))

Other comments:
Added tests

Release Notes:

  • solvers
    • Fixed NoneType Error Bug in solvers.solvers.unrad()

@sympy-bot
Copy link

sympy-bot commented Jan 13, 2020

Hi, I am the SymPy bot (v149). 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.6.

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.

Fixes #17882
Closes #18026

**Brief description of what is fixed or changed:**

Fixes an error in solvers.solvers.unrad() where it would return a `TypeError: cannot unpack non-iterable NoneType object`

Unrad() now returns the simplified numerator even when there are radicals left in the denominator, but since the numerator is free of radicals it seems logical to return the simplified numerator.

**Example:**
```
1) eq = -8*x**2/(9*(x**2 - 1)**(S(4)/3)) + 4/(3*(x**2 - 1)**(S(1)/3))
   a, b = unrad(eq)
OR
2) solveset(-8*x**2/(9*(x**2 - 1)**(S(4)/3)) + 4/(3*(x**2 - 1)**(S(1)/3)), x, S.Complexes)
```
**Used to return:** `TypeError: cannot unpack non-iterable NoneType object`

**Now returns:** `1) (4*x**2 - 12, []) and 2) FiniteSet(sqrt(3), -sqrt(3))`

**Other comments:**
**Added tests**

**Release Notes:**
<!-- BEGIN RELEASE NOTES -->
* solvers
   *  Fixed NoneType Error Bug in solvers.solvers.unrad()

Update

The release notes on the wiki have been updated.

@sachin-4099
Copy link
Contributor Author

sachin-4099 commented Jan 13, 2020

Please review the PR @jksuom @oscarbenjamin .
If any changes are required please suggest
Otherwise the PR is ready to be merged.

@codecov
Copy link

codecov bot commented Jan 13, 2020

Codecov Report

Merging #18324 into master will increase coverage by 0.534%.
The diff coverage is 100%.

@@              Coverage Diff              @@
##            master    #18324       +/-   ##
=============================================
+ Coverage   75.002%   75.536%   +0.534%     
=============================================
  Files          649       643        -6     
  Lines       167347    167325       -22     
  Branches     39418     39440       +22     
=============================================
+ Hits        125514    126392      +878     
+ Misses       36299     35403      -896     
+ Partials      5534      5530        -4

@@ -178,6 +178,14 @@ def test_issue_11536():
assert solveset(0**x - 1, x, S.Reals) == FiniteSet(0)


def test_issue_17882():
equation = solveset(-8*x**2/(9*(x**2 - 1)**(4/3)) + 4/(3*(x**2 - 1)**(1/3)), x, S.Complexes)
equation = str(equation)
Copy link
Member

Choose a reason for hiding this comment

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

We should avoid using str for testing.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Should I implement an alternative approach??

Copy link
Member

Choose a reason for hiding this comment

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

Use rational numbers for the coefficients, like S(4)/3. You should be able to compare the solution exactly.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Can you rewrite the equation in the required way, so that I get a better idea?

Copy link
Member

Choose a reason for hiding this comment

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

Specifically, you should write the equation like
solveset(-8*x**2/(9*(x**2 - 1)**(S(4)/3)) + 4/(3*(x**2 - 1)**(S(1)/3)), x, S.Complexes)

Copy link
Member

@sylee957 sylee957 Jan 15, 2020

Choose a reason for hiding this comment

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

It looks like the issue is not resolved 'well'.
If you just want to stop investigating further and get over with the unevaluated result like
ConditionSet(x, Eq(-8x**2(x2 - 1)(-1.33333333333333)/9 + 4*(x2 - 1)(-0.333333333333333)/3, 0), S.Complexes), I would merge this soon.

But I would rather update the original post and keep the thread open, and make sure that it should resolve

  1. Some logic that leads to infinite recursions
  2. It should actually 'solve' the equation rather than returning conditionset.

Copy link
Member

@sylee957 sylee957 Jan 15, 2020

Choose a reason for hiding this comment

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

Actually, it looks like this is not resolving anything because your original test case
solveset(-8*x**2/(9*(x**2 - 1)**(4/3)) + 4/(3*(x**2 - 1)**(1/3)), x, S.Complexes)
works as same in the master.

It looks like you should actually get
solveset(-8*x**2/(9*(x**2 - 1)**(S(4)/3)) + 4/(3*(x**2 - 1)**(S(1)/3)), x, S.Complexes)
to work

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Ok, no issue.
But in my opinion, we can merge this and keep the thread open for further improvements.

Copy link
Member

Choose a reason for hiding this comment

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

No, unfortunately for the reason in #18324 (comment)

Copy link
Contributor Author

Choose a reason for hiding this comment

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

ok, i didn't observe this, i will start working on this immediately.

@sachin-4099
Copy link
Contributor Author

@jksuom in the original issue: #17882, was regarding a Nonetype error, but since the issue is already resolved, should we go ahead with this PR, and try to get:
solveset(-8*x**2/(9*(x**2 - 1)**(S(4)/3)) + 4/(3*(x**2 - 1)**(S(1)/3)), x, S.Complexes)
to work or the result shown is fine.
Shall we open a new issue regarding the maximum recursion depth exceeded error we encountered?

@jksuom
Copy link
Member

jksuom commented Jan 15, 2020

It seems that unrad should not have returned None as there are radicals in the expression. However, after some simplifications they are only in the denominator d:

eq, d = eq.as_numer_denom()

I think that unrad should return the simplified numerator eq even there are no radicals left. Maybe something like this:

--- a/sympy/solvers/solvers.py
+++ b/sympy/solvers/solvers.py
@@ -3460,7 +3460,7 @@ def _take(d, take_int_pow):
     # check for trivial case
     # - already a polynomial in integer powers
     if all(_Q(g) == 1 for g in gens):
-        return
+        return eq, []
     # - an exponent has a symbol of interest (don't handle)
     if any(g.as_base_exp()[1].has(*syms) for g in gens):
         return

@sachin-4099
Copy link
Contributor Author

a, b = unrad(eq)
was giving: TypeError: cannot unpack non-iterable NoneType object

whre eq = -8*x**2/(9*(x**2 - 1)**(4/3)) + 4/(3*(x**2 - 1)**(1/3))

Now after the above mentioned change by @jksuom, the issue is resolved.

@sachin-4099
Copy link
Contributor Author

@jksuom shall i go ahead with this or anything else needs to be changed?

@sachin-4099
Copy link
Contributor Author

It seems that unrad should not have returned None as there are radicals in the expression. However, after some simplifications they are only in the denominator d:

eq, d = eq.as_numer_denom()

I think that unrad should return the simplified numerator eq even there are no radicals left. Maybe something like this:

--- a/sympy/solvers/solvers.py
+++ b/sympy/solvers/solvers.py
@@ -3460,7 +3460,7 @@ def _take(d, take_int_pow):
     # check for trivial case
     # - already a polynomial in integer powers
     if all(_Q(g) == 1 for g in gens):
-        return
+        return eq, []
     # - an exponent has a symbol of interest (don't handle)
     if any(g.as_base_exp()[1].has(*syms) for g in gens):
         return

This is causing testcases to fail in solvers\ode.py

@sachin-4099
Copy link
Contributor Author

This is caused due to change in return type of unrad()

@jksuom
Copy link
Member

jksuom commented Jan 15, 2020

The equations of ode.py involve derivatives. Those are removed from poly.gens by _take to form gens. It seems that the algorithm expect None to be returned if there are such generators (i.e.,not all poly.gens are in gens). This can be handled by, for example,

--- a/sympy/solvers/solvers.py
+++ b/sympy/solvers/solvers.py
@@ -3460,7 +3460,10 @@ def _take(d, take_int_pow):
     # check for trivial case
     # - already a polynomial in integer powers
     if all(_Q(g) == 1 for g in gens):
-        return
+        if len(gens) == len(poly.gens):
+            return eq, []
+        else:
+            return
     # - an exponent has a symbol of interest (don't handle)
     if any(g.as_base_exp()[1].has(*syms) for g in gens):
         return

@sachin-4099
Copy link
Contributor Author

Still one testcase is failing:
sympy\solvers\solveset.py", line 1744, in sympy.solvers.solveset._transolve
Failed example: pprint(tsolve(f, x), use_unicode=False)

@jksuom
Copy link
Member

jksuom commented Jan 15, 2020

It looks like more conditions have to be added. That tsolve example created generators g with non-integer exponents. I had expected that the condition _Q(g) == 1 would suffice to reject those but apparently that is not true. The following seems to work in this case:

--- a/sympy/solvers/solvers.py
+++ b/sympy/solvers/solvers.py
@@ -3460,7 +3460,11 @@ def _take(d, take_int_pow):
     # check for trivial case
     # - already a polynomial in integer powers
     if all(_Q(g) == 1 for g in gens):
-        return
+        if (len(gens) == len(poly.gens) and
+            all(g.is_rational_function() for g in gens)):
+            return eq, []
+        else:
+            return
     # - an exponent has a symbol of interest (don't handle)
     if any(g.as_base_exp()[1].has(*syms) for g in gens):
         return

It might be possible (or necessary) to use an even more restrictive condition like g.is_polynomial().

@sachin-4099
Copy link
Contributor Author

Now the tests are passing, but the same error is occuring:
TypeError: cannot unpack non-iterable NoneType object

@sachin-4099 sachin-4099 changed the title solvers: Fixed NoneType Error of solvers.solveset() solvers: Fixed NoneType Error Feb 4, 2020
@sachin-4099 sachin-4099 removed the request for review from sylee957 February 4, 2020 19:40
@sachin-4099
Copy link
Contributor Author

@jksuom please review the PR, if any changes are required please suggest otherwise the PR is ready to be merged.

@jksuom
Copy link
Member

jksuom commented Feb 5, 2020

Thanks, I think it is ready.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

Successfully merging this pull request may close these issues.

TypeError: 'NoneType' object is not iterable in solveset
6 participants