Re: Making a function dynamically define another conditional function...

*To*: mathgroup at smc.vnet.net*Subject*: [mg21765] Re: [mg21733] Making a function dynamically define another conditional function...*From*: Bojan Bistrovic <bojanb at physics.odu.edu>*Date*: Thu, 27 Jan 2000 22:56:45 -0500 (EST)*Sender*: owner-wri-mathgroup at wolfram.com

> > How can I make a function dynamically define a conditional function? > > Given a list of arguments {{a,A}, {b,B}, ...} I want to write a function > that will take these arguments, and generate a new function, f say, > which is defined as (for example): > f[x_] := x+a /; x==A > f[x_] := x+b /; x==B > etc. > > So, the obvious solution is to define a function as follows: > > In[1] := TestFn[data_List] := Module[{args}, > ClearAll[f]; > Do[ > args = data[[i]]; > f[x_] = x + args[[1]] /; x==args[[2]], > {i, Length[data]} > ]] > > and call it using something like TestFn[{{1,2},{3,4},{5,6}}]. > > But this doesn't work (see attached notebook) as it appears that > Mathematica does not evaluate any part of the condition at the time of > definition, so args[[2]] remains unevaluated. As a consequence, the > resulting function definition is not properly defined. > > So, the obvious solution to this is to wrap Evaluate[] around the > condition (i.e. define the function as f[x_] = x + args[[1]] /; > Evaluate[x == args[[2]]]. And this appears to work. If you do ?f, then > you see a function comprising a number of conditional definitions. > However, if you come to use the function, then it appears that > Mathematica does not perform the condition test that appears in the > definition! It simply uses the first definition it finds. > > What is going on?! How can I make this work? > > I attach a notebook with example code. [Contact Paul to > get this notebook - Moderator] > > Many thanks for any help. > > Paul > What happens is this: SetDelayed (or := as it is usually called) has an attribute HoldAll su that neither the left hand side (TestFn[data_List]) nor the right-hand side (Module[{args}, ... ]) are evaluated at the time. When you call the function with TestFn[{{1,2},{3,4},{5,6}}] what happens is this: The loop gets evaluated Lenght[data_List] times (in this case 3); you assign the i-th element of data_List to the temporary element args (which is unnecessary since you can use data[[i,1]] and data[[i,2]] instead) and then attempt to use Set (=) and Condition (/;) to define you functions. This doesn't work because Condition has an attribute HoldAll which prevents x==args[[2]] from being evaluated. Now, the thing to ude with HoldAll attribute is Evaluate, but if you define In[1]:= TestFn[data_List] := Module[{args}, ClearAll[f]; Do[ args = data[[i]]; f[x_] = x + args[[1]] /; Evaluate[x==args[[2]]], {i, Length[data]} ]] it will appear to work: In[2]:= TestFn[{{1,2},{3,4},{5,6}}]; In[3]:= ?f Out[3]= Global`f f[x$_] = 1 + x$ /; x$ == 2 f[x$_] = 3 + x$ /; x$ == 4 f[x$_] = 5 + x$ /; x$ == 6 but when you try to use it it won't work after all: In[4]:= {f[1],f[2],f[3],f[4],f[5],f[6]} Out[4]= {2 /; 1==2,3 /; 2==2, 4 /; 3==2, 5 /; 4==2, 6 /; 5==2,7 /; 6==2} What happens here is this: the args part in x==args[[2]] gets evaluated, since it doesn't give you either True or False, it's left unevaluated, and the whole right-hand side gets assigned to f[x$_] like this: f[x_] = ( x + args[[1]] /; Evaluate[x==args[[2]]] ), so that the f[x_] is defined to be Condition[x + args[[1]], x==args[[2]]]]: f[x$_] = Condition[1 + x$ , x$ == 2] f[x$_] = Condition[3 + x$ , x$ == 4] f[x$_] = Condition[5 + x$ , x$ == 6] which againd has the attribute HoldAll so that the arguments don't get evaluated. Putting any additional Evaluate commands won't change anything since they will be evaluated at the time Set is evaluated and when you latter call the function f[4] (for example), 4 will mathch x$_ (everything will) and you'll get the result back 5/; 4==2. The thing to do is: In[5]:= TestFn[data_List] :=(ClearAll[f];Do[ f[x_] := Evaluate[ x + data[[i,1]] /; Evaluate[ x==data[[i,2]]]], {i, Length[data]}]) Since SetDelayed has attributes HoldAll, the whole right rand side of the equation is wrapped in Evaluate, so that Condition is evaluated, and then the other Evaluate after /; is needed to evaluate the data[[i,2]] part. What you're left with looks the same as the last cas In[6]:= TestFn[{{1,2},{3,4},{5,6}}]; In[7]:= ?f Out[7]= Global`f f[x$_] := 1 + x$ /; x$ == 2 f[x$_] := 3 + x$ /; x$ == 4 f[x$_] := 5 + x$ /; x$ == 6 but now it gets interpreted like you want it, SetDelayed[f[x$_] , Condition[1 + x$, x$ == 2]] so each time you type something like f[x] Mathematica tries to match x to the second argument of the Condition command and then use the appropriate definition: In[8]:= {f[1],f[2],f[3],f[4],f[5],f[6]} Out[8]= {f[1],3,f[3],7,f[5],11} To finish this email, since you aren't using any patterns in the right hand side of Condition (you have pure numbers like 2,4,6) it's a much better idea to use something like TestFn[data_List] :=(ClearAll[f];Do[ f[data[[i,2]]] =data[[i,2]] + data[[i,1]] ,{i, Length[data]}]) It will work in most cases and it's much faster. Bye, Bojan ------------------------------------------------------------- Bojan Bistrovic, bojanb at physics.odu.edu Old Dominion University, Physics Department, Norfolk, VA -------------------------------------------------------------