I understand Mathematica can't assign the results of a Solve to the unknowns because there may be more than 1 solution. How can I assign the 4 values of following result to variables?
Solve[y^2 == 13 x + 17 && y == 193 x + 29, {x, y}]
Mathematica Stack Exchange is a question and answer site for users of Wolfram Mathematica. It only takes a minute to sign up.
Sign up to join this communityYou can do this :
s = Solve[y^2 == 13 x + 17 && y == 193 x + 29, {x, y}];
xx = s[[All, 1, 2]];
yy = s[[All, 2, 2]];
Now you can access solutions, this way xx[[1]]
, yy[[2]]
.
If you prefer to collect solutions in Array
, there is another way :
X = Array[ x, {Length@s}];
Y = Array[ y, {Length@s}];
x[k_] /; MemberQ[ Range[ Length @ s], k] := s[[k, 1, 2]]
y[k_] /; MemberQ[ Range[ Length @ s], k] := s[[k, 2, 2]]
now X
is equivalent to s[[All, 1, 2]]
, while Y
to s[[All, 2, 2]]
, e.g. :
X[[1]] == x[1]
Y == s[[All, 2, 2]]
True True
You do not have to use or even to define X
and Y
arrays,
e.g.
{x[1], y[1]}
{(-11181 - Sqrt[2242057])/74498, 1/386 (13 - Sqrt[2242057])}
We've used Condition
i.e. /;
to assure definitions of x[i], y[i]
only for i
in an appropriate range determined by Length @ s
, i.e. number of solutions.
ReplaceAll
. This might be a bit too advanced for someone new to Mma.
$\endgroup$
assignment
tag, so he is rather looking for Set
or SetDelayed
applications.
$\endgroup$
FullForm[s]
.
$\endgroup$
Part
then you'll understand what such a notation as [[i,j,k]]
mean.
$\endgroup$
Usually you don't want to actually assign values to x
and y
, and you would use replacement rules instead:
sols = Solve[y^2 == 13 x + 17 && y == 193 x + 29, {x, y}];
{x, y} /. sols[[1]]
or for the second solution:
{x, y} /. sols[[2]]
If you really want to assign values to x
and y
globally, you could use:
Set @@@ sols[[1]]
but you must clear x
and y
before using another set:
Clear[x, y]
Set @@@ sols[[2]]
If you want to assign values to x
and y
within a Block
you could do something like this:
Hold @@ {sols[[2]]} /. Rule -> Set /. _[vars_] :>
Block[vars,
Sin[x] + Sqrt[y] // N
]
This uses what I am calling the injector pattern to get the values into Block
in the right syntax without it prematurely evaluating.
Related questions:
Solve
will work better if it has this global value instead of trying to remain general for all possible values). I tried the equivalent of Set[sols[[1]]]
, and when that didn't work. Of course the "help" file is no help because it insists on explaining the symbol =
and not the function Set
, so I ended up here. What is Set @@@ sols[[1]]
doing?
$\endgroup$
Feb 21, 2016 at 22:39
@@@
is shorthand for Apply
at levelspec {1}
. So foo @@@ {x -> val1, y -> val2}
becomes {foo[x, val1], foo[y, val2]}
, or in the code in the question {Set[x, val1], Set[y, val2]}
, which then assigns the values with Set
. (=
is the shorthand for Set
.)
$\endgroup$
Feb 22, 2016 at 4:38
code
in HoldForm[FullForm[ code ]]
-- for example HoldForm[FullForm[ {x -> val1, y = val2} ]]
will reveal List[Rule[x, val1], Set[y, val2]]
. This "FullForm" expression is what you need to visualize when you think about Mathematica manipulating code. Virtually all Replace
, Map
, Apply
, Part
, etc. operations effectively "see" this structure, not the short form you type in. See e.g. HoldForm[FullForm[ a - b ]]
$\endgroup$
Feb 22, 2016 at 16:45
Update: Version 10 built-in function Values does value extraction conveniently for rules appearing in lists of arbitrary lengths and depths:
{{x1, y1}, {x2, y2}} = Values[Solve[y^2 == 13 x + 17 && y == 193 x + 29, {x, y}]]
(* {{(-11181-Sqrt[2242057])/74498,1/386 (13-Sqrt[2242057])},
{(-11181+Sqrt[2242057])/74498,1/386 (13+Sqrt[2242057])}} *)
Another example:
lst={{a->1,b->2},{c->3},{{d->4}},{e->5,{f->6,{g->7}}}};
Values[lst]
(* {{1,2},{3},{{4}},{5,{6,{7}}}} *)
Original post:
{{x1, y1}, {x2, y2}} = Solve[y^2 == 13 x + 17 && y == 193 x + 29, {x, y}][[All, All, -1]]
(* {{(-11181 - Sqrt[2242057])/74498, 1/386 (13 - Sqrt[2242057])},
{(-11181 + Sqrt[2242057])/74498, 1/386 (13 + Sqrt[2242057])}} *)
{x1, y2}
(* {(-11181- Sqrt[2242057]) / 74498, 1 / 386 (13 + Sqrt[2242057])} *)
Last@@@Solve[...]
.
$\endgroup$
If you really wish to assign solutions to variables, you can do something like this:
In[1]:= ClearAll[Subscript]
sols=Solve[y^2==13x+17&&y==193x+29,{x,y}];
i=0;
sols/.{r__Rule}:>Set@@@({r}/.var:x|y->Subscript[var,++i]);
Subscript//Definition
Out[5]=
Subscript[x,1]=(-11181-Sqrt[2242057])/74498
Subscript[x,2]=(-11181+Sqrt[2242057])/74498
Subscript[y,1]=1/386(13-Sqrt[2242057])
Subscript[y,2]=1/386 (13+Sqrt[2242057])
Then you can use the solutions for demonstration purposes:
Here's a painless solution:
s = Solve[y^2 == 13 x + 17 && y == 193 x + 29, {x, y}];
Assign the four results of the solution s above to a variable each, in sequence
{X1, Y1, X2, Y2} = s // Values // Flatten;
Verify
{X1, Y1, X2, Y2}
{(-11181 - Sqrt[2242057])/74498, 1/386 (13 - Sqrt[2242057]), (-11181 + Sqrt[2242057])/74498, 1/386 (13 + Sqrt[2242057])}
Ah, they finally implemented it in version 10, then! Here's a procedure I've been using since version 5, it might provide similar features in versions prior to the introduction of Value. (I'm not sure, but maybe I posted it on the MathGroup... so forgive me if this is not news)
I had called it "ToValues". I gave it two options:
Options[ToValues] = { Flattening -> Automatic, IndexedFunction -> False};
The help message is hopefully self-explicating:
ToValues::usage = "ToValues[li] suppresses the Rule wrapper in every part of list li.\n ToValues[li,F] \ applies the function F to every rhs of Rule, turning var->value into \ F[value]. If the function F has a parametrized head, then it is possible to \ pass the lhs of Rule to it by setting the option IndexedFunction->True. It will \ turn var->value into F[var][value].\n When the option Flattening is set to \ Automatic, ToValues flattens li to yield a simplified structure (the \ flattening is tuned to get the simplest list of values for the solution of a \ system of several equation in several variables). With Flattening set to None \ the original structure is left intact.";
The code is really short.
ToValues[li_, opts___Rule] := Module[ {newli, vars, sols, fl}, fl = Flattening /. {opts} /. Options[ToValues]; sols = First[Dimensions[li]]; vars = Last[Dimensions[li]]; newli = li /. Rule[_, v_] -> v; If[fl == Automatic && vars == 1, newli = Flatten[newli]]; If[fl == Automatic && sols == 1, First[newli], newli] ] ToValues[li_, fun_, opts___Rule] := Module[ {newli, vars, sols, foo, fl, mi}, mi = IndexedFunction /. {opts} /. Options[ToValues]; fl = Flattening /. {opts} /. Options[ToValues]; If[mi == True, newli = li /. (x_ -> v_) -> foo[x][v], newli = li /. (_ -> v_) -> foo[v] ]; sols = First[Dimensions[li]]; vars = Last[Dimensions[li]]; If[fl == Automatic && vars == 1, newli = Flatten[newli]]; If[fl == Automatic && sols == 1, First[newli], newli] //. foo -> fun ]
Example data:
sols = {{x -> 1}, {y -> 2}, {z -> 3}};
Application of ToValues to lists of rules produces a list of values
ToValues[sols] // InputForm
{1, 2, 3}
Of course assignment is immediate, here
{x1,x2,x3} = ToValues[sols]
By default, ToValues returns the simplest list of values possible, suppressing nested list. If you want to preserve the original nesting, this is what the Flattening option does:
ToValues[sols, Flattening -> None] // InputForm
{{1}, {2}, {3}}
We can specify a function to be applied to the returned values.
ToValues[sols, F] // InputForm
{F[1], F[2], F[3]}
We can also use function that make use of the right hand sides of the rules. Just define them as functions with a parametrized Head and set IndexedFunction->True to instruct ToValues to make use of that. In this case we want to return lists in the form {variable name, variable value}:
F[var_][value_] := {var, value}
ToValues[sols, F, IndexedFunction -> True] // InputForm
{{x, 1}, {y, 2}, {z, 3}}
ToValues[sols, F, IndexedFunction -> True, Flattening -> None] // InputForm
{{{x, 1}}, {{y, 2}}, {{z, 3}}}
Real world applications
ToValues is normally used to extract solutions from the lists returned by Solve, NSolve, DSolve, etc. In its default form it can be applied in this way:
Solve[{x + y == 1, x - y == 2}] // ToValues
{3/2, 1/2}
This gives a list of the complex solutions
Solve[x^5 == 1] // ToValues
This uses the optional function to compute the real and imaginary part of each solution
coords = ToValues[Solve[x^5 == 1, x], {Re[#], Im[#]} &] // N;
ListPlot[coords, AspectRatio -> Automatic, Frame -> True,
PlotStyle -> PointSize[.018]];
And this pushes the function to create graphics objects (Points) based on those values inside ToValues:
pts = ToValues[Solve[x^9 == 1, x], Point[{Re[#], Im[#]}] &];
Show[Graphics[{PointSize[.018], pts}],
AspectRatio -> 1, Frame -> True, Axes -> True];
Someone who has patience enough might want to add the plots.
Here is an easy solution
s = Solve[y^2 == 13 x + 17 && y == 193 x + 29, {x, y}];
x1 = x /. s[[1, 1]];
y1 = y /. s[[1, 2]];
x2 = x /. s[[2, 1]];
y2 = y /. s[[2, 2]];
We can verify with
MatrixForm[{{x1, y1}, {x2, y2}}]
The output looks like
For reference, please look at assign.
Solve
orders y
results before or after x
. Here it does though, and that's not good at all.
$\endgroup$
Jun 8, 2018 at 23:26
In[9051]:= sol =
Solve[y^2 == 13 x + 17 && y == 193 x + 29, {x, y, x, y}] /.
Rule -> Set
Out[9051]= {{(-11181 - Sqrt[2242057])/74498,
1/386 (13 - Sqrt[2242057])}, {(-11181 + Sqrt[2242057])/74498,
1/386 (13 + Sqrt[2242057])}}
In[9055]:= x1 = sol[[1, 1]]
Out[9055]= (-11181 - Sqrt[2242057])/74498
In[9056]:= y1 = sol[[1, 2]]
Out[9056]= 1/386 (13 - Sqrt[2242057])
In[9057]:= x2 = sol[[2, 1]]
Out[9057]= (-11181 + Sqrt[2242057])/74498
In[9058]:= y2 = sol[[2, 2]]
Out[9058]= 1/386 (13 + Sqrt[2242057])
Replace
(orPart
) to assign the values to variables. $\endgroup$