# How to use Solve rules as a function body?

Solve gives me an expression which I want to use as the body of a function. Rather than run Solve every time inside my function body, I just want to take the rule output Solve already gave me, and repurpose it into something that accepts arguments.

For example, this works, but is slow because Solve runs in every invocation:

(* returns the two points where the line through pt {x1, y1}
with slope m intersects the circle x^2 + y^2 = 100 *)
intersections[m_, x1_, y1_] :=
Solve[y - y1 == m (x - x1) &&
x^2 + y^2 == 100, {x, y}] /. Rule[_, val_] -> val

intersections[1, 0, 0]
(* result: *) {{-5 Sqrt[2], -5 Sqrt[2]}, {5 Sqrt[2], 5 Sqrt[2]}}


I've tried variations on below, but they don't work:

solution = Solve[y - y1 == m (x - x1) &&
x^2 + y^2 == 100, {x, y}] /. Rule[_, val_] -> val /. {m -> #1,
x1 -> #2, y1 -> #3}

intersections[m_, x1_, y1_] := solution[m, x1, y1]


Below is almost what I want, but the rule replacements don't perform as well as real function arguments, and this is also dependent on copying around replacement symbol names:

solution = Solve[y - y1 == m (x - x1) &&
x^2 + y^2 == 100, {x, y}] /. Rule[_, val_] -> val ;
intersections := solution /. { m -> #1, x1 -> #2, y1 -> #3} &;


How can I take the the expression Solve gave me, and "function-ify" it? Copy-pasting the expressions into a function works, but obviously I don't want to do that.

Use Block or Formal Symbols to guard against unwanted evaluation, then define your function using Set (=) rather than SetDelayed (:=). Might as well throw in a FullSimplify to clean it up a bit.

Block[{x, y, x1, y1, m},
intersections[m_, x1_, y1_] = FullSimplify[
{x, y} /. Solve[y - y1 == m (x - x1) && x^2 + y^2 == 100, {x, y}]
]
];

intersections[1, 0, 0]

{{-5 Sqrt[2], -5 Sqrt[2]}, {5 Sqrt[2], 5 Sqrt[2]}}


A look at the definition we created:

?intersections


A related abstraction:

Here's a way to create a pure function:

ClearAll[functionify];
functionify[v__][sol_] := functionify[sol, Flatten@{v}];
functionify[sol_, v_] :=
Function[v, #] &[sol /. {{r_Rule} :> Last@r, r_Rule :> Last@r}];


If you list the variables, functionify[v1, v2] uses the symbols as the arguments to the Function constructed from the solutions. Example:

intersections =
Solve[y - y1 == m (x - x1) && x^2 + y^2 == 100, {x, y}] //
functionify[m, x1, y1]

intersections[1, 0, 0]
(*  {{-5 Sqrt[2], -5 Sqrt[2]}, {5 Sqrt[2], 5 Sqrt[2]}}  *)


If you want to solve the equation once, and use the solution again, then you can try

sol = Solve[y - y1 == m (x - x1) && 4 x^2 + y^2 == 100, {x, y}];
intersections[mm_, xx1_, yy1_] :=
{x /. sol /. {x1 -> xx1, m -> mm, y1 -> yy1},
y /. sol /. {x1 -> xx1, m -> mm, y1 -> yy1}
}


Now you can call it as

intersections[1, 2, 3]


which gives

{{(1/5)*(-1 - 4*Sqrt[31]), (1/5)*(-1 + 4*Sqrt[31])}, {4/5 - (4*Sqrt[31])/5, 4/5 + (4*Sqrt[31])/5}}


Solve is only called once as you asked for. The solution is used again and again

• This is pretty much the same as my last example. Commented Dec 7, 2012 at 19:30