Message Boards Message Boards

0
|
2372 Views
|
12 Replies
|
2 Total Likes
View groups...
Share
Share this post:

Module doesn't recognize function parameters

Posted 1 year ago

Hello everyone. I hope you can help me solve this problem. I want to find if the functions fA1, fB2, fC3 are within the range LowerLimit <= hF1[fA1, fB2, fC3] <= UpperLimit and save the matching values into the list selectedData. The code must work for arbitrary functions.

Running the code shows the following error:

Set::setraw: Cannot assign to raw object 1.80609586246897`.

Set::setraw: Cannot assign to raw object 1.4410360862456661`.

Set::setraw: Cannot assign to raw object 1.0125069354448308`.

General::stop: Further output of Set::setraw will be suppressed during this calculation.

below the code: (* Step 1.- Construction of test functions *)

fA1[w1_,w2_,w3_,w4_]:= 10+w1+w2+w3+w4

fB2[r1_,r2_,r3_,r4_]:= 1+r1+r2+r3+r4

fC3[t1_]:=5*t1

(* Step 2.- Cconstruction of the rule where the functions will be evaluated*)

hF1[fA1_,fB2_,fC3_]:= (2*fA1)*(3*fB2)*(4*fC3)

(* Step 3.- Construction of the Main function  *)
GT5[fA1_,fB2_,fC3_,x1_,x1min_,x1max_,x2_,x2min_,x2max_,x3_,x3min_,x3max_,x4_,x4min_,x4max_,NN_]:=
Module[
 {
  p1, p1min, p1max, 
  p2, p2min, p2max,
  p3, p3min, p3max,
  p4, p4min, p4max,
  n, selectedData,LowerLimit,UpperLimit
 },
 LowerLimit = 1;
 UpperLimit = 10000000;
 selectedData={};
 p1=x1; p1min=x1min; p1max=x1max;
 p2=x2; p2min=x2min; p2max=x2max; 
 p3=x3; p3min=x3min; p3max=x3max; 
 p4=x4; p4min=x4min; p4max=x4max;
 n=1;
 Do[
   {  
    x1 = RandomReal[{p1min, p1max}];
    x2 = RandomReal[{p2min, p2max}];
    x3 = RandomReal[{p3min, p3max}];
    x4 = RandomReal[{p4min, p4max}]; 
    If[
       LowerLimit <= hF1[fA1, fB2, fC3] <= UpperLimit,
       selectedData = AppendTo[selectedData, {p1,p2,p3,p4,hF1[fA1, fB2, fC3]}], 
       0
      ]; 
    }, {n, NN}
   ];
   selectedData
]

Now, run the instruction:

GT5[
    fA1[D1+D2,D3,D1,D2],
    fB2[D1+D2,D3,D1,D2],
    fC3[2*D1],
    D1,1,2,
    D2,1,2,
    D3,1,2,
    D4,1,2,
    10
   ]

and I get:

During evaluation of In[18]:= Set::setraw: Cannot assign to raw object 1.80609586246897`.

During evaluation of In[18]:= Set::setraw: Cannot assign to raw object 1.4410360862456661`.

During evaluation of In[18]:= Set::setraw: Cannot assign to raw object 1.0125069354448308`.

During evaluation of In[18]:= General::stop: Further output of Set::setraw will be suppressed during this calculation.

Out[18]= {{1.8061, 1.44104, 1.01251, 1.13217, 64553.9}, {1.8061, 
  1.44104, 1.01251, 1.13217, 64553.9}, {1.8061, 1.44104, 1.01251, 
  1.13217, 64553.9}, {1.8061, 1.44104, 1.01251, 1.13217, 
  64553.9}, {1.8061, 1.44104, 1.01251, 1.13217, 64553.9}, {1.8061, 
  1.44104, 1.01251, 1.13217, 64553.9}, {1.8061, 1.44104, 1.01251, 
  1.13217, 64553.9}, {1.8061, 1.44104, 1.01251, 1.13217, 
  64553.9}, {1.8061, 1.44104, 1.01251, 1.13217, 64553.9}, {1.8061, 
  1.44104, 1.01251, 1.13217, 64553.9}}

I will appreciate your help or comments.

Precisely, I want to use functions whose inputs will not always be like this fA1[x1 + x2, x3, x1, x2], fB2[x1 + x2, x3, x1, x2], fC3[2*x1] I've been able to get it to work by removing Module and adding Clear[x1,x2,x3,x4] to the end, but I think there must be a better way to solve it.

