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

Equations SymPEP #1

Open
wants to merge 20 commits into
base: main
Choose a base branch
from
Open

Equations SymPEP #1

wants to merge 20 commits into from

Conversation

gutow
Copy link

@gutow gutow commented Jan 24, 2021

No description provided.

Copy link
Author

@gutow gutow left a comment

Choose a reason for hiding this comment

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

Suggested behavior for diff(eqn)

Equations.md Outdated Show resolved Hide resolved
Copy link
Author

@gutow gutow left a comment

Choose a reason for hiding this comment

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

Questions thoughts on Integral/integrate.

Equations.md Outdated Show resolved Hide resolved
@asmeurer
Copy link
Member

I appreciate the initiative here. However, I plan to start a SymPEP 1 that outlines what SymPEPs are and what they should look like, including a template. So that work should be completed before any actual SymPEPs are done.

@gutow
Copy link
Author

gutow commented Jan 26, 2021

I appreciate the initiative here. However, I plan to start a SymPEP 1 that outlines what SymPEPs are and what they should look like, including a template. So that work should be completed before any actual SymPEPs are done.

Should we close this pull request and reopen it later?

@asmeurer
Copy link
Member

Based on some of the discussion that has happened on the mailing list, perhaps we should reduce the scope of this to only those things that have been uncontroversial. For example, the behavior of diff() has been controversial, as has the behavior of function(eq). But I think the basic ideas like eq + eq aren't. The controversial ideas could be considered in the future, once we have the basic implementation in place.

@gutow
Copy link
Author

gutow commented Apr 17, 2021

I believe that the way Pow class is defined and requiring that both b and e (see below) be valid expressions will make it impossible to do algebra on equations. The issue is with the code beginning on line 281:

        from sympy.core.relational import Relational
        if isinstance(b, Relational) or isinstance(e, Relational):
            raise TypeError('Relational can not be used in Pow')

        # XXX: This should raise TypeError once deprecation period is over:
        if not (isinstance(b, Expr) and isinstance(e, Expr)):
            SymPyDeprecationWarning(
                feature="Pow with non-Expr args",
                useinstead="Expr args",
                issue=19445,
                deprecated_since_version="1.7"
            ).warn()

This all occurs before the object b gets to call its _eval_pow method. It is necessary to call this method on an Eqn to extract the two valid Expr from which the Eqn is built. The simplest solution is, I believe , to only require that e be a valid Expr. An alternative may be the more complex logic in sympy/core/operations.py line 38ff used for mul and add.

@sylee957
Copy link
Member

I think that my comments had been spread over many places and quite misinterpreted a lot
But my biggest argument about this idea, in summary is that

  • Algebra for equation is too rudimentary (addition, multiplication)
  • Even for introducing elementary algebra, there are mathematical correctness issues (like division), which can lead to controversial ideas.

Unlike you have stated in sympy/sympy#21325 (comment)

The syntax should be as close to standard on paper mathematics as possible.
You should have to understand mathematics, not how the program works to use it.

In my experience, I don't think that applying cancel, collect, ... to solve equation is easy or mathematical, but rather needs some deep understanding of heuristics inside.
And this can fall into a danger to become an expression blowing up program for novice users.

@gutow
Copy link
Author

gutow commented Apr 17, 2021

And this can fall into a danger to become an expression blowing up program for novice users.

I am not sure what kinds of problems you are envisioning or have encountered. Can you provide some specific examples?

In 18 months of testing the implementation I have devised with students, I have encountered only the issue above with sqrt, which I believe has to do with calls to Functions. This work involves a lot of calculus, algebra and statistics. In addition to the students using it, I have produced most of the answer keys for my classes using the tool.

@sylee957
Copy link
Member

sylee957 commented Apr 17, 2021

I think that your need more clear statements about the expected users and their proficiency.
At least for lots of people here, would be more proficient than their first course in python, so we may not easily assume how some people call python to be difficult and one liners of sympy code is still difficult.
I think that your 'students' sounds like people studying theoretical science or mathematics who couldn't take a course in python at all, but may only try to learn a subset of commands, is it right?

