4
$\begingroup$

My basic need is I have to take lots of data and other information and assemble it into a function (static parameters). I then need to call the function many times for numerical results for many values of the dynamic parameters. I then need to repeat with a new set of static parameters. I have a workable solution that I'm using now but it does not feel like a slick solution. So I'm looking for some fresh ideas.

MakeRegion[id_, g_, geo_] := (
  listend = #[[-1]] & /@ (Select[
     FindShortestPath[g, id, #] & /@ (Pick[VertexList[g], 
        VertexOutDegree[g], 0]), Length[#] > 0 &]);
  cond = Table[
     {crf, rrf, typerf, ptsrf} = {ApCenter, ApR, Type, ApPoints} /. geo[[listend[[i]]]];
     Which[
        typerf == "Polygon", PointInPoly[ptsrf, {x, y}],
        typerf == "Circle", (x - crf[[1]])^2 + (y - crf[[2]])^2 <= r
      ],
      {i, 1, Length[listend]}];
  Clear[region];
  region[x_, y_] := Evaluate[Or @@ cond];
  );

I do not think I need to go into the details of the code for you to get the idea. MakeRegion takes in geometry information and creates the function region[x,y] which is a logical domain that I can use in NIntegrate and other functions.

Here is a simple example:

Clear[example]
example[a_] := (
   Clear[fun];
   fun[x_, y_] := 
      Evaluate[x Total[RandomVariate[NormalDistribution[], a]] + y ];
   );

The function example has no return value, but it defines the function fun, which I can use until I need to get a new instance of the function fun which I do by running example[a].

$\endgroup$
  • $\begingroup$ your function MakeRegion can't work : It doesn't return anything because of the semi-colon at the end of the last but one line $\endgroup$ – andre314 Feb 23 '13 at 12:53
  • $\begingroup$ Yes the function MakeRegion does not have a return value but it does define the function region which is the function that I use for the numerical calculations. Here is a simple proof of concept example: Clear[example] example[a_] := ( Clear[fun]; fun[x_, y_] := Evaluate[x Total[RandomVariate[NormalDistribution[], a]] + y ]; ); $\endgroup$ – c186282 Feb 23 '13 at 13:14
  • $\begingroup$ Here are two links to posts using closures. You might find these interesting. 1 and 2 $\endgroup$ – Szabolcs Feb 24 '13 at 21:09
19
$\begingroup$

The more Mathematica-like way of doing this is to actually return a function, rather than define a single global function as a side-effect:

createFunction[a_] := 
    Function[{x,y}, 
        x Total[RandomVariate[NormalDistribution[], a]] + y 
    ]

Now you can create as many functions parameterized by a as you like, assign those functions, pass them other places:

f3=createFunction[3]
f9=createFunction[9]
{NIntegrate[f3[x, y], {x, 0, 5}, {y, 0, 4}]], Plot[f9[x, 5.], {x, 0, 5}]}
$\endgroup$
  • $\begingroup$ Thank you. I had originally tried something like this but I made the silly mistake of doing f3:=createFunction[3]. Note, improper usage of := $\endgroup$ – c186282 Feb 23 '13 at 17:42
1
$\begingroup$

Over the years I have come across more situations where I need Function A to create function B. I have used what was provided by "Joel Klein" but I wanted more and I have come across a better way to get done what I need:

Clear[AmakeB];

Options[AmakeB] = {"FunctionName" -> Automatic, "Quiet" -> False};

AmakeB::Function = "I made your function `1`";

AmakeB[a_, b_, opts : OptionsPattern[AmakeB]] := Module[
  {fn},
  fn = OptionValue["FunctionName"];
  If[! StringQ[fn], fn = "Fun"];

 Clear[Evaluate[Symbol[fn]]];
 With[{av = a, bv = b},
  Evaluate[Symbol[fn]][x_?NumericQ] := av Cos[bv x];
  Evaluate[Symbol[fn]]["Info"] = <|"a" -> av, "b" -> bv|>
 ];
 If[! TrueQ[OptionValue["Quiet"]],
   Message[AmakeB::Function, fn]
 ];

]

Now the function that is created is not returned via a Return from the Module but is added to the Global context. One of the advantages to me is that now I can define an arbitrarily complex function.

Usage:

AmakeB[1, 1]

Returns nothing but now the function Fun exists:

?Fun
(*
Global`Fun
Fun[Info]=<|a->1,b->1|>
Fun[x$_?NumericQ]:=1 Cos[1 x$]
*)

Make another function:

AmakeB[1, 2, "FunctionName" -> "Yes"]

Now the function Yes exists

?Yes
(*
Yes[Info]=<|a->1,b->2|>

Yes[x$_?NumericQ]:=1 Cos[2 x$]
*)
$\endgroup$

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.