GT5[fA1_,fB2_,fC3_,x1_,x1min_,x1max_,x2_,x2min_,x2max_,x3_,x3min_,x3max_,x4_,x4min_,x4max_,NN_]:=
{
selectedData = {};
LowerLimit = 1;
UpperLimit = 10000000;
selectedData = {};
Do[
{
x1 = RandomReal[{x1min, x1max}];
x2 = RandomReal[{x2min, x2max}];
x3 = RandomReal[{x3min, x3max}];
x4 = RandomReal[{x4min, x4max}]; 
If[
LowerLimit <= hF1[fA1, fB2, fC3] <= UpperLimit,
selectedData = AppendTo[selectedData, {x1,x2,x3,x4,hF1[fA1, fB2, fC3]}], 
0]
}, {n, NN}
];
Print[selectedData];
Clear[x1,x2,x3,x4];
}
Attachments:
POSTED BY: Tomás Valencia
12 Replies
Posted 1 year ago

I've been very confused about your question, but I think I've finally figured it out. Here's what I think you're trying to achieve:

  • You want to define a predicate that depends on some arguments that in turn you want to depend on some functions.
  • Those other functions can be arbitrary, and they don't all have the same signature.
  • While they don't have the same signature, they do all depend on the same overall set of arguments, so you somehow need to pass in all of these lower level arguments and feed them to your functions in some pre-specified manner

If all of that's correct, then here's a possible answer. I'll start by defining a function that does all the work of putting things together correctly. It'll be a bit confusing, but I'll demonstrate how to use it.

