# Operations with Equal

Posted 4 years ago
10026 Views
|
18 Replies
|
9 Total Likes
|
 Sometimes when we have some equations we wish to add a constant to both sides or multiply by a factor.If you naively try: eq1 = a == b; eq2 = c == d; eq1 + 1 (* Out: 1 + (a == b) *) eq1 + eq2 (* Out: (a == b) + (c == d) *) 2*eq1 (* Out: 2*(a == b) *) To augment the functionality of Equal, we need to change built-in functions (not a smart idea).To do so we'll use the following lines of code: SetEqual = (Unprotect@Equal; (* HoldPattern is needed to avoid missinterpretation of the pattern *) Equal /: HoldPattern@Plus[Equal[a_, b_], c : Except[Equal[__], _]] := a + c == b + c; Equal /: HoldPattern@Plus[Equal[a_, b_], Equal[c_, d_]] := a + c == b + d; Equal /: HoldPattern@Times[Equal[a_, b_], c : Except[Equal[__], _]] := a*c == b*c; Equal /: HoldPattern@Power[Equal[a_, b_], c : Except[0, _]] := a^c == b^c; HoldPattern@Equal[L : List[a_, b__], c_] := (# == c & /@ L); Protect@Equal;) (* Undo built-in modifications *) ClearEqual := (Unprotect@Equal; Clear@Equal; Protect@Equal;) (* Make Simplify not change sides *) SimplifySides[Equal[a_, b_]] := Simplify@a == Simplify@b SimplifySides[L_List, args___] := SimplifySides[#, args] & /@ L With this (after calling SetEqual) we have: eq1 + 1 (* Out: 1 + a == 1 + b *) eq1 + eq2 (* Out: a + c == b + d *) 2*eq1 (* Out: 2*a == 2*b *) And after we can just call ClearEqual to avoid any mishaps.With this we can complete the square: *Where the use of HoldForm is needed otherwise Simplify is not smart enough. Also, List is needed because of the Plus or Minus square roots of the equation. Answer
18 Replies
Sort By:
Posted 4 years ago
 Unprotect@Equal --- you like to live dangerously ;-) Answer
Posted 4 years ago
 "Oh, behave!"If you get the reference. ;) Answer
