Could you post an example of a large system?

/c

On Wednesday, August 20, 2025 at 9:45:00 AM UTC-5 [email protected] 
wrote:

>
> Hi Oscar,
>
> Sorry for the late reply, I opened the two issues:
>
> https://github.com/sympy/sympy/issues/28331
> https://github.com/sympy/sympy/issues/28332
>
> Not quite sure if the format and the text is fine, let me know if I need 
> to modify anything.
>
> Thanks very much for the detailed explanation on solve vs solveset. I 
> found it very interesting, and I agree with the points. For my usecase I 
> definitely need to use solve, because I need the solutions afterwards.
>
> I'm writing an implementation for my very special and restricted usecase 
> of systems, where I might need to convert between dicts and sets, mainly 
> to keep track of the potential infinite solutions:
> {x[0]: x[2], x[1]: x[2], x[2]: x[2]} == {x[0]: x[1], x[1]: x[1], x[2]: 
> x[1]} is False for dicts, but they both represent the same FiniteSet if 
> the domain for x[1] and x[2] are the same. Is there some code in sympy 
> which converts between these in certain cases, or I can just go with my 
> (rather naive) approach with something like:
>
> def subs_to_fset(subs:list[dict],
> variables:Iterator[sympy.Symbol]) -> sympy.FiniteSet:
> if any(len(d) != len(variables) for d in subs):
> raise SubstitutionSizeNotMatcingNumberOfVariablesError
> return sympy.FiniteSet(*[tuple(d[v] for v in variables) for d in 
> subs])
>
> def fset_to_subs(fset:sympy.FiniteSet,
> variables:Iterator[sympy.Symbol]) -> tuple[tuple]:
> if any(len(p) != len(variables) for p in fset):
> raise FiniteSetDimensionNotMatcingNumberOfVariablesError
> return tuple(tuple(zip(variables, p)) for p in fset)
>
>
> You also mention that there is no benefit using linsolve and nonlinsolve 
> vs solve. Do you mean that for the performance, as well, or only for 
> capability? To me performance may matter, and the awkward conversion 
> between sets and list[dicts] might be worth it in case linsolve is 
> significantly faster than solve. But if they essentially have the same 
> underlying code, then solve is far superior for its output.
>
>
> Thanks for the pointers on how to handle systems w Min/Max. For now I 
> ended up using an extra domain parameter that restricts the potential 
> solution onto an interval (in my special usecase that's the situation), 
> and since all non-MinMax equations are linear, I can use some heuristics 
> to compute upper and lower bounds for each variable based on what 
> subsolutions / substitutions I found so far, and intersect that with the 
> domain of interval of possible solutions. In certain cases (apparently a 
> lot of the cases for my systems) this provides a solution to a lot of 
> variables, just like in the case for the minimal example I provided. This 
> way I can significantly reduce the number of equations having MinMax in 
> them.
> For some big systems there still are many of those MinMax equations, 
> though (many meaning ~20, but that is already >1mil different cases to 
> solve for). So for those I'll try your suggested approach of recursively 
> solve one equation and substitute back, but that seems to be less 
> efficient for now that simply enumerating all potential 2**20-many 
> possibilities. I must have some silly mistake in my code, which I'll have 
> to check.
>
> In any case, thank you very much for all the help!
>
> Thanks,
> Gábor
>
> > On Sat, 9 Aug 2025 at 17:31, Gábor Horváth <[email protected]> wrote:
> >>> On Sat, 9 Aug 2025 at 13:26, Gábor Horváth <[email protected]> 
> wrote:
> >>>>
> >>>> So my questions are:
> >>>> 1) Is the expected behaviour for sympy.solve for the Piecewise case 
> to throw a NaN comparison exception, or is this a sign of some underlying 
> issue in sympy.solve for Piecewise functions?
> >>>
> >>> No, that is just a bug.
> >>
> >> Ok, thanks. Should I report it in some official way somewhere (if yes,
> >> where and how), or has this email already taken care of the bugreport?
> >> Maybe I should open an issue on https://github.com/sympy/sympy/issues ?
> >
> > Yes, please open an issue there.
> >
> > I think that the expected behaviour here is to raise an error but it
> > should be an explicit error like "equation type not supported".
> >
> >>>> 2) Is sympy.solve expected to rewrite Min and Max to Piecewise at 
> some point in the future? I found some piece of code in 
> solvers/solvers.py:944-957 which does some sort of rewriting for Abs, but 
> didn't find any for Min or Max.
> >>>
> >>> It probably does make sense to rewrite Min and Max as Piecewise if
> >>> they contain the variables of interest.
> >>
> >> Ok, thanks. Same question as above: should I open some issue on
> >> https://github.com/sympy/sympy/issues or elsewhere, or this is already
> >> taken care of by this email?
> >
> > Yes, please open an issue. It can be the same issue.
> >
> >>>> 3) From some reading on the sympy docs page, I figured solveset is 
> expected to be the future solver. Is there a direct way I can apply 
> solveset on a system, rather than on one equation?
> >>>
> >>> This documentation needs to be changed. The solveset function is not
> >>> going to replace solve. It was originally intended as a replacement
> >>> for solve but was then misdesigned as something different that cannot
> >>> replace solve because it does not provide comparable functionality or
> >>> interface.
> >>
> >> Ah, I see. This was the page I found first:
> >> https://lidavidm.github.io/sympy/modules/solvers/solveset.html
> >
> > That is an old version hosted from someone's outdated fork. Can you
> > open a separate sympy github issue about that? We can tag the owner of
> > the fork and ask them to remove this. It isn't possible to open an
> > issue in their repo as it has issues disabled I think:
> > https://github.com/lidavidm/sympy
> >
> >> BTW, are there some old threads somewhere maybe where such discussions
> >> can be read? I would be curious what you mean by misdesign, and what 
> were
> >> the discussion and decision points around solve an solveset.
> >
> > Some will be here on the mailing list which you can search. Others
> > will be on GitHub.
> >
> > What I mean by misdesign here is not that solveset is misdesigned in
> > general but rather that if the intention was to replace solve then it
> > was misdesigned for that purpose. It is not possible to replace solve
> > with solveset because they just don't do the same thing.
> >
> > The purpose of a function like solve is that it turns an implicit
> > representation of the solutions (equations to be solved) into an
> > explicit representation which is a list of assignments like x = ..., y
> > = .... Its return value is therefore a list of dicts each of which
> > could be passed to subs.
> >
> > There are some limitations in this explicit format which mean that it
> > cannot always be fully mathematically correct/complete. For example
> > your system of equations has the solution set:
> >
> > {(a, a) for a in [2, oo)}
> >
> > The best solve can do to represent that solution set is to return
> >
> > [{x: y}]
> >
> > but that loses the information that y >= 2 is a constraint on the
> > solutions. It could be possible to extend solve to also return the
> > condition like
> >
> > [({x: y}), y >= 2)]
> >
> > but that would be an incompatible change in its output format.
> >
> > With solveset the intention is that the output is always
> > mathematically correct/complete but then by design it does not
> > necessarily return an explicit representation of the solutions which
> > contradicts the basic purpose of solve. There is a tradeoff here where
> > you have to choose between having explicit representations but with
> > some attached explicit or implicit conditions vs not having an
> > explicit representation at all.
> >
> > The purpose of the solve function is to have the explicit
> > representations subject to the fact that they may be incomplete or not
> > always valid whereas the purpose of solveset is to be always complete
> > and valid and therefore not necessarily give an explicit
> > representation of the solutions. These are contradictory goals and so
> > in a basic way solveset cannot replace solve.
> >
> > There are other reasons why solveset cannot replace solve. Another
> > reason is that solveset returns output in an unstructured form that is
> > not easily usable even when the solutions can be given explicitly.
> > There are some places in the sympy codebase that try to use solveset
> > and they always have awkward scaffolding code that basically tries to
> > turn the output of solveset into something that looks like the output
> > of solve. This is because the sets that solveset returns are only
> > really nice just to "look at". If you actually want to use the
> > solutions of the equation for something then you want an explicit
> > representation i.e. you basically want solve rather than solveset.
> >
> > An even more obvious reason why solveset cannot replace solve is that
> > it only handles single univariate equations rather than systems of
> > equations. It has not even been designed in a way that it could be
> > extended to handle systems of equations in future.
> >
> >> There is also mention in the docs about FiniteSet handling tuples
> >> corresponds to a finite subset of points in the multi-dimensional space.
> >> That suggests that solveset was intended to be able to solve 
> multi-variate
> >> equations or even systems. Is that indeed the case, or only some special
> >> cases (like linsolve) can really handle multi-variate equations/systems?
> >
> > The linsolve and nonlinsolve functions do handle systems of equations
> > and are useful. They also return a somewhat awkward output format and
> > do not really handle infinite solution sets in a coherent way which
> > undermines the benefit of not simply returning a list of dicts like
> > solve does. I am not sure that there is any particular benefit in
> > using either of these functions rather than just using solve. They are
> > basically just new implementations of the way that solve handles
> > systems and perhaps have cleaner code but otherwise do not
> > fundamentally increase capability or usefulness.
> >
> >>> In general I think that what you should really want in a situation
> >>> like this is something like Mathematica's Reduce function rather than
> >>> Solve. Unfortunately SymPy has several versions of solve but nothing
> >>> like reduce.
> >>
> >> Hm, all are very good points. I have some very crude code to solve these
> >> systems exactly as you suggest, by splitting at the various Min and Max
> >> occurrences, solving the underlying linear system (with linsolve), and
> >> then check if the obtained solutions indeed solve the original system 
> with
> >> Min and Max.
> >>
> >> That said, somehow my code is rather slow, especially when there are 
> many
> >> Max occurrences. I feel that sympy.solve is faster when it doesn't fail,
> >> so somehow sympy handles Piecewise functions pretty fast. I guess I'll
> >> have to do some profiling on where I can still gain on performance.
> >>
> >> Your comment also made me realize that in my systems there are some
> >> underlying assumptions, as well, as inequalities. For the above system I
> >> quickly checked and the corresponding assumption would be 1<=Min(x,y) 
> and
> >> Max(x,y)<=2. With that assumption the solution becomes unique. I guess
> >> I'll need to handle these assumptions in my code, as well. (sympy.solve
> >> dies with the same NaN comparison error even with the extended
> >> assumptions)
> >
> > Okay, so your actual system here is:
> >
> > x = Max(y, 1)
> > y = Max(2, x)
> > 1<=Min(x,y)
> > Max(x,y)<=2
> >
> > If I wanted to make a solver for systems like this then I would make
> > something that turns it into separate systems of inequalities that
> > don't involve Min and Max. For example x = Max(y, 1) can be separated
> > into two disjoint cases represented by pairs of inequalities:
> >
> > (1)
> > x = y
> > y > 1
> >
> > (2)
> > x = 1
> > y <= 1
> >
> > You can do the same for each Max and Min. That will give you 8 (2^3)
> > systems of linear equations and inequalities. To solve those first
> > solve the linear equations and then substitute into the inequalities.
> > Then Fourier-Motzkin can solve the remaining system of inequalities.
> >
> > If you have a large number of Max/Min then the approach I just
> > described might be inefficient but it depends how many of the Max/Min
> > are actually distinct. In the above case Max(x,y) and Min(x,y) can
> > both switch in the same condition x>y. That is why we get 2^3 cases
> > rather than 2^4. If your 2^n here is large then a better approach is
> > something that works by progressively solving and substituting e.g.
> > for case (1) above you substitute x = y into all remaining
> > inequalities before splitting any of the other Min/Max at which point
> > they simplify significantly.
> >
> > If SymPy were to have a solver for this kind of system it would be one
> > of the inequality solvers but I don't think any of those handles a
> > multivariate system as is needed here. Ideally SymPy would have a
> > reduce function that would be able to handle exactly this kind of
> > system but it does not. Much of the effort that went into solveset
> > would have been better spent on a reduce function which would have
> > then been a good foundation for building a new version of solve.
> >
> > --
> > Oscar
> >
> > -- 
> > You received this message because you are subscribed to the Google 
> Groups "sympy" group.
> > To unsubscribe from this group and stop receiving emails from it, send 
> an email to [email protected].
> > To view this discussion visit 
> https://groups.google.com/d/msgid/sympy/CAHVvXxQ%3D0t4J9hqjhW43wYezd5%2BBwxKN8aeG6oBWmjkJU9hapQ%40mail.gmail.com
> .
> >

-- 
You received this message because you are subscribed to the Google Groups 
"sympy" group.
To unsubscribe from this group and stop receiving emails from it, send an email 
to [email protected].
To view this discussion visit 
https://groups.google.com/d/msgid/sympy/1d1c80c9-8b37-48b6-ac1e-1286d2eb83een%40googlegroups.com.

Reply via email to