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

Implemented inequation solver for continous functions with finite number of solutions #2736

Merged
merged 1 commit into from
Jan 13, 2014

Conversation

hargup
Copy link
Contributor

@hargup hargup commented Jan 6, 2014

No description provided.


for x in solns:
end = x
if rel.subs(sym, (start + end)/2):
Copy link
Contributor Author

Choose a reason for hiding this comment

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

The 2 here doesn't have anything inherently special. The function just needs to check if the relation is satisfied somewhere in the interval (start, end).

Copy link
Member

Choose a reason for hiding this comment

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

You have to watch out for +/-oo otherwise you might generate a nan after substitution, e.g. x + abs(x) < 3 has the solution (-oo, 3/2) but the average is -oo and substitution gives a nan. So you have to be smarter about this test, maybe:

if start == -oo and end == oo:
    test = 0
elif start == -oo:
    test = end - 1
elif end == oo:
    test = start + 1
else:
    test = (start + end)/2

Btw, solve stumbles on this equation and reduce_inequalities doesn't like (x + abs(x) < 3, assume=Q.real(x)) so the changes you are making are needed, they should just be incorporated somehow into the solve and perhaps other inequalities solvers.

Also, if the input is True (e..g. var('x', real=True); isolve(x**2+1>0,x) then (-oo, oo) should be returned; if the input is False then the empty set should be returned.

Copy link
Member

Choose a reason for hiding this comment

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

I think the way to go is to put isolve into inequalities.py and make sure it return inequalites, not ranges then in _solve_inequality make it look like this:

    ...
    try:
        p = Poly(expr, s)
        if p.degree() != 1:
            raise NotImplementedError
    except (PolynomialError, NotImplementedError):
        return isolve(expr, s)
    ...

Copy link
Member

Choose a reason for hiding this comment

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

...and I would name your solver solve_continuous_inequality.

While you are editing such files, you might remove references to solve_poly_inequalities or else write an appropriate function; looks like an author oversight that it's not there.

@skirpichev
Copy link
Contributor

But what's wrong with the current solve?

For example:

In [6]: solve(x**2>=4, x)
Out[6]: im(x) = 0 ∧ (re(x) ≥ 2 ∨ re(x) ≤ -2)

In [7]: solve(x**2>=4,x, assume=Q.real(x))
Out[7]: x ≥ 2 ∨ x ≤ -2

See sympy.solvers.inequalities module.

@smichr
Copy link
Member

smichr commented Jan 6, 2014

Maybe all that is needed is a method to turn an inequality into an interval, e.g. solve(x**2>=4,x, assume=Q.real(x)).as_interval() to give your result.

@skirpichev
Copy link
Contributor

Or Set constructor should accept relational input in some way.

@hargup
Copy link
Contributor Author

hargup commented Jan 7, 2014

But what's wrong with the current solve?

I'm a little embarrassed to admit it but I didn't know solve could handle relational inputs. I have went through solvers documentation in past but somehow the fact that it can solve relational input slipped from my mind. I had this idea of solving inequalities and I implemented it right away. Sorry for being reckless.

The current solve can handle only polynomial or rational functions with rational coefficients.

In [19]: solve(exp(x)>E, x, assume=Q.real(x))
---------------------------------------------------------------------------
NotImplementedError                       Traceback (most recent call last)
/home/hargup/arbit_sympy_testing/<ipython-input-19-b452703a5f71> in <module>()
----> 1 solve(exp(x)>E, x, assume=Q.real(x))

/home/hargup/arbit_sympy_testing/sympy/solvers/solvers.py in solve(f, *symbols, **flags)
    686         elif isinstance(fi, bool) or fi.is_Relational:
    687             return reduce_inequalities(f, assume=flags.get('assume'),
--> 688                                        symbols=symbols)
    689 
    690         # Any embedded piecewise functions need to be brought out to the


/home/hargup/arbit_sympy_testing/sympy/solvers/inequalities.pyc in reduce_inequalities(inequalities, assume, symbols)
    421                     abs_part[gen] = [(expr, rel)]
    422             else:
--> 423                 raise NotImplementedError("can't reduce %s" % inequalities)
    424 
    425     extra_assume = And(*extra_assume)

NotImplementedError: can't reduce [exp(x) > E]
In [20]: solve(x**2 > E, x, assume=Q.real(x))
---------------------------------------------------------------------------
NotImplementedError                       Traceback (most recent call last)
/home/hargup/arbit_sympy_testing/<ipython-input-20-4ea6a51c0168> in <module>()
----> 1 solve(x**2 > E, x, assume=Q.real(x))

/home/hargup/arbit_sympy_testing/sympy/solvers/solvers.py in solve(f, *symbols, **flags)
    686         elif isinstance(fi, bool) or fi.is_Relational:
    687             return reduce_inequalities(f, assume=flags.get('assume'),
--> 688                                        symbols=symbols)
    689 
    690         # Any embedded piecewise functions need to be brought out to the


/home/hargup/arbit_sympy_testing/sympy/solvers/inequalities.pyc in reduce_inequalities(inequalities, assume, symbols)
    434 
    435     for gen, exprs in poly_part.items():
--> 436         poly_reduced.append(reduce_rational_inequalities([exprs], gen, assume))
    437 
    438     for gen, exprs in abs_part.items():

/home/hargup/arbit_sympy_testing/sympy/solvers/inequalities.pyc in reduce_rational_inequalities(exprs, gen, assume, relational)
    203 
    204             if not (domain.is_ZZ or domain.is_QQ):
--> 205                 raise NotImplementedError("inequality solving is not supported over %s" % opt.domain)
    206 
    207             _eqs.append(((numer, denom), rel))

NotImplementedError: inequality solving is not supported over EX

My algorithm can handle inequalities with any continuous univariate function that can be handled by solve. Using isolve for the same functions as above gives the correct result as:

In [4]: isolve(x**2 > E, x)
Out[4]: (-oo, -exp(1/2)) U (exp(1/2), oo)

In [5]: isolve(exp(x) > E, x)
Out[5]: (1, oo)

Extending the implementation to discontinuous functions will be easy if we can efficiently extract the points of discontinuities.

I guess I work on should improving the current solve for relationals, rather than making a new procedure.

@hargup
Copy link
Contributor Author

hargup commented Jan 9, 2014

The current online documentation doesn't have references for sympy.solvers.inequalities. I added them at #2746

@mrocklin
Copy link
Member

mrocklin commented Jan 9, 2014

Maybe all that is needed is a method to turn an inequality into an interval, e.g. solve(x**2>=4,x, assume=Q.real(x)).as_interval() to give your result.

This functionality exists, it's just hard to find. It would be nice to have a standard inequality->set function somewhere in sets.

In [1]: from sympy.solvers.inequalities import reduce_rational_inequalities

In [2]: reduce_rational_inequalities([[x >= 0]], x, relational=False)
Out[2]: [0, ∞)

@mrocklin
Copy link
Member

mrocklin commented Jan 9, 2014

Oh, I see now that @smichr suggested a Relational.as_interval method. This seems like a good idea. I would suggest an as_set method instead though. Sets already have the reverse direction

In [7]: Interval(-oo, 0) + FiniteSet(1, 2, 3)
Out[7]: (-∞, 0] ∪ {1, 2, 3}

In [8]: _.as_relational(x)
Out[8]: x = 1x = 2x = 3x0

@asmeurer
Copy link
Member

There's also the rewrite framework.

@smichr
Copy link
Member

smichr commented Jan 11, 2014

I sent a PR (my isolve branch) to this that incorporates isolve into solve and makes corrections that I recommended above.

variable name changes and remove comment in test
@smichr
Copy link
Member

smichr commented Jan 13, 2014

The travis test SHA1 that passes doesn't match the last-showing SHA1 above and when I pull your branch I get the df9... version. I made the necessary modification and will push from here if the tests pass.

@smichr smichr merged commit df92d4d into sympy:master Jan 13, 2014
@smichr
Copy link
Member

smichr commented Jan 13, 2014

Thanks for upgrading the solver with this routine. This is in.

@hargup hargup deleted the isolve branch January 16, 2014 05:31
@hargup
Copy link
Contributor Author

hargup commented Jan 16, 2014

I added as_set method in #2781

@hargup hargup restored the isolve branch July 25, 2014 12:34
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

5 participants