Posted 4 years ago
 We have been waiting decades already for a natural way of transforming equations in Mathematica. We can work around the problem without unprotecting Equal. Introduce this operator: mapToSidesOfEquations[action_] := % /. eq_Equal :> Map[action, eq] Then you can transform your equation in simple steps within a single cell: a x^2 + b x + c == 0 (# - c)/a & // mapToSidesOfEquations Expand // mapToSidesOfEquations # + (b/(2 a))^2 & // mapToSidesOfEquations Expand // mapToSidesOfEquations % /. b -> HoldForm[b/(2 a)] 2 a Factor // mapToSidesOfEquations % // ReleaseHold Simplify // mapToSidesOfEquations % /. u_^2 == v_/z_^2 :> (u == Sqrt[v]/z) \[Or] (u == -Sqrt[v]/z) # - b/(2 a) & // mapToSidesOfEquations Together // mapToSidesOfEquations It is less convenient to type. Answer
Posted 4 years ago
 We have been waiting decades already for a natural way of transforming equations in Mathematica. Yeup, I'm always solving equations by hand, so the trick of SetEqual and ClearEqual works, since I never call Solve while solving by hand (it would be an oxymoron).I used to have a function wrapper loike yourself, but, it gets messy... Answer
Posted 4 years ago
 What happens when you call Solve[] with the modified equal? I never understood why I couldn't operate on equations in mathematica as nature intended :( Answer
Posted 4 years ago
 You can 'edit' equations using Thread: eq = a == c + b eq2 = g == h + k Thread[eq + 3, Equal] Thread[eq*2, Equal] Thread[eq^2, Equal] Thread[Log[eq], Equal] Thread[eq + eq2, Equal] It is a bit cumbersome, but it nicely extends to 'equations' of larger size: a == b+c == d+e+f Answer
Posted 4 years ago
 You can 'edit' equations using Thread: There are countless ways of parsing it. Thread is a very nice one (I'll be using it sometimes)! But I really don't like those large equations.But I really don't get it. You can differentiate an Equal equation (you can't integrate though...), you can use Series with it, and possible others functions can operate on it, but you can't add a constant to both sides... Answer
Posted 4 years ago
 I totally agree. It would also be nice to have (a>b)+1 be automatically evaluated to a+1>b+1. And so on. I only wonder if Wolfram is afraid of breaking some old code by allowing automatic threading over equations. Answer
Posted 4 years ago
 I think they never will: you should see equations as things that are either True, False, or Unevaluated. For the unevaluated case discussed above it makes sense to add '1' to each side, or to square both sides. However for the True and False case, this does not make any sense. What is True + 1?Currently all the operations you can do on equations are designed such that one can symbolically manipulate it (expand, simplify, et cetera) and then fill in the numbers, or the other way around, it gives the same result (the operations commute). This breaks for cases where you add '1' and fill in the numbers (or adding equations, or squaring them, or ...): eq = a == c Thread[eq + 1, Equal] /. {a -> 1, c -> 1} Thread[(eq /. {a -> 1, c -> 1}) + 1, Equal] The addition of 1 to an equation and filling in the values are two operations that don't commute. Of course you can make exceptions; if it is True/False then it does not make sense to 'add 1' or add up two equations that are True/Faslse. The problem with that, however, is that this goes very much against the symbolic nature of the Wolfram Language where one can add pictures to strings, and numbers to graphs and whateverWhat WOULD be useful if there would be some e.q. wrapper or function(ality) that facilitates these operations. But changing the current definitions would be messy and more likely break the symbolic nature of Wolfram Language. Answer
Posted 4 years ago
 If an equation becomes True after some transformation, I stop there and have no reason to add 1. Or we could operate on Inactive[Equal], which would avoid the trap. Answer
Posted 4 years ago
 I think they never will: you should see equations as things that are either True, False, or Unevaluated. For the unevaluated case discussed above it makes sense to add '1' to each side, or to square both sides. However, for the True and False case, this does not make any sense. What is True + 1? One could argue that Series[False, {x,0,1}] and D[True, x] doesn't make sense since False or True are not numbers. Hence they cannot be "constant" or anything whatsoever unless you have a very loose definition to account this.It's not that Mathematica allows nonsense as True^2 or Cos[True], it just simple remains "unevaluated."Other nonsense examples are Simplify[True^2 == True^2] which evaluates to True. Sometimes Mathematica knows True is boolean and sometimes it just thinks it is a Symbol.So, there are many instances where True is treated as a constant, even though it is not a number (any Symbol is a constant in the view of D).But the best practice is, when solving manually, stop when things evaluate to True :). Answer
Posted 4 years ago
 I would say: Why D and Series do support Equal as an argument is more of a question, than why equal does not work with Plus. It's not that Mathematica allows nonsense as True^2 or Cos[True], it just simple remains "unevaluated." That's not how I would formulate it: It does allow for it and it remains unevaluated (i.e. it does not spawn an error like many other languages!). Simplify[True^2 == True^2] Equal just checks if the lhs and rhs are the same, nothing more. So it still does not interpret it here as a boolean or whatever. But the best practice is, when solving manually, stop when things evaluate to True :). I agree but if you have some automated script that takes user-input (an equation). and you want to work on it reliably it is tricky, because that would involve constantly checking if it is evaluated to True or False or unevaluated. Answer
Posted 4 years ago
 I don't understand yet why D does work to be honest seems, at first sight, 'off' Answer
Posted 4 years ago
 The Thread method fails in more complicated cases: eq = a == c + b eq2 = g == h + k Thread[eq - eq2, Equal] Thread[2 eq + 1, Equal] Answer
Posted 4 years ago
 You can only do one operand at the time using the above code, so you would need nesting, e.g.: Thread[eq + Thread[-eq2, Equal], Equal] first 'minus' then 'add' or first multiply then add Answer
