10

Is there an elegant way to use $\pm$ in equations, without having to make a text change and substitution using an Or function?

For instance, I would like this equation

Solve[x \[PlusMinus] 2 == 0, x]

to be solved to {{x -> -2},{x -> 2}}

and Plot[\[PlusMinus] x^2, {x, 0, 1}] to give two branches, of the form

Plot[{x^2, -x^2}, {x, 0, 1}]
Glorfindel
  • 547
  • 1
  • 8
  • 14
David G. Stork
  • 41,180
  • 3
  • 34
  • 96
  • 1
    Should Solve[x \[PlusMinus] 2 + Exp[ \[PlusMinus] 2] == 0, x] denote two cases, four cases, or simply be disallowed? – Michael E2 Jul 02 '18 at 17:42
  • Oh... I would say four cases. – David G. Stork Jul 02 '18 at 17:43
  • This is far from a perfect response, but the way I would handle it in simple cases would be to choose "-", negate both sides, then replace "x" with Abs[x].

    Solve[2 - Abs[x] == 0, x, Reals] gives {{x -> -2}, {x -> 2}}.

    – kjosborne Jul 02 '18 at 18:23
  • @josborne: That's a help, but your approach gets very awkward when one tries to solve even something as simple as Solve[Abs[x \[PlusMinus] 2] \[PlusMinus] 3 == 0, x]. – David G. Stork Jul 02 '18 at 18:38
  • What about something like LogicalExpand@Reduce[{Abs[x + f 2] + f2 3 == 0, Abs@f == 1, Abs@f2 == 1, (f | f2) \[Element] Reals}, x]? - Essentially this replaces a ± b with a + f b && (f==1 || f==-1) – Lukas Lang Jul 02 '18 at 19:40
  • @LukasLang: Interesting approach, but a bit kludgy, reliant on hand analysis of the structure of the equation, and the resulting solution is rather complicated and involves Im[x] (fixed with x \[Element] Reals). Better would be a "wrapper" function that did the analysis automatically... but even there, it is a bit kludgy. – David G. Stork Jul 02 '18 at 19:44
  • Note that for Plot to plot all combinations of signs, the functions need to be in a List; but Solve[{eqplus, eqminus} == 0,...] and Solve[{eqplus == 0, eqminus == 0},...] implicitly join the equations with And and not Or. So the built-in syntax of Plot vs. Solve/Reduce leads to some incompatibility that needs to be overcome. – Michael E2 Jul 03 '18 at 17:12

3 Answers3

9

The following function performs the transformation I've suggested in the comments:

Options[PMReduce] = {"SynchronizePM" -> False};
PMReduce[eqns_, vars_, dom_: Complexes, OptionsPattern[]] := Module[
  {
   pEqns,
   params,
   i = 0,
   step = Boole[! OptionValue@"SynchronizePM"]
   }, {pEqns, params} = Reap[
    Flatten@{eqns} //. {
      (a_ ± b_) :> (a + Sow[C[i += step]] b),
      (a_ ∓ b_) :> (a - Sow[C[i += step]] b)
      }
    ];
  Reduce[
   Append[
    pEqns,
    And @@ (# == 1 || # == -1 & /@ First@params)
    ],
   vars,
   dom
   ]
  ]

The "SynchronizePM" option controls whether the ± should be changed synchronously (i.e. a±b±c to a+b+c||a-b-c)

Examples:

PMReduce[Abs[x ± 2] ± 3 == 0, x, Reals]
(* (C[1] == -1 && C[2] == -1 && x == -1)
|| (C[1] == -1 && C[2] == -1 && x == 5)
|| (C[1] == -1 && C[2] == 1 && x == -5)
|| (C[1] == -1 && C[2] == 1 && x == 1) *)

PMReduce[Abs[x ± 2] ± 3 == 0, x, Reals, "SynchronizePM" -> True]
(* (C[0] == -1 && x == -1) 
|| (C[0] == -1 && x == 5) *)
Lukas Lang
  • 33,963
  • 1
  • 51
  • 97
  • Oh... very nice. And I've tried the code on several non-obvious equations and sets of equations with excellent results. (Accept) – David G. Stork Jul 02 '18 at 20:54
  • Thanks for the accept! For completeness, I've updated the answer with an option to control whether the ± should be changed simultaneously and added support for – Lukas Lang Jul 02 '18 at 21:10
7

I may need to give this more thought but it seems to me you actually want Or.

For example:

a_: 0 ± n_ := a - n || a + n

Solve[x ± 2 == 0, x]