In this point of view, you may also want to state clear in proposal that this tool shouldn't become some complicated syntactical manipulation or theorem prover in the future, even if they are more sophisticated, and this should stay as a stable beginner tool.
And maybe this can give a strong reason that allowingcos(Eqn) should work, but we may just need to investigate this idea is technically stable.

@gutow
Copy link
Author

gutow commented Apr 18, 2021

I think that your need more clear statements about the expected users and their proficiency.
At least for lots of people here, would be more proficient than their first course in python, so we may not easily assume how some people call python to be difficult and one liners of sympy code is still difficult.
I think that your 'students' sounds like people studying theoretical science or mathematics who couldn't take a course in python at all, but may only try to learn a subset of commands, is it right?

Actually, I expect this to be very useful even for people who are adept at coding. I use the proposed features almost daily. Although not a professional programmer, I have been writing computer code since 1976. I have programmed in assembly, direct binary, multiple flavors of Fortran, Basic, C, Pascal, Forth, Perl, shell-scripting, DOS batch file commands, java, java-script, Mathematica, Maple, Python, and a number of scripting languages specific to particular data-analysis software. Thus, I am quite comfortable writing code when necessary. However, I do not wish to spend anymore time than necessary getting a computer to do things for me. Thus, in this case, I prefer to use the succinct and familiar notation used for math on paper whenever possible. Although the computer can often do the algebra faster than I can, it is not useful to me if it takes me so long to tell it what to do that I can nearly complete the task manually in the same amount of time. Imagine if it took 1 minute to input numbers into your calculator to multiply 1358.9 X 547. If that were the case, it would be a waste to use the calculator rather than do the math by hand.

The other place I find these features handy is when I want to quickly produce typeset versions of the steps in a manipulation. With this tool SymPy converts the relatively easily typed computer math syntax into an ordered typeset list of steps.

In this point of view, you may also want to state clear in proposal that this tool shouldn't become some complicated syntactical manipulation or theorem prover in the future, even if they are more sophisticated, and this should stay as a stable beginner tool.
And maybe this can give a strong reason that allowingcos(Eqn) should work, but we may just need to investigate this idea is technically stable.

I think you are beginning to understand the motivation behind this proposal. However, you read too much into it. I actually think the addition of syntactically complicated programmer extensions are a useful idea. I just do not think the programming extensions should prevent the use of math-on-paper syntax. Programming extensions should be an alternative that can provide access to more powerful tools.

Below is the Motivation section extracted from the SymPEP, I am trying to be clear that this is intended as an on-ramp for new sympy users and a convenience for those of us who routinely manipulate equations where both sides are messy expressions. If that is not clear please point out where you believe further clarification would help.

Motivation and Scope

The original impetus for development of the Equation class came from discussions J. Gutow
had with Physical Science Educators using SymPy in their classes. They wanted this on-paper-like
behavior to facilitate demonstrating algebraic manipulations in physical science classes.

There are a number of specific motivations for the development of the Equation class:

  1. Make interactive manipulation of equations as similar to doing the work on paper as
    possible and make the results easier to read by having results that look like
    x = 2*y + 1 rather than 2*y + 1, with what it is equal to on a separate line.
  2. Have equations on which manual algebra can be done by having SymPy perform the actual
    symbolic manipulation. This allows people to perform messy manipulations with fewer errors, much
    as calculators, spreadsheets and other numerical computation tools facilitate arithmetic.
  3. From an educational and new user perspective this increases the ease of use of SymPy
    by decreasing the cognitive load of using SymPy. This would be acheived by maintaining as
    close to standard mathematical notation for operations as possible (see
    Detailed Description). Making SymPy easier to begin using will
    increase its adoption and encourage people to learn to use symbolic math tools.
  4. The Equality class does not reliably support general SymPy operations on both sides
    of the equality without collapsing to a Boolean value of True or False. Parts of SymPy
    depend on this Boolean behavior; thus this proposal for a separate Equation class rather
    than an extension of Equality.
  5. Currently cycling between expressions and the results of the solve operation is quite
    messy. This proposal includes extending the solve operation so that if passed an equation
    or set of equations it would return the solutions as a set of equations.
  6. .subs() could also be made more natural to use if it could take a list of equations.

@sylee957
Copy link
Member