Posted 4 years ago
 How about this: Format[inactiveEqual[a_, b___]] := Inactive[Equal][a, b]; inactiveEqual /: (f_)[inactiveEqual[a___]] /; MemberQ[Attributes[f], Listable] := Map[f, inactiveEqual[a]]; inactiveEqual /: inactiveEqual[a___] + b : Except[_inactiveEqual] := Map[# + b &, inactiveEqual[a]]; inactiveEqual /: inactiveEqual[a___]*b : Except[_inactiveEqual] := Map[#*b &, inactiveEqual[a]]; inactiveEqual /: inactiveEqual[a___] + inactiveEqual[b___] /; Length[{a}] == Length[{b}] := Apply[inactiveEqual, {a} + {b}] You can do manipulations with automatic threading and nice formating: inactiveEqual[a, b] % // Exp % + inactiveEqual[x, y] % + 1 2 % 1 - % Answer
Posted 4 years ago

I was pointed to a tiny package for this written by Roman Maeder: Automatic Threading of Equations. Quoting the description:

this little utility was originally developer for DMUG, the German Mathematica User Group (http://www.mathematica.ch/). It answers a frequently asked question about the manipulation of equations. Mathematica does not "thread" arithmetic and other functions over equations, so the following naive approach to solving equations by rearranging terms does not work:

In:= 1 + x == 2

In:= %-1

Out= -1 + (1 + x == 2)


To make this work, the symbol Equal (the head of an equation) should behave like List with respect to listable functions. Just as {a,b}+1 turns into {a+1, b+1}, one may want (a==b)+1 to turn into a+1 == b+1. This can be achieved explicitly with Thread:

In:= Thread[(a==b) + 1, Equal]

Out= 1 + a == 1 + b


The automatic transformation of f[a, b, c, ...] into Thread[f[a, b, c, ...]] should happen whenever f has the attribute Listable and at least one of the arguments a, b, ... has head Equal. This definition is essentially what is needed:

Equal/: lhs:f_Symbol?listableQ[___, _Equal, ___] :=

listableQ[f_] := MemberQ[Attributes[f], Listable]


The use of "Unevaluated" prevents an infinite recursion. Together with the necessary framework, the definition is in the little package EqualThread.m.

Now, you can solve equation as you did in school:

In:= Needs["EqualThread"]


the equation, to be solved for x:

In:= a == b Log[2 x]


divide by b:

In:= %/b
a
Out= - == Log[2 x]
b


exponentiate:

In:= Exp[%]

a/b
Out= E    == 2 x


divide by 2:

In:= %/2

a/b
E
Out= ---- == x
2


You can also add equations, etc.:

In:= (a==b) + (c==d)

Out= a + c == b + d


~ Roman M=E4der

# CODE

(* :Title: make equations behave like lists *)

(* :Author: Roman E. Maeder *)

(* :Summary:
make listable functions thread over equations as they do over lists.
Allows for easy manipulation of equations.
*)

(* :Context: EqualThread *)

(* :Package Version: 1.1 *)

Permission is granted to use and distribute this file for any purpose
except for inclusion in commercial software or program collections.
This copyright notice must remain intact.
*)

(* :History:
Version 1.1 for mathgroup and MathSource, January 1998.
Version 1.0 for DMUG (German Mathematica User Group), January 1998.
*)

(* :Keywords:
*)

(* :Warning: Adds definitions to the built-in symbol SystemEqual.
*)

(* :Mathematica Version:3.0 *)

BeginPackage["EqualThread"]

(* no exports *)

Begin["Private"]

listableQ[f_] := MemberQ[Attributes[f], Listable]

protected = Unprotect[Equal]

Equal/: lhs:f_Symbol?listableQ[___, _Equal, ___] :=

Protect[Evaluate[protected]]

End[]

EndPackage[] Answer
Posted 3 years ago
 I hope you noticed the new in 11.3 functions AddSides, MultiplySides, etc. These handle equations, inequalities, piecewise expressions, and more.There are arguments for and against thread. I would say the main argument against is that the moment you get to multiplcation and division you need to incoroprate assumptions and/or conditions, and suddenly it is now a mathematical rather than structural operation. These new functions allow you to control this behavior (with carefully considered defaults, of course). Answer