6

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].

m_goldberg
  • 107,779
  • 16
  • 103
  • 257
c186282
  • 1,402
  • 9
  • 17
  • 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 – andre314 Feb 23 '13 at 12:53
  • 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 ]; ); – c186282 Feb 23 '13 at 13:14
  • Here are two links to posts using closures. You might find these interesting. 1 and 2 – Szabolcs Feb 24 '13 at 21:09

2 Answers2

22

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}]}
Joel Klein
  • 5,225
  • 1
  • 31
  • 44
  • Thank you. I had originally tried something like this but I made the silly mistake of doing f3:=createFunction[3]. Note, improper usage of := – c186282 Feb 23 '13 at 17:42
2

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$]
*)
c186282
  • 1,402
  • 9
  • 17