How could I define a function as the solution of equations in Mathematica?

I have posed a specific question yesterday but it may be too trivial to answer.

I think the question could be asked in a more general way so it is easier to answer. Then I could solve the original problem by myself.

Usually, we define a function as

F[x_] := x + 10

where the right-hand side is an expression.

Now, I would like define a function where the right-hand side is the solution of a set of equations. Like

optV[V_, r_, λ_, μ_, η_, σ_] :=
V /.
FindRoot[{
A V^θ[r, λ, μ, η, σ] h[V, c, r, λ, μ, η, σ] == V - c,
D[A*V^θ*h[V, c, r, λ, μ, η, σ], V] == 1
},
{A, 0}, {V, 1}];

a[V_, r_, λ_, μ_, η_, σ_] :=
A /.
FindRoot[{
A V^θ[r, λ, μ, η, σ] h[c, r, λ, μ, η, σ] == V - c,
D[A V^θ[r, λ, μ, η, σ]  h[V, c, r, λ, μ, η, σ], V] == 1
},
{A, 0}, {V,1}]

This may not be correct code, but I think you can understand my question from it. optV and a are both parameters for another final function which would be manipulated. So you could regard optV and a as intermediate parameters. So the solution of the set of equations, correspondingly optV and a, varies along with c, r, λ, μ, η, σ, which are parameters input for manipulating plot.

• Since NSolve[] will return a list of lists, you'll likely want to put Part[] in there somewhere... – J. M. will be back soon Jun 17 '13 at 17:45
• – Dr. belisarius Jun 17 '13 at 17:49
• @bel, FWIW: it's one of the songs I listen to after a hard day... precisely that medley. – J. M. will be back soon Jun 17 '13 at 17:51
• Just yesterday I posted an answer where this is illustrated. There are countless other answers on this site that do similar things. Maybe just searching for NDSolve will turn up other good examples. – Jens Jun 17 '13 at 17:56
• you can easily do what you asked, eg.f[a_] := x /. NSolve[{x + y == a, x^2 + y^2 == 1}, {x, y}]. I cant understand what your intent is with those examples though. The arg x on input does what? – george2079 Jun 17 '13 at 18:37

If I understand you right, here is the answer, but it is in a form of a more transparent example.

Let this

Clear[a,b];
eq=x^2 - b*x - 1 == 0

be an equation depending upon a parameter b with b>0. Let us define a=a[b] which is its smaller solution of the equation eq:

a[b_] := Solve[eq, x][[1, 1, 2]]

It seems that this (or something alike) is what you need. You can check that a is indeed a function of b by, say, plotting a[b]. Evaluate this:

Plot[a[b], {b, 0, 3}]

With some care one can do the same with the FindRoot statement:

Clear[a,b];
a[b_] := FindRoot[eq, {x, 0}][[1, 2]]
Plot[a[b], {b, 0, 3}]
• While this works, I would be careful about explicitely making eq a function of b: 'eq[b_] = x^2 - b*x - 1 == 0' and I would force the definition of a[b] to take only numeric values: a[b_?NumberQ]. In this example it is fine, but you have to be careful of the order of evaluation when you are mixing both symbolic and numerical values. – Jonathan Shock Jun 18 '13 at 8:41
• Isn't it inefficient to call Solve every time the function a is evaluated? If you used Set instead of SetDelayed, the equation would only be solved once. – Niki Estner Jun 18 '13 at 9:07
• @nikie yes in this simple example. There are however situations where you need to Solve (or especially NSolve ) for the specific value of the parameters. – george2079 Jun 18 '13 at 19:15

I will give an elaborate answer because I think this is an area where Mathematica really shines ;)

Let me digress.

We know that, in general, an equation system defines a set of points as a function of the parameters in it. Namely, the set of variable assignments or valuations that make the equation true.

Thus an equation system can also be seen as a predicate $E(\vec x, \vec p)$ which defines the set of its solutions given the parameters $\vec p$: $$sol(E, \vec p) := \{\vec x : E(\vec x, \vec p)\}$$

Note that "solving" an equation system, even for given parameter values (for example if you have no parameters) does not usually give a single value $\vec x$.

Now what does mathematica's Solve[E, {x1,...,xn}] (or NSolve) do? It gives a representation of this set in the form of a finite list of replacement rule sets, $\{r_1, r_2, ..., r_n\}$.

