# Operations with Equal.

GROUPS:
 Thales Fernandes 3 Votes 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.
26 days ago
16 Replies
 Kapio Letto 2 Votes Unprotect@Equal --- you like to live dangerously ;-)
25 days ago
 Thales Fernandes 1 Vote "Oh, behave!"If you get the reference. ;)
25 days 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.
25 days 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...
25 days 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 :(
24 days 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
25 days 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...
25 days 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.
25 days 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.
25 days 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.
25 days ago
 Thales Fernandes 1 Vote 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 :).
25 days 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.
25 days ago
 I don't understand yet why D does work to be honest… seems, at first sight, 'off'
25 days 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] 
25 days 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…
25 days 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 - %