Solve[Abs[x ± 2] ± 3 == 0, x]
{{x -> -2}, {x -> 2}}

{{x -> -5}, {x -> -1}, {x -> 1}, {x -> 5}}


In light of your edit to include Plot we could either allow the expansion above and modify Plot to operate on Or, or we could modify both Solve and Plot (etc.) to specially handle ±. Doing my best to read between the lines I think you prefer the latter, so I'll illustrate that.

ClearAll[PlusMinus]

Plot;
Unprotect[Plot];
PrependTo[DownValues[Plot], 
  HoldPattern[Plot[expr_, arg___]] /; ! TrueQ[$plotPlusMinus] :>
    Block[{$plotPlusMinus = True}, 
      Plot[#, arg] &[expr //. a_: 0 ± n_ :> {a - n, a + n}]
    ]
];
Protect[Plot];

Plot[x + Sin[±x] ± 1/2, {x, 0, 8}]

enter image description here

Notes

  • This assumes the plot function is composed of Listable functions; if that does not hold manual threading can be added, but I first want to know if this is moving in a direction that pleases you or not.

  • I did not localize the Plot variable(s). That can be done but again I first want to know if this is going to be useful.

Mr.Wizard
  • 271,378
  • 34
  • 587
  • 1,371
  • Perhaps... but my question stated: "...without having to make a text change and substitution using an Or function" – David G. Stork Jul 02 '18 at 21:17
  • @DavidG.Stork But I don't understand; why would you avoid Or if it is actually the solution? I tried to provide syntactic sugar to that end, though I'm sure you were capable as well. I feel like I'm missing something here; I was hoping you'd provide an example where this fails. – Mr.Wizard Jul 02 '18 at 21:19
  • @DavidG.Stork Perhaps you want ± to expand only inside of Solve? – Mr.Wizard Jul 02 '18 at 21:22
  • Solve was just one function that needs to handle \{PlusMinus, but there are many others, e.g., Plot[\PlusMinus] x^2, {x, 0, 1}], Simplify, etc. – David G. Stork Jul 02 '18 at 21:32
  • @David wouldn't it be best to overload each of these functions for ±? I don't see how one universal expansion can address your needs. – Mr.Wizard Jul 02 '18 at 21:34
  • @MrWizard. I too don't see immediately how a universal expansion can be used, but I thought I'd search. The substitution with Or seemed straightforward, but @LukasLang's solution was superior (as far as I could see). Perhaps Wolfram should incorporate \[PlusMinus] much the way they have handled automatically Which and other function partition methods. – David G. Stork Jul 02 '18 at 21:38
  • @David Isn't this notation often used to describe an interval rather than two discrete values? I think a different notation is needed for the latter if it is going to be integrated. Maybe Plot[3 || 7, {x, 0, 5}] should give the same output as Plot[{3, 7}, {x, 0, 5}]? Anyway you said Lukas's solution is superior, and it probably is, but could you give me an example where it works and mine does not? – Mr.Wizard Jul 02 '18 at 21:43
  • I don't know of an application where Lukas' solution works and yours does not, but he was 40 minutes earlier than you, works fine for all my cases, and hence he gets the accept. Thanks for your "polishing" of his key insight, though! – David G. Stork Jul 02 '18 at 21:47
  • @MichaelE2 What output is that giving you? In v10.1 I get a bunch of ConditionalExpression which I'm guessing you were working to avoid. – Mr.Wizard Jul 02 '18 at 22:19
  • 5
    @DavidG.Stork I would point out that you can't really avoid Or (well, without, say, mapping Solve over the alternatives). Note Lukas's solution does not avoid Or: it takes and sticks in the Or's after reaping the text-replaced alternatives. – Michael E2 Jul 02 '18 at 22:35
2

Little improving magnificent code from user Lukas Lang:

SOLVE[eqns_, vars_, dom_: Complexes] := {{ToRules[Module[{pEqns, params, i = 0}, {pEqns, params} = 
Reap[Flatten@{eqns} //. (a_ \[PlusMinus] b_) :> (a + Sow[f[i++]] b)];
Reduce[Append[pEqns, And @@ (# == 1 || # == -1 & /@ First@params)], vars, dom]]]}[[All, -1]]}


SOLVE[x ± 2 == 0, x]
(* {{x -> 2, x -> -2}} *)

SOLVE[Abs[x ± 2] ± 3 == 0, x, Reals]
(* {{x -> -1, x -> 5, x -> -5, x -> 1}} *)
Mariusz Iwaniuk
  • 13,841
  • 1
  • 25
  • 41