As I recall, one of my arguments about designing multiplication and division for equation was from the future design of inequality classes.
I had concluded before that if we need to design multiplication or division for inequality, branching is inevitable.
Because for multiplying or dividing both sides of inequality, we must have to choose > or < depending on sign.

I originally thought that multiplication or division for equation could branch like inequality (to appear) depending on zero assumption (c != 0, c = 0), if branching itself can't be eliminated for designing inequality. (c > 0, c < 0, c = 0)

But if you don't want to branch multiplication or division for equality, then this should automatically lead to a design for inequality (to appear) that multiplication and division should only branch with either strictly positive or strictly negative cases. (c > 0, c < 0)

I'm not sure if you had thought in this direction, but this was one of the clue I could support my arguments about multiplication and division previously.

@gutow
Copy link
Author

gutow commented Apr 20, 2021

@sylee957

Because for multiplying or dividing both sides of inequality, we must have to choose > or < depending on sign.

Obvious and expected. Thus, if the sign of the divisor is unknown the appropriate response is to return a set of two relations, one valid for each sign of the divisor. This is equivalent to the solution set returned by solve, but would return a set of relations (or we can call them equations) rather than a set of expressions.

I originally thought that multiplication or division for equation could branch like inequality (to appear) depending on zero assumption (c != 0, c = 0), if branching itself can't be eliminated for designing inequality. (c > 0, c < 0, c = 0)

But if you don't want to branch multiplication or division for equality, then this should automatically lead to a design for inequality (to appear) that multiplication and division should only branch with either strictly positive or strictly negative cases. (c > 0, c < 0)

It is unclear to me how you propose to include branching directly in equations. We already have piecewise expressions and sets of solutions as the way sympy handles branching. I may be misunderstanding you, but you appear to want equations to include branching sets of equations. Why do we need the equation type to include branching sets of equations? Isn't it more flexible and code efficient to keep them as sets of equations, where an equation is defined as a single relation of the form lhs(relational operator)rhs, and the sides are not made of other equations? I can certainly imagine a construct where the two sides of an equation could be sets of equations, but it does not seem consistent with the mathematical notation I am familiar with. Additionally, such a construct appears to be inconsistent with the constructions used in sympy and other symbolic math systems with which I am familiar.

Can you provide a specific example demonstrating what you mean and how it would be superior to using sets of equations? If you are unclear what I mean by sets of equations, look at the sets of solutions returned by solve and substitute equations or relations for the Expr type in the solution set.

@JSS95
Copy link

JSS95 commented Apr 20, 2021

Thus, if the sign of the divisor is unknown the appropriate response is to return a set of two relations, one valid for each sign of the divisor. This is equivalent to the solution set returned by solve, but would return a set of relations (or we can call them equations) rather than a set of expressions.

No. (x > y)/z operation (with sign of z unknown) should return unevaluated DivideSides(x > y, z) object, rather than a set {x/z > y/z, x/z < y/z}. This way, we can do DivideSides(x > y, z).refine(Q.positive(z)) and get x/z > y/z.

If the sign of symbol z is given by assumption property like Symbol('z', positive=True), of course (x > y)/z will directly give x/z > y/z.

@gutow
Copy link
Author

gutow commented Apr 20, 2021

No. (x > y)/z operation (with sign of z unknown) should return unevaluated DivideSides(x > y, z) object, rather than a set {x/z > y/z, x/z < y/z}. This way, we can do DivideSides(x > y, z).refine(Q.positive(z)) and get x/z > y/z.

If the sign of symbol z is given by assumption property like Symbol('z', positive=True), of course (x > y)/z will directly give x/z > y/z.

@JSS95 Thank you that clearly explains what the intent is. I like the idea of not evaluating unless requested for relations. That solves a lot of the branching issues. Additionally, that is completely compatible with the proposed equation class and your suggestion that when relations are included __mul__, etc should call mulsides, etc. where the appropriate action can be taken depending on the relational operator. For the = operator it would just perform the operation. For the other relationals it would not perform the operation unless explicitly asked to.

A related question: Have you thought about how to implement something like ((x>y)/z).doit? I would expect that to return the set of possibilities {(x/z>y/z,z > 0),(x/z < y/z,z<0)}.