Each $r_i$ contains rules of the form $x_{ij} \mapsto f_{ij}(\vec x', \vec p)$. Let $(\vec x)_i'$ be the sublist of $\vec x$ not appearing as an $x_{ij}$ (on the left hand side of a rule), $(\vec x)_i''$ be the others. Then the ruleset $r_i$ defines a map $F_i$ with $$(\vec x)_i'' := F_i((\vec x)_i', \vec p).$$ The set of solutions is then characterized as follows: $$\vec x \in sol(E, \vec p) \iff \exists i\quad (\vec x)_i'' = F_i((\vec x)_i', \vec p).$$

Turning this into a function

Ideally, we would want to get a function $G$ with

$$G(\vec p) := sol(E, \vec p)$$

Obviously, this is in general impossible because the set of solutions is infinite (sometimes not even countable).

But assume we knew $E$ has a finite amount of solutions for every fixed $\vec p$. Can we derive these from the output of Solve?

In general no, one because of the parameters $\vec C$ mathematica might add to describe the solution space and because we dont know which $(\vec x)_i'$ will not generate Undefined values with the functions we are given. And we get no explicit way of enumerating only valid candidates.

Still, if the $F_i$ are total in $(\vec x)_i'$ we might be able to leverage them to describe our solution space in a more explicit way.

In particular, we can ask Mathematica to give us the solution in 1 variable in terms of the parameters and the others, simply by 'solving' for that variable only. Using ParametricPlot and friends you can then visualize the solution.

Wrap up

Lets assume you know that $(\vec x)_i'' = \vec x$ for all $r_i$, i.e. that all variables you care about have been explicitly solved for. Then the function $$f(\vec p) := \{F_1(\vec p), ...,F_n(\vec p)\}$$ can be defined in the following two ways in mathematica. (Let us write {{x1, ...}*} = f[{p1, p2,...}]).

1. Solving the equation system once

If you know (or enforce) that x1,...,p1,... are undefined at the point of definition:

ClearAll[f, p1, p2, x1, x2];
(*Define f[{p1,...,pn}]. {x1,...,xn, p1,...,pn} must not be defined at this point \
for this to work*)
f[{p1_, p2_}] := Evaluate[{x1, x2} /. Solve[
(*The equation system*)
x2 == p1^2 + p1 && p2 == x1,
{x1, x2}]];
(*Test*)
?f
f[{3, 4}]

Otherwise (namespace-clean version):

ClearAll[f];
(*Prepare f*)
Evaluate[Module[{x1, x2, p1, p2},
f[params] = {p1, p2};
f[variables] = {x1, x2};
f[solutions] = f[variables] /.
Solve[
(*The equation system*)
x2 == p1^2 + p1 && p2 == x1, f[variables]]]
];
(*Define f[{p1,...,pn}]*)
f[p_] := f[solutions] /. Rule @@@ Transpose@{f[params], p};
(*Test*)
?f
f[{3, 4}]

2. Solving the equation system on every call

Namespace-dirty version -- x1,... must not be defined when calling f.

ClearAll[f, x1, x2];
(*When calling this function, x1,...,xn must be undefined*)
f[{p1_, p2_}] := {x1, x2} /. Solve[
(*The equation system*)
x2 == p1^2 + p1 && p2 == x1,
{x1, x2}];
(*Test*)
?f
f[{3, 4}]

To make this clean, simply wrap the definition in a module:

ClearAll[f, x1, x2];
Module[{x1, x2},
f[{p1_, p2_}] := {x1, x2} /. Solve[
(*The equation system*)
x2 == p1^2 + p1 && p2 == x1,
{x1, x2}];
];
(*Test*)
?f
f[{3, 4}]

Some more details

1. Note that the $F_i$ are in general partial functions. You may get

x -> ConditionalExpression[1, a > 0]

which is Undefined for certain values, try it:

ConditionalExpression[1, a > 0] /. {a -> 0}

2. The above explanation makes it clear why {} denotes the empty set of solutions.

And also why {{}} is the full dimensional set of solutions: In this case $(\vec x)_1' = \vec x$, $(\vec x)_1''$ is empty and the function $F_1$ returns nothing, thus $(\vec x)_1'' = F_1((\vec x)_1',\vec p)$ for any $\vec x$.

3. Sometimes Solve will introduce new parameters $\vec C$ in the solution. These parametrize the $F_i$ so that actually, implicitly, infinitely many $F_i$ are available to pick to construct a solution:

$$\vec x \in sol(E, \vec p) \iff \exists i\exists \vec C\quad (\vec x)_i'' = F_i((\vec x)_i', \vec p, \vec C).$$

1. Because "Solve gives generic solutions only. Solutions that are valid only when continuous parameters satisfy equations are removed" the picture I painted above is a bit too simple. Sometimes there will be solutions that Mathematica is well aware of but does not give because of this. It will generate ConditionalExpression with inequalities for parameters:

Solve[x^2 == a - b, x, Reals]

{{x -> ConditionalExpression[-Sqrt[a - b], a > b]}, {x -> ConditionalExpression[Sqrt[a - b], a > b]}}

but by default 'forgets' all solutions that would require an equality between parameters:

Solve[x == 0 && x^2 == a - b, x, Reals]

{}

It will also generate solutions that are wrong for a finite set of parameter assignments: Solve[x a == 1 , {x, y}] {{x -> 1/a}}

I don't see why you shouldn't always use MaxExtraConditions -> All which gives these solutions back:

Solve[x == 0 && x^2 == a - b, x, Reals, MaxExtraConditions -> All]

{{x -> ConditionalExpression[0, a == b]}}

Solve[x a == 1 , {x, y}, MaxExtraConditions -> All]

{{x -> ConditionalExpression[1/a, a != 0]}}