SpecialFunction[combiner_, lower_, upper_, count_][fns__][ranges : {_, _} ...] :=
 With[
  {randomVals = Table[RandomReal /@ {ranges}, count],
   applicators = MapApply /@ {fns},
   checker = Function[Null, lower <= combiner[##] <= upper]},
  With[
   {appliedVals = Through[applicators[randomVals]]},
   Transpose[{randomVals, Transpose@appliedVals, checker @@@ Transpose[appliedVals]}]]]

The first set of arguments correspond to how you want to do your checking (basically your hF1 and the less-equal tests). The second set of arguments are the functions you want to apply to the arguments (your fA1, fB2, and fB3). We'll need to put them in a special form, but we'll get to that later. The last set of arguments are the ranges in which you want to pick random values for each argument that will be fed to the functions. The way this is set up, you can pass any number of fns and any number of ranges.

Let's try it out with some dummy arguments so you can see what it does:

SpecialFunction[someCombiner, 0, 100, 2][func1, func2, func3][{1, 5}, {10, 20}]

{{{4.62279, 16.5337}, {func1[4.62279, 16.5337], func2[4.62279, 16.5337], func3[4.62279, 16.5337]}, 0 <= someCombiner[func1[4.62279, 16.5337], func2[4.62279, 16.5337], func3[4.62279, 16.5337]] <= 100}, {{1.44301, 17.4801}, {func1[1.44301, 17.4801], func2[1.44301, 17.4801], func3[1.44301, 17.4801]}, 0 <= someCombiner[func1[1.44301, 17.4801], func2[1.44301, 17.4801], func3[1.44301, 17.4801]] <= 100}}

Let's focus on just the first item in this output (note that the random numbers will be different when you try this yourself).

{{4.62279, 16.5337}, {func1[4.62279, 16.5337], func2[4.62279, 16.5337], func3[4.62279, 16.5337]}, 0 <= someCombiner[func1[4.62279, 16.5337], func2[4.62279, 16.5337], func3[4.62279, 16.5337]] <= 100}

We have our random values, the values we get when we apply our intermediate functions, and then the result of applying our combiner and the limits. We get that kind of output for as many trials as we do (which is determined by count).

Now, the challenge we have is that you've got several low-level arguments that get fed to the intermediate functions in different ways, in terms of count, order, and even more intermediate computations (like adding the first and second or doubling the first). So, we need to define our intermediate functions by wrapping our actual functions. You can do this with OperatorApplied or CurryApplied, but rather than introduce yet another complication, let's just use plain Function.

wrappedFA1 = Function[Null, fA1[#1 + #2, #3, #1, #2]];
wrappedFB2 = Function[Null, fB2[#1 + #2, #3, #1, #2]];
wrappedFC3 = Function[Null, fC3[2*#1]];

Now we can pass these to SpecialFunction. I'll also change it to use the parameters you were using.

SpecialFunction[hF1, 1, 10000000, 2][wrappedFA1, wrappedFB2, wrappedFC3][{1, 2}, {1, 2}, {1, 2}, {1, 2}]

{{{1.13805, 1.77789, 1.77946, 1.09484}, {fA1[2.91594, 1.77946, 1.13805, 1.77789], fB2[2.91594, 1.77946, 1.13805, 1.77789], fC3[2.2761]}, 1 <= hF1[fA1[2.91594, 1.77946, 1.13805, 1.77789], fB2[2.91594, 1.77946, 1.13805, 1.77789], fC3[2.2761]] <= 10000000}, {{1.2858, 1.52344, 1.41616, 1.93163}, {fA1[2.80924, 1.41616, 1.2858, 1.52344], fB2[2.80924, 1.41616, 1.2858, 1.52344], fC3[2.5716]}, 1 <= hF1[fA1[2.80924, 1.41616, 1.2858, 1.52344], fB2[2.80924, 1.41616, 1.2858, 1.52344], fC3[2.5716]] <= 10000000}}

Now we're ready to use the definitions you provided for the fA1 and so forth.

hF1[fA1_, fB2_, fC3_] := (2*fA1)*(3*fB2)*(4*fC3);
fA1[w1_, w2_, w3_, w4_] := 10 + w1 + w2 + w3 + w4;
fB2[r1_, r2_, r3_, r4_] := 1 + r1 + r2 + r3 + r4;
fC3[t1_] := 5*t1;

Finally, let's evaluate our SpecialFunction again:

SpecialFunction[hF1, 1, 10000000, 2][wrappedFA1, wrappedFB2, wrappedFC3][{1, 2}, {1, 2}, {1, 2}, {1, 2}]

{{{1.23086, 1.13019, 1.20986, 1.62693}, {15.932, 6.93197, 12.3086}, True}, {{1.96329, 1.14836, 1.4373, 1.46791}, {17.6606, 8.66061, 19.6329}, True}}

At this point, you can select the ones with True.

Comments/suggestions:

  • Looking at it now, I realize that it might have been useful to add the value of the combiner to the output. I don't want to worry about copy-paste errors at this point, so I'll let you decide how you want your results to be displayed.
  • This currently assumes that hF1 takes its arguments in the order of the fns. If you want to play with that, then you'd want to wrap hF1 like we did for fA1 et al.
  • Obviously, you need to provide as many argument range specs as you'll need for the fns. And you'll need to provide as many fns as you'll need for the combiner.
  • You could work the final selection into SpecialFunction, but I thought it was easier to demonstrate without that step, so that's an exercise I leave to you.
  • This could all be simplified if there were known constraints on your functions. Given that you wanted a general solution that works for any arbitrary set of functions, you'll need something at about this level of complexity.
POSTED BY: Updating Name
Posted 1 year ago

Ugh. I see an edit I need to make, but for some reason that post was attributed to "Updating Name" and so now I can't edit my own post! I was just going to fix the line that was truncated, but hopefully it's not too unclear as it stands.

POSTED BY: Eric Rimbey

Thank you so much. I will work on your solution and update this post.

POSTED BY: Tomás Valencia

not really sure that you are actually wanting to find the functions. The code looks for a vector of 4 random numbers that when evaluated by a function stay within a range.

The function you are evaluating is

fA1[w1_, w2_, w3_, w4_] := 10 + w1 + w2 + w3 + w4
fB2[r1_, r2_, r3_, r4_] := 1 + r1 + r2 + r3 + r4
fC3[t1_] := 5*t1
hF1[fA1_, fB2_, fC3_] := (2*fA1)*(3*fB2)*(4*fC3)

FullSimplify[
 hF1[fA1[d1 + d2, d3, d1, d2], fB2[d1 + d2, d3, d1, d2], fC3[2*d1]]]

which evaluates to

240 d1 (1 + 2 d1 + 2 d2 + d3) (2 (5 + d1 + d2) + d3)

so:

f[{d1_, d2_, d3_, d4_}] := 
 240 d1 (1 + 2 d1 + 2 d2 + d3) (2 (5 + d1 + d2) + d3)

the input parameters are

n = 100
{min, max} = {1, 10^6};
ranges = {{1, 2}, {1, 2}, {1, 2}, {1, 2}};

so this would solve the problem in one line.

Column[{#, f[#]} & /@ Select[Transpose[RandomReal[#, n] & /@ ranges], min < f[#] < max &]]

or step by step

(*gerenrate the random vectors where each row of ds = {d1, d2, d3, d4}*)
ds = Transpose[RandomReal[#, n] & /@ ranges]
(*select the values for which each row of ds remains in the limits*)
sel = Select[ds, min < f[#] < max &]
(*show the output show the output, where it recomputes f again, which is not needed*)
Column[{#, f[#]} & /@ sel]
POSTED BY: Martijn Froeling

Thanks for reviewing the code and providing your help. The problem is that the code must work for arbitrary functions.

POSTED BY: Tomás Valencia

My code works with arbitrary functions. I just showed it in its most simple form

fA1[w1_, w2_, w3_, w4_] := 10 + w1 + w2 + w3 + w4
fB2[r1_, r2_, r3_, r4_] := 1 + r1 + r2 + r3 + r4
fC3[t1_] := 5*t1
hF1[{fA1_, fB2_, fC3_}, {d1_, d2_, d3_, 
   d4_}] := (2*fA1[d1 + d2, d3, d1, d2])*(3*
    fB2[d1 + d2, d3, d1, d2])*(4*fC3[2*d1])

n = 100;
dom = {min, max} = {1, 10^6};
ranges = {{1, 2}, {1, 2}, {1, 2}, {1, 2}};

FindValue[{f_, fs_}, {min_, max_}, n_, ranges_] := {#, f[fs, #]} & /@ 
  Select[Transpose[RandomReal[#, n] & /@ ranges], 
   min < f[fs, #] < max &]

hF1[{fA1, fB2, fC3}, {d1, d2, d3, d4}]

FindValue[{hF1, {fA1, fB2, fC3}}, dom, n, ranges]

Or in the case the evaluation of your function takes a long time, your dont want to compute f[fs,#] twice so you can also use

FindValue2[{f_, fs_}, {min_, max_}, n_, ranges_] := 
 Block[{rand, val, sel},
  rand = Transpose[RandomReal[#, n] & /@ ranges];
  val = f[fs, #] & /@ rand;
  sel = min < # < max & /@ val;
  Pick[Thread[{rand, val}], sel, True]
  ]

Which is apparently faster even if the computation is short

FindValue[{hF1, {fA1, fB2, fC3}}, dom, n, ranges]; // AbsoluteTiming
FindValue2[{hF1, {fA1, fB2, fC3}}, dom, n, ranges]; // AbsoluteTiming

{0.0018419, Null}

{0.001193, Null}
POSTED BY: Martijn Froeling
Posted 1 year ago

Based on my understanding of what OP wants, no, your code does not work with arbitrary functions. Let's say that we want to swap fC3 with a new function that takes two arguments. The way your code is written, hF1 needs to know that, and so it also needs to change. Or let's say we wanted to replace fC3 with a new function that takes 5 arguments. Now your code is broken completely, because hF1 explicitly expects all of the intermediate functions to take at most 4 arguments. Your code has fairly tightly coupled the "shape" of the hF1 function (or any alternative we might want to use) to the "shape" of the intermediate fA1 (et al) functions. Now, maybe that's suffient for the OPs case, but I got the impression that something more general was wanted.

POSTED BY: Eric Rimbey
Posted 1 year ago

Let's start from the inside and work our way out.

LowerLimit <= hF1[fA1, fB2, fC3] <= UpperLimit

What you actually passed in for argument fA1 was

fA1[D1 + D2, D3, D1, D2]

When you start evaluating the Module, D1/2/3/4 have no values assigned to them. But you're also passing in these symbols when you call GT5. The argument names are x1/2/3/4. So the lines like

x1 = RandomReal[{p1min, p1max}]

actually get interpreted as

D1 = RandomReal[{p1min, p1max}]

That's why fA1[D1+D2,D3,D1,D2] actually resolves to some actual value.

Taking a tangent, this explains why you get those messages the second time around. The second time around, D1 has a numeric value. Thus, the argument x1 gets a numeric value. And so, the line

x1 = RandomReal[{p1min, p1max}]

gets interpreted as

1.6817646433788693 = RandomReal[{p1min, p1max}]

(or whatever, it's random). You can't assign a new value to an actual number.

The main problem you're having is you're duplicating information. The first argument you pass to GT5 is fA1[D1+D2,D3,D1,D2], but then your fourth argument is D1. You're basically passing in D1 several times. Maybe you were trying to parameterize GT5 to allow arbitrary functions being passed in, but let's defer that and just assume that you always want to compute with fA1, fB2, and fC3. This allows us to just apply those functions in the body of GT5. Specifically, the line we started looking at could be written like this:

LowerLimit <= hF1[fA1[x1 + x2, x3, x1, x2], fB2[x1 + x2, x3, x1, x2], fC3[2*x1]] <= UpperLimit

This means we can simplify the signature of GT5 like this:

GT5[x1_, x1min_, x1max_, x2_, x2min_, x2max_, x3_, x3min_, x3max_, x4_, x4min_, x4max_, NN_] := ...

And we can go further, because x1/2/3/4 were just dummy arguments. All we really need are the 4 pairs of min/max. We can use a local variable for each--we don't need to pass that in. Furthermore, the variables p1/2/3/4 aren't doing anything--let's eliminate them. So, at this point, we have something like this:

GT5[x1min_, x1max_, x2min_, x2max_, x3min_, x3max_, x4min_, x4max_, NN_] :=
  Module[
    {x1, x2, x3, x4,
     n, selectedData, LowerLimit, UpperLimit},
    LowerLimit = 1;
    UpperLimit = 10000000;
    selectedData = {};
    n = 1;
    Do[
      x1 = RandomReal[{x1min, x1max}];
      x2 = RandomReal[{x2min, x2max}];
      x3 = RandomReal[{x3min, x3max}];
      x4 = RandomReal[{x4min, x4max}]; 
      If[
        LowerLimit <= hF1[fA1[x1+x2,x3,x1,x2], fB2[x1+x2,x3,x1,x2], fC3[2*x1]] <= UpperLimit,
        selectedData = AppendTo[selectedData, {x1,x2,x3,x4,hF1[fA1[x1+x2,x3,x1,x2], fB2[x1+x2,x3,x1,x2], fC3[2*x1]]}], 
        0],
      {n, NN}];
    selectedData]

There is still more work that should be done. We're calculating some things twice, we still have some superfluous local variables, and we probably want to make the upper/lower limits arguments instead of magic local values. But hopefully the above is enough to get you started.

POSTED BY: Eric Rimbey

Thank you very much for reviewing my code. Precisely, I want to use functions whose inputs will not always be like this fA1[x1 + x2, x3, x1, x2], fB2[x1 + x2, x3, x1, x2], fC3[2*x1] I've been able to get it to work by removing Module and adding Clear[x1,x2,x3,x4] to the end, but I think there must be a better way to solve it.

GT5[fA1_,fB2_,fC3_,x1_,x1min_,x1max_,x2_,x2min_,x2max_,x3_,x3min_,x3max_,x4_,x4min_,x4max_,NN_]:=
{
selectedData = {};
LowerLimit = 1;
UpperLimit = 10000000;
selectedData = {};
Do[
{
x1 = RandomReal[{x1min, x1max}];
x2 = RandomReal[{x2min, x2max}];
x3 = RandomReal[{x3min, x3max}];
x4 = RandomReal[{x4min, x4max}]; 
If[
LowerLimit <= hF1[fA1, fB2, fC3] <= UpperLimit,
selectedData = AppendTo[selectedData, {x1,x2,x3,x4,hF1[fA1, fB2, fC3]}], 
0]
}, {n, NN}
];
Print[selectedData];
Clear[x1,x2,x3,x4];
}
POSTED BY: Tomás Valencia
Posted 1 year ago

When you define this:

hF1[fA1_,fB2_,fC3_]:= (2*fA1)*(3*fB2)*(4*fC3)

Are you using the argument names fA1 and so forth as just a mnemonic device, or are you expecting some actual computational link to the functions fA1 etc that you previous defined?

POSTED BY: Eric Rimbey
Posted 1 year ago

You didn't assign any values to D1, D2, etc. What were you expecting? Maybe you can explain what you're trying to achieve.

POSTED BY: Eric Rimbey

I want to find if the functions fA1, fB2, fC3 are within the range LowerLimit <= hF1[fA1, fB2, fC3] <= UpperLimit, using RandomReal and save the matching values into the list selectedData. But using x1,x2,x3,x4 throws error. In Module I used the relations p1=x1, p2=x2,p3=x3,p4=x4 but it does not evaluate with those assignments.

POSTED BY: Tomás Valencia
Reply to this discussion
Community posts can be styled and formatted using the Markdown syntax.
Reply Preview
Attachments
Remove
or Discard

Group Abstract Group Abstract