I have not got time right now, but will try to update the language in the proposal to include this soon. If you have specific suggestions please use the code comments feature on this pull request to suggest them. I really believe that equations and relations do belong together, but would like to get the simpler Eqn with = implemented as quickly as possible. I use it regularly now and have found it useful with my students. I originally started to write a more general relational class, but quickly ran up against the issue of assumptions and branching. I think with the work you are doing, there is progress being made on the more difficult general relational class.

@JSS95
Copy link

JSS95 commented Apr 20, 2021

I strongly disagree that ((x>y)/z).doit() should return a set. Maybe we can have some other method like ((x>y)/z).as_conditional() or ((x>y)/z).rewrite(set) or anything, but never doit(). That's because doit() is a method for recursive evaluation, and it does not make sense that operation on the equation evaluates to something other than equation.

Here is how I think DivideSides should be:

  1. DivideSides should be unevaluated by default. This means that DivideSides(x > y, 2) signal should not be automatically evaluated to x/2 > y/2. (This is because we don't want any more automatic evaluation in SymPy. Run from sympy import this and see what the first item says.)

  2. evaluate=True signal should evaluate the operation by checking the assumption property (a.k.a old assumptions system) . This means that DivideSides(x > y, 2, evaluate=True) returns x/2 > y/2.

  3. Even if full evaluation is impossible, it should try as much as it can. For example, DivideSides(x > y, 2*z, evaluate=True) should return DivideSides(x/2 > y/2, z).

  4. DivideSides(arg1, arg2).doit(deep=False) should be exactly same to DivideSides(arg1, arg2, evaluate=True).

  5. DivideSides(arg1, arg2).doit(deep=True) should be exactly same to DivideSides(arg1.doit(deep=True), arg2.doit(deep=True), evaluate=True).

  6. refine() should evaluate the operation using assumption predicates (a.k.a. new assumptions system).

  7. Finally, eqn.__truediv__(other) method should do nothing but call DivideSides(eqn, other, evaluate=True). This means that (x>y) / 2 returns x/2 > y/2, (x>y) / z returns DivideSides(x > y, z), and (x>y) / (2*z) returns DivideSides(x/2 > y/2, z).

@siefkenj
Copy link

A couple of thoughts/questions: Why wouldn't eqn.doit() return True/False/None? That would be what I expect...

There seems to be something weird with the proposed interaction of inequalities and assumptions. Of course, x > y doesn't make sense for Complex. Will the constructor error if the variables are not assumed to be real?

To me, the core of this idea is some sort of SymbolicRelation, which consists of a lhs, rhs, and relation operator. SymbolicRelation(SymEq, x, y) / f should become SymbolicRelation(SymEq, x/f, y/f) for any f. On the other hand, SymbolicRelation(SymGt, x, y) / f should become SymbolicRelation(SymGt/f, x/f, y/f). Now, (SymGt/f).refine(Q.negative(f)) becomes SymLt, and (SymGt/f).refine(Q.zero(f)) and (SymGt/f).subs({f: I}) becomes SymUndefined.

@JSS95
Copy link

JSS95 commented Apr 20, 2021

@siefkenj

The design that has been made so far is that boolean relational and symbolic relational should be strictly discerned. Mathematically, we cannot do numeric field operations +, -, *, / on boolean objects. The new Eqn is rather a container than a boolean object, and operation between them is not mathematically rigorous but allowed for convenience.

@siefkenj
Copy link

The design that has been made so far is that boolean relational and symbolic relational should be strictly discerned. Mathematically, we cannot do numeric field operations +, -, *, / on boolean objects. The new Eqn is rather a container than a boolean object, and operation between them is not mathematically rigorous but allowed for convenience.

This makes me more convinced that the relation operator should be an entity on its own that one is able to do arithmetic with and doesn't have a lhs or rhs. Then a SymbolicRelation is just a container with some pretty printing built in. This would allow some interesting extensions. For instance, you could have a SymModEquiv for equivalence in modular arithmetic. SymModEquiv would define how it is printed and all the rules for different operations.

Of course, there could (and should?) be syntactic sugar for common cases like an equality.

I know sympy has a Tuple type. Does that pass through operations to its children? Is there already a generic container that does that?

@gutow
Copy link
Author

gutow commented Apr 20, 2021

@siefkenj in #1 (comment) are you suggesting that we should not make an effort to combine the proposed Eqn type for the = operator with the general relations?

@siefkenj
Copy link

@siefkenj in #1 (comment) are you suggesting that we should not make an effort to combine the proposed Eqn type for the = operator with the general relations?

I don't quite know what you're asking, but my proposal is that a SymbolicRelation class be created which subclasses to SymbolicEqual, SymbolicGreaterThan, etc. These objects would respond to all the arithmetic operations themselves.

Then, there would be a separate class (I don't know a good name for it...) DisplayRelation which would take a SymbolicRelation, a rhs and a lhs. It would pass through all operations to it's three children. On top of this, it would have pretty-printing functionality.

The benefits of this proposal is that only one new mathematical object would be added (the SymbolicRelation), and the rules for SymbolicRelation could be defined consistently depending on how it's operated on. Then, a separate object, which is purely syntactic sugar, could be added for the kind of "line by line" algebra that this PEP states as its goal.

Or, let me state it a different way: the current proposal combines a mathematical proposal with a UI proposal. I think these should be separated.

@JSS95
Copy link

JSS95 commented Apr 20, 2021

@siefkenj In PR sympy/sympy#21325, SymbolicRelation class is already introduced. I believe that it fits to your idea?

@siefkenj
Copy link

siefkenj commented Apr 20, 2021

@siefkenj In PR sympy/sympy#21325, SymbolicRelation class is already introduced. I believe that it fits to your idea?

That is different. And now that I have thought about it now, I have some new proposals for consistent vocabulary.

  • RelationSymbol - an atom representing the symbol used in a relation. E.g., = or >, etc.
  • FormalRelation - a container that holds a RelationSymbol, lhs, and rhs. (This would be most similar to SideProxy in feat: introduce symbolic equation sympy#21325 perhaps?)

What is currently called Eqn in this PEP would be renamed FormalEq and FormalEq(lhs, rhs) == FormalRelation( RelationSymbol("="), lhs, rhs ) (though for some reason Relation seems to be defined using Polish notation instead of RPN; to be consistent maybe one should say FormalRelation( lhs, rhs, RelationSymbol("=") ), even though I'm not a fan of putting the symbol last...). I think this would interop better with the current Relations, and calling as_Relation on a FormalRelation would cast it to an actual Relation. Also, having both Eq and Eqn would produce a lot of confusion for users.

I think Formal is a better term than Symbolic because it is used in math to mean "ignore what the variables are, and work symbolically" (e.g., formal polynomial).

@gutow
Copy link
Author

gutow commented Apr 20, 2021

Or, let me state it a different way: the current proposal combines a mathematical proposal with a UI proposal. I think these should be separated.

I am not sure how you have a UI without the binary operations and application of sympy functions on both sides of the equation. There are certainly some operations (e.g. diff), where it does not make sense to have them operate on both sides of the equation. This proposal specifically leaves out those that have been identified.

The key question we have to decide is what is the minimal functionality that is a valuable improvement to sympy? I propose the minimum is the functioning on-paper-like manipulations of expressions with the form lhs = rhs.

The more difficult general relations can be hooked into this as they are developed. See PR sympy/sympy#21333, for an implementation that does not require making immediate decisions about how the relationals work, but would give us the basic behavior for =. As pointed out in #1 (comment), it would be easy to convert Equation to use the completed Relational scheme by have __mul__, etc. point to the appropriate MultiplySides, etc. method for the operator. At that point the Equation class could be extended to accept other operators (eg. =,<, etc...).

I feel we are delaying useful functionality, because we have not settled on all the possible extensions. IMHO this is silly, because those extensions can be added relatively simply when they are settled.

@gutow
Copy link
Author

gutow commented Apr 20, 2021

Why this SymPEP uses the name Equation:

  • As noted this is primarily a UI proposal to make it more natural to manipulate relations with the = operator.
  • If you ask most undergraduates, graduate students and many of the mathematicians I know to write a simple example of an equation you will get something similar to: a = b/c. Thus if somebody is trying to figure out how to get sympy to manipulate such a symbolic relation, they are likely to search for the term equation.
  • Part of making a UI useful is making it easy for the users to discover its existence and features.

@siefkenj
Copy link

There are certainly some operations (e.g. diff), where it does not make sense to have them operate on both sides of the equation. This proposal specifically leaves out those that have been identified.

When would you differentiate only one side of an equation?

The more difficult general relations can be hooked into this as they are developed.

It's important to have the proper abstraction. There are lots of places in sympy (for example, the geometry module and the matrix module) where operations were added whose conventions conflict with other modules and it's very hard to modify them while staying compatible. (Isn't that why there's a PEP procedure now, so things can get thoroughly discussed?)

If you ask most undergraduates, graduate students and many of the mathematicians I know to write a simple example of an equation you will get something similar to: a = b/c. Thus if somebody is trying to figure out how to get sympy to manipulate such a symbolic relation, they are likely to search for the term equation.

I agree. Documentation is key! Equation is better than Eqn, but every system has a certain amount of learning associated with it. Sympy already has Eq, and for better or for worse, it's behavior cannot change significantly until a 2.0 release. Now, picture a new user who searches on stackoverflow and sees the use of Eq. Are they going to know the difference between that and Eqn or Equation? Probably not without reading the documentation... (As a novice user, I might think that Eqn is just a typo and Eq and Eqn are supposed to be the same and just skip the documentation all together...)

@gutow
Copy link
Author

gutow commented Apr 21, 2021

When would you differentiate only one side of an equation?

I don't think you should, but the current implementation of differentiation in sympy (and other math tools such as Sagemath) makes it not work well. The problem is that diff is really defined as a partial derivative assuming that everything but the symbol of differentiation is a constant. This is convenient much of the time, but leads in equations to transformation like this diff(a=b/c,c) -> 0 = -b/c**2. Most people would expect the result Derivative(a,c) = -b/c**2. Workarounds that depend on defining symbols as sympy functions, run up against issues of circular dependence when you try to use them in common models of real physical situations. I think what is needed is a more general partial derivative. As this proposal is primarily a UI proposal, I believe we should put off dealing with that until the future, so I have removed default both sides application of diff and Integrate from the proposal.

I am fiddling with ideas for adding the concept of an Infinitessimalclass to the Calculus module and through that total and fully specified partial derivatives. But this needs further work before I can present my ideas.

@gutow
Copy link
Author

gutow commented Apr 21, 2021

The more difficult general relations can be hooked into this as they are developed.

It's important to have the proper abstraction. There are lots of places in sympy (for example, the geometry module and the matrix module) where operations were added whose conventions conflict with other modules and it's very hard to modify them while staying compatible. (Isn't that why there's a PEP procedure now, so things can get thoroughly discussed?)

  1. The present proposal does not propose to change any underlying mathematical behavior of sympy.
  2. How the behavior is accessed can be changed without changing the UI behavior.
  3. I believe we have identified, in @JSS95 's suggestion (Equations SymPEP #1 (comment)) and my follow-on comment (Equations SymPEP #1 (comment)) how extended behavior could be readily coupled into the Equation class proposed in PR (Introduce equation module sympy#21333) by redirecting calls such as __Mul__.

@JSS95
Copy link

JSS95 commented Apr 21, 2021

@siefkenj What is the benefit from having RelationSymbol('=') instance, instead of having Eqn class?

@siefkenj
Copy link

@siefkenj What is the benefit from having RelationSymbol('=') instance, instead of having Eqn class?

For only Eqn, it doesn't matter so much, but when introducing further relations it would. However, there's still an upside:

RelationSymbol('=') should absorb all function operations, so in some sense, it's rather boring. However, if it exists, it would allow for cheap-and-dirty implementation of Eqn. For example

Matrix([RelationSymbol('='), x, y])

would behave basically like Eqn. You inherit all vectorized operations from Matrix for free (I'm not saying implement it this way, but it would be possible). Say you wanted to work with double equations? Matrix([RelationSymbol('='), RelationSymbol('='), x, y, z]) could represent x=y=z. The arity gives you compatibility checks for free. And, this would allow for some really cool things. For instance, there could be a RelationSymbol('BigO'), etc.

Now that I think about it...why isn't this proposal just a wrapper around Matrix? Is there anything besides pretty-printing that Eqn would do that Matrix doesn't?

@JSS95
Copy link

JSS95 commented Apr 21, 2021

RelationSymbol('=') should absorb all function operations, so in some sense, it's rather boring. However, if it exists, it would allow for cheap-and-dirty implementation of Eqn.

Why would we want cheap-and-dirty implementation of equation when we can define it in clean and robust way?

Now that I think about it...why isn't this proposal just a wrapper around Matrix? Is there anything besides pretty-printing that Eqn would do that Matrix doesn't?

Matrix class is not just an arbitrary container. Every feature of it is designed with firm mathematical background to handle linear algebra (if there is anything that's not, it should be fixed). Warping its purpose to represent a binary (or polyadic) relation will cause endless bugs, confusion and slowdown.

@JSS95
Copy link

JSS95 commented Apr 21, 2021

I think you may want to take a look at assumptions/relation module in SymPy master branch. I recently implemented relational predicate instance in there, which represents equality as AppliedBinaryRelation(Q.eq, x, y)). Perhaps this design is similar to your idea.

assumptions/relation module is introduced because allowing relations to be assumed in ask system requires them as binary predicates. (Note that to avoid confusion, this module is not exposed to end users)

1. Currently cycling between expressions and the results of the `solve` operation is quite
messy. This proposal includes extending the `solve` operation so that if passed an equation
or set of equations it would return the solutions as a set of equations.
1. `.subs()` could also be made more natural to use if it could take a list of equations.
Copy link
Member

Choose a reason for hiding this comment

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

This should not be confused with xreplace to be changed to unpack equation objects.
I think that for xreplace, the only xreplace to be allowed with equation is substituting the whole equation object with any other specified target, if equation matches some of the subtree.

Copy link
Author

Choose a reason for hiding this comment

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

At this point I was only envisioning that .subs(Eqn(a,b)) would be equivalent to .subs({a:b}). A wholesale update to .subs() should probably be a separate SymPEP or at least issue. Getting even more generic syntax such as .subs(a=b) being equivalent to .subs({a:b}) will require more involved workarounds (preparsing?) as Sagemath uses. That is definitely beyond the scope of this proposal.

Copy link
Member

Choose a reason for hiding this comment

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

It is possible to make Eqn recognized as some rule table (like how sympy's own Tuple or Dict are recognized as rule. But at least I'm sure that they shoul)
For making subs(a=b) work, I think that we can lookup for unknown keyword argument passed to **kwargs by kwargs.items, but the possible problem is conflicting with the options for subs, If the symbol is named like simulatneous.

Copy link
Author

Choose a reason for hiding this comment

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

For making subs(a=b) work, I think that we can lookup for unknown keyword argument passed to **kwargs by kwargs.items, but the possible problem is conflicting with the options for subs, If the symbol is named like simulatneous.

This is why I think .subs(a=b) would need more sophisticated preparsing to make it work.

@sylee957
Copy link
Member

sylee957 commented Apr 24, 2021

Although @siefkenj's ideas look interesting, I'm not sure there are known algorithms to implement such abstractions. I think the part to vectorize could be easy to implement, but the idea of having operation like SymGt/f is not the ordinary mathematic I am familiar with. (as noted in SymbolicRelation(SymGt, x, y) / f -> SymbolicRelation(SymGt/f, x/f, y/f) / f)

On the contrary, I think that we should use some mathematical formalism for algebra over equations to make people converge on the idea about how eqn + eqn, SymGt / f should make sense, but I'm not sure if the same algebra exists for equation and we can use some existing publication that is beyond precollege education.

@smichr
Copy link
Member

smichr commented Mar 25, 2022

I am not sure why there can't be a "let me shoot myself in the foot" functionality that doesn't impose mathematical rigor on what is written. Can we just think of the Eqn class as a type-setting class? If I want to change x*y = 2 into x = 2/y -- like I just did -- my keyboard doesn't stop me. Would it help to call it something else? Mimic - an object that has two sides and will apply any action to both sides so cos(Mimic(x, pi)) -> Mimic(cos(x), -1)`?

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.

7 participants