Group Abstract Group Abstract

Message Boards Message Boards

1
|
11.6K Views
|
57 Replies
|
3 Total Likes
View groups...
Share
Share this post:

Referring to arguments of a function by order in which they appear

Posted 2 years ago

I have an application in which I need to pass arguments to a function in non-list form (I know functions can take arguments in list form, but there is a bug that makes this not work in my case, we don't have to get into it), but then I need to recreate the lists from the arguments. So for example, if

f[a1_,a2_]:=a1+a2

I would like to define, inside f a list={a1,a2] and then redefine

f[a1_,a2_]:=list[[1]]+list[[2]]

I would like to refer to a1 as first argument of f, a2 as second argument instead of by their names, because I have a much more complicated function in my real case and I want to automate list by using such Mathematica constructs as Table and Array. So how to do this?

POSTED BY: Iuval Clejan
57 Replies
Posted 2 years ago

I think I solved it! So flattening the lists before passing to ffoutsuper, and reconstructing them should have worked, because that is what I had before, no lists. But I also had the arguments passed to ffoutsuper be _Real. So once I did that, it works again. I don't really know why. Somehow the conditionals work now. It would have been nice not to have to flatten the lists and reconstruct them. Something for the developers to figure out.

POSTED BY: Iuval Clejan
Posted 2 years ago

Kuba, The problem of delaying the evaluation of ffoutsuper till after eqnlist has been generated has been already solved by Eric. The problem of giving ffoutsuper a flat list and reconstructing the actual lists inside of ffoutsuper (so they can be passed on to other functions) has also been already solved by Eric, so thanks but I don't need that anymore. However, I was wrong to think that this would solve my problem. I thought it would, because when I gave ffoutsuper a flat list and delayed the evaluation of eqnlist with the "Real" hack (imposing that its args be real numbers instead of symbolic or otherwise), everything worked. But now I am thinking that the "Real" hack must have had other effects that made things work (but it doesn't work with lists, at least as far as Derivative is concerned, which is a BUG. See this thread:https://community.wolfram.com/groups/-/m/t/3092236 and Ginalucca's response:" Very curious. It appears that you cannot mix numeric tests like xReal or x?NumberQ with list structures inside Derivative")

So the problem in its most general form is to have the same code that worked without lists, work with lists (of different shapes and sizes).

POSTED BY: Iuval Clejan
Posted 2 years ago

Kuba, Eric, I am including a simple (as simple as I could get it) example to illustrate the bug. It seems to be an inability of NDSolve to handle conditionals. The first cell has a problem (even at t=0) because it can't deal with Re[Eigenvalues]. The second cell has no problem because I remove the Re[]. This is a bug, but do you have any suggestions for a workaround? I can't remove the Re in my actual problem, because the matrices are not symmetric and the eigenvalues can become complex (they don't in this example). Also, in my actual problem I have other conditionals on the equivalent of ff, which might also be causing problems, I'll check that next. (Note: don't confuse Re[Eigenvalues] with the Real_ (arguments to ff) hack I was doing initially to delay evaluation of eqnlist. They seem to be unrelated). Not also the nonsense with Re'[4], which is a problem with just Derivative (not even NDSolve) that I showed previously.

POSTED BY: Iuval Clejan
Posted 2 years ago

*Edited. And here is another bug, which I don't really understand (I thought problem was Derivative, but I was wrong, forgot to refresh definitions). The first cell is without the conditional, gives good output. Second gives output, but it's wrong. It has a local variable that gets confused and forgets that it is 1. If you uncomment the commented area, and comment the If statement in ffoutsuper, you will see that it works fine, so the local variable is fine, except if it's called with the conditional.

POSTED BY: Iuval Clejan
Posted 2 years ago

Eric, the only thing I still need help with is to index correctly into the lists

ffoutsuper[args__] := fList[{args}];
fList[{flag_, LRc_, cL_, cR_, alphaL_, alphaR_, LRC_, CL_, CR_, 
AlphaL_, AlphaR_}] :=???

flag, LRc and LRC are scalars, cL and cR are 4-vectors, alphaL, alphaR, AlphaL, and AlphaR are 4x4 matrices (for now, the dimensions of lists will change in the future). Is there a good way to do this? The eariler simple example had only one 1-dimensional list, so it was trivial. I need to recreate the original lists from the flattened, joined lists that are served as a sequence to ffoutsuper.

POSTED BY: Iuval Clejan
Posted 2 years ago

If the argument list always has this same structure, you can just refer to the pattern names you've already used:

fList[{flag_, LRc_, cL_, cR_, alphaL_, alphaR_, LRC_, CL_, CR_, AlphaL_, AlphaR_}] := 
 StringForm["``-``-``-``-``-``-``-``-``-``-``", LRc, CR, AlphaL, flag, cL, alphaL, cR, alphaR, CL, AlphaR, LRC];

fList[Range[11]] // ToString
(* "2-9-10-1-3-5-4-6-8-11-7" *)

But if you really want to access by index, then you'll need a pattern name for the whole list:

fList[args : {flag_, LRc_, cL_, cR_, alphaL_, alphaR_, LRC_, CL_, CR_, AlphaL_, AlphaR_}] := 
 StringForm["``-``-``-``-``-``-``-``-``-``-``:::``:::(``)", LRc, CR, AlphaL, flag, cL, alphaL, cR, alphaR, CL, AlphaR, LRC, args, args[[5]]];

fList[Range[11]] // ToString
(* "2-9-10-1-3-5-4-6-8-11-7:::{1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11}:::(5)" *)

And if you only want to access by index, you don't need all those other pattern names:

fList[args : {_, _, _, _, _, _, _, _, _, _, _}] := args[[RandomSample[Range[11]]]];    

fList[Range[11]]
(* {3, 1, 4, 6, 8, 11, 2, 7, 10, 5, 9} *)

And if you don't actually want to restrict it to 11 arguments, but any arbitrary number:

fList[args : {___}] := RandomSample[args];

fList[Range[5]]
(* {1, 5, 4, 2, 3} *)

And also, you can index into any one particular argument:

fList[{flag_, LRc_, cL_, cR_, alphaL_, alphaR_, LRC_, CL_, CR_, 
   AlphaL_, AlphaR_}] := cL[[2]];

fList[{1, 2, {100, 101, 102, 103}, 4, 5, 6, 7, 8, 9, 10, 11}]
(* 101 *)
POSTED BY: Eric Rimbey
Posted 2 years ago

At least one of us is not understanding the other here. I need to access all these args that come from a flattened list of joined lists for computation. So flag is just flag (a scalar), RLc is just RLc (a scalar), I need to access different element of cL and cR (which are one dimensional lists of length 4), I need to access different elements of aL and aR which are 4x4 2 dimensional lists, etc. I want fList to be the function that has those original lists in it, somehow reconstructed from the flattened sequence that ffoutsuper gets.

How does mixing up the order of the arguments (some of which are lists) and then finding their original order help me?

POSTED BY: Iuval Clejan
Posted 2 years ago

I need to tell flist that the first argument is a scalar called flag, the second also a scalar called RLc, the third through 6th correspond to a 1D list of dimension 4 called cL, etc.

POSTED BY: Iuval Clejan
Posted 2 years ago

I need to tell flist that the first argument is a scalar called flag, the second also a scalar called RLc, the third through 6th correspond to a 1D list of dimension 4 called cL, etc.

If you mean you need to set these conditions as constraints on the arguments, then you could try any of these (I'm going to simplify your example, we don't need eleven arguments to demonstrate this):

myFuncTakesScalars[arg1_Real, arg2_Integer, arg3_?NumericQ, arg4_?AtomQ] := "constraints satisfied";
myFuncTakesScalars[1., 2, Pi, "a"]
(* "constraints satisfied" *)

myFuncTakesLists[arg1 : {_, _, _, _}, arg2_?ArrayQ, arg3_?MatrixQ] := "constraints satisfied";
myFuncTakesLists[{1, 2, 3, 4}, RandomReal[{0, 1}, 100], RandomInteger[{1, 10}, {20, 30}]]
(* "constraints satisfied" *)

myFuncTakesListsWithFurtherConstraints[arg1 : {_, _, _, _}, arg2_?ArrayQ, arg3_?MatrixQ] := "constraints satisfied" /; 4 == Length[arg1] && 2 == ArrayDepth[arg3];
myFuncTakesListsWithFurtherConstraints[{1, 2, 3, 4}, RandomReal[{0, 1}, 100], RandomInteger[{1, 10}, {20, 30}]]
(* "constraints satisfied" *)
POSTED BY: Eric Rimbey
Posted 2 years ago
POSTED BY: Iuval Clejan
Posted 2 years ago
POSTED BY: Eric Rimbey
Posted 2 years ago
POSTED BY: Eric Rimbey
Posted 2 years ago
POSTED BY: Iuval Clejan
Posted 2 years ago

Sorry, I am not familiar with associations

Sorry for the distraction then. Associations aren't inherent to the problem you're trying to solve. I was just trying to demonstrate how to transform between representations.

I'll try to refactor your code later. I only have a couple of minutes right now. So for now, I'll just try to explain why it failed.

Here's your definition for fflat1 (I'm removing the comments for clarity)

fflat1[Sequence @@ Flatten[{flag_, LRc_, cL_}]] := cL[[1]]

If you look at just the argument list you created, it looks like this.

Sequence @@ Flatten[{flag_, LRc_, cL_}]
(* Sequence[flag_, LRc_, cL_] *)

So, your function expects exactly three arguments. But when you tried to apply it:

fflat1[Sequence @@ Flatten[{1, 0.1, cout0L}]]

you actually provided 6 arguments:

Sequence @@ Flatten[{1, 0.1, cout0L}]
(* Sequence[1, 0.1, 4., 4., 4., 4.] *)

When you applied it the other way:

fflat1[1, 0.1, cout0L]

you did provide exactly three arguments:

Sequence[1, 0.1, cout0L]
(* Sequence[1, 0.1, {4., 4., 4., 4.}] *)

but the last argument was itself a list. So, with the argument constraint satisfied, the function was evaluated to be the first item in the third argument, which is 4..

POSTED BY: Eric Rimbey
Posted 2 years ago

Yes, I understand why it won't evaluate that one line, but I was hoping you could figure out how to make it work in an elegant (non-tedious way).

Also, the whole reason for getting away from lists and giving ffoutsuper list-free arguments was initially that Derivative was not able to handle conditionals in lists, and those were only necessary in order to keep eqnlist unevaluated. But you figured out how to not evaluate it by having a dummy function in the definition of eqnlist, that only later gets substituted with the function I want (ffoutsuper).

However, though Derivative can handle lists (now without the hack conditionals), it takes a really long time to evaluate my actual ffoutsuper when we keep the lists. And moreover, there is another bug, which is that since my ffoutsuper needs to take the real part of certain eigenvalues of certain matrices, the derivative outputs such nonsense as Re'[number]. I have included a file that demonstrates both of these problems, for a simpler ffoutsuper than my actual one. If we could fix this, we probably wouldn't need to do the whole list-> sequence rigamarole.

POSTED BY: Iuval Clejan
Posted 2 years ago

So, back to trying without lists in the args to ffoutsuper, since we Derivative has problems with lists in my real case, either being too slow, or trying to do nonsense like differentiaing the real part of a variable. This should not be complicated, but I don't know how to do it. I want to reconstruct the lists inside ffoutsuper. ffoutsuper gets a flat sequence, so the information of the list stuctures is lost to it, but not in my head. For each simulation I will have a constant list structure, though these will vary from simulation to simulation, and for now I don't mind rewriting code for different simulations.

So I know where in the flat structure to start and where to end, for reconstructing all the lists, no matter what shape they have. I just need a way to refer to the nth argument of the flat sequence in the args of ffoutsuper. Can you show me how to do that? Do I need to define a pure function and use Slot? Here is a failed attempt to reconstruct one of the lists for a simple example Wolfram Notebook

POSTED BY: Iuval Clejan
Posted 2 years ago
POSTED BY: Eric Rimbey
Posted 2 years ago

Getting close, but still no cigar. I'm now able to give ffoutsuper a sequence, and resonstruct lists inside it (I only did it for 2 of the 2dimensional lists to keep it simple). But now I'm still getting superslow evaluation, and the Re'[number] bug. Any ideas?

POSTED BY: Iuval Clejan
Posted 2 years ago

And other issues that are seen in the actual code. Is there a way to tell Derivative to not even try to evaluate something symbolically?

POSTED BY: Iuval Clejan
Posted 2 years ago

If I understood what you're trying to achieve mathematically, maybe I could give you suggestions, but I don't, so I can't. But as a Mathematica programming problem, you might be beating your head against a wall. I'm not sure that we can expect Mathematica to figure out the derivative that you want from the form that you're providing to it.

Not that it really matters to the underlying problem, but you can avoid using temporary variables:

ffoutsuper[args__] := Max[Re[Eigenvalues[Dot @@ ArrayReshape[Drop[{args}, 10], {2, 4, 4}]]]]

I really don't think I can help you if you can't provide simpler examples. I mean, just forget your actual domain completely, and just show an example of dynamically generating a deferred derivative (or whatever we're trying to do here). Show an example where you know the right answer and show me the right answer. The stuff you give me is too far along, and I don't know where to start looking, and so I end up spending a lot of time reverse engineering your code. I'm not willing to do that any longer.

Some general advice: start small and take baby steps. Don't get this far into your coding before you try to fix it. Start with the absolute simplest representation of your problem (or a minimal alternative to your problem) and just do one computation/transformation and make sure it works. Then build on that foundation with one more dead simple computation/transformation. You have so much crazy code here that I don't know if you've made a straight up semantic error or if you're just mis-using a Mathematica function or if we just need to change the order of evaluation. There may be a simple fix, or this whole thing might actually be impossible. I have no idea where we are on that spectrum.

POSTED BY: Eric Rimbey
Posted 2 years ago
POSTED BY: Iuval Clejan
Posted 2 years ago
POSTED BY: Eric Rimbey
Posted 2 years ago
POSTED BY: Iuval Clejan
Posted 2 years ago

No need to pay.

POSTED BY: Eric Rimbey
Posted 2 years ago

How does mixing up the order of the arguments (some of which are lists) and then finding their original order help me?

I was just demonstrating various ways of accessing the arguments and parts of argument in the RHS of the function definition. I don't know how you actually need to use the indexes, so I made something up.

Also the title your post here is

Referring to arguments of a function by order in which they appear

so, I dunno, sorry to not be able to read your mind, but it sounds like you're struggling with, I dunno, making the RHS of your function definition refer to the arguments in some way. I'd ask for you to give me a concrete output that you're trying to achieve so that I can then show you how to write your function to produce that output, but I'm afraid you'd insult my intelligence again. Dude, just ask a straightforward question using a minimal example. Provide inputs and expected outputs. If you can't do that, then you'll just have to endure the frustration of watching me trying to figure out what you're asking for.

POSTED BY: Eric Rimbey
Posted 2 years ago

I'm not confident that this is the final answer, but I just want to use this as a point of discussion to try to nail down where the disconnect is. What if we just used a purely formal symbol for the "non-analytical" function and then provided whatever implementation you want as a second function?

av0 = {1., 1.};
varex = Table[av[i][t], {i, 2}];
eqnlist =
  {Derivative[1][av[1]][t] == Derivative[1, 0][f] @@ varex,
   Derivative[1][av[2]][t] == Derivative[0, 1][f] @@ varex,
   av[1][0] == av0[[1]],
   av[2][0] == av0[[2]]}

(* 
  {Derivative[1][av[1]][t] == Derivative[1, 0][f][av[1][t], av[2][t]],
   Derivative[1][av[2]][t] == Derivative[0, 1][f][av[1][t], av[2][t]], 
   av[1][0] == 1., 
   av[2][0] == 1.}
 *)

And then,

fImplementation[x_, y_] := (1/2) (1 - y) x^2 + (1 - x) y^2 + x  y;
eqnlist /. f -> fImplementation
(*
  {Derivative[1][av[1]][t] == av[1][t]*(1 - av[2][t]) + av[2][t] - av[2][t]^2, 
   Derivative[1][av[2]][t] == av[1][t] - av[1][t]^2/2 + 2*(1 - av[1][t])*av[2][t], 
   av[1][0] == 1., 
   av[2][0] == 1.}
 *)

Or even this:

f[x_, y_] := (1/2) (1 - y) x^2 + (1 - x) y^2 + x  y;
av0 = {1., 1.};
varex = Table[av[i][t], {i, 2}];
eqnlist =
 {Derivative[1][av[1]][t] == Derivative[1, 0][Inactive[f]] @@ varex,
  Derivative[1][av[2]][t] == Derivative[0, 1][Inactive[f]] @@ varex,
  av[1][0] == av0[[1]],
  av[2][0] == av0[[2]]}

And then when you want your implementation to be applied:

eqnlist // Activate

Does that get us anywhere?

POSTED BY: Eric Rimbey
Posted 2 years ago

Eric, I'm thinking you might have missed one of my posts, please go back through them all (I should too, to make sure they all posted successfully). I've done my utmost best to simplify the problem and tell you why your solution doesn't work, and tell you exactly what is needed. Your comment sounded sarcastic because if I knew how to "manually change the thing that doesn't work to the thing that does work and show me that" then the problem would be solved.

POSTED BY: Iuval Clejan
Posted 2 years ago

Oh, well then I've completely misunderstood where the problem is.

Look you posted this:

f1[a_] := a[[1]] (1 - a[[2]]) + a[[2]] - a[[2]]^2;
f2[a_] := a[[1]] - 0.5 a[[1]]^2 + 2 (1 - a[[1]]) a[[2]];
av0 = {1., 1.};
varex = Table[av[i][t], {i, 2}];
eqnlist = {Derivative[1][av[1]][t] == f1[varex], 
   Derivative[1][av[2]][t] == f2[varex], av[1][0] == av0[[1]], 
   av[2][0] == av0[[2]]};
solDEsuper = NDSolve[eqnlist, varex, {t, 0, 1.4}]

and said that it worked.

I posted this:

avInit = {1, 1};
avFns = Array[av, 2];
avFnsApplied = Through[avFns[t]]; 

avProtoList[a_List] := 
  0.5  (1 - a[[2]])  a[[1]]^2 + (1 - a[[1]])  a[[2]]^2 + 
   a[[1]]   a[[2]];
avProto[args___] := avProtoList[{args}];

g1 = Derivative[1, 0][avProto];
g2 = Derivative[0, 1][avProto];

eqnlist = {Derivative[1][av[1]][t] == g1 @@ avFnsApplied, 
   Derivative[1][av[2]][t] == g2 @@ avFnsApplied, 
   av[1][0] == avInit[[1]], av[2][0] == avInit[[2]]};
solDEsuper = NDSolve[eqnlist, avFnsApplied, {t, 0, 1.4}]

and you said that it didn't work.

When I look at eqnlist for each of them, I can't tell the difference. I thought if we used a simpler function, I could see the difference by inspection. But you don't want to provide a simpler function. Fine, just tell me what's different about these two. I'm sorry that I'm just not picking up on it, but that's where we are.

But then later, I forced you to tell me whether that expression was correct or not, and you said that it wasn't. So, I thought the problem was in generating eqnlist, and that maybe you could indicate the difference by giving me a reference. But now you seem to be saying that you don't know what eqnlist should even look like, you just know it's wrong. Okay, that's fair, but now we're talking about a mathematics problem, not a programming problem. So, you'll have to lead me through the mathematics before I can provide the code.

Now, you probably think I'm being stupid, and you'll say "no, no, that's not what I said/meant", and that's totally fine. Communication is hard. But I, as of right now, have no idea what/where the problem is. I know that for you, the problem is something about whether arguments are passed as a sequence or as a list. To me, that's a trivial problem, and I'm extremely confident that I can solve it. But I've been failing to produce a good result even though it seems to match the good results you've previously given me. It sounds like you're getting "good answers" with sequences, so I'm just trying to pin down what a good answer is.

So, at the end of the day, it sounds to me like we'd like to feed some inputs into NDSolve. We've got to generate those inputs somehow. You seem to be able to recognize when those inputs are good or not. I don't seem to be able to figure that part out. Also, I'm not really sure where we're starting here. It sounds like there are things "before" we start defining f, f1, etc. I know in your real world problem, those things are big and complicated, but in our toy problem, I would think you could give them to me explicitly. So, my brain is saying, "if he gives me the uber inputs, A, and then the inputs to NDSolve, B, then I can figure out how to transform A into B".

If you can tell me where I'm going wrong in any of the above thinking, that would help greatly. If you can give me any concrete examples that I can compare to at any point in the computation, that would help greatly. If you can try different words to explain your intent, that might help.

POSTED BY: Eric Rimbey
Posted 2 years ago

Dear Eric, I do appreciate your help very much and your persistence on insisting for clarity. Please see below:

"Oh, well then I've completely misunderstood where the problem is.

Look you posted this:

f1[a_] := a[[1]] (1 - a[[2]]) + a[[2]] - a[[2]]^2;
f2[a_] := a[[1]] - 0.5 a[[1]]^2 + 2 (1 - a[[1]]) a[[2]];
av0 = {1., 1.};
varex = Table[av[i][t], {i, 2}];
eqnlist = {Derivative[1][av[1]][t] == f1[varex], 
   Derivative[1][av[2]][t] == f2[varex], av[1][0] == av0[[1]], 
   av[2][0] == av0[[2]]};
solDEsuper = NDSolve[eqnlist, varex, {t, 0, 1.4}]

and said that it worked."

My bad, that IS confusing. I meant it worked in this example and didn't give an error. It will not work in my actual problem, because in my actual problem I can't have the RHS of eqnlist be given as an analytic function of the arguments, as in what f1 and f2 are doing.

"I posted this:

avInit = {1, 1};
avFns = Array[av, 2];
avFnsApplied = Through[avFns[t]]; 

avProtoList[a_List] := 
  0.5  (1 - a[[2]])  a[[1]]^2 + (1 - a[[1]])  a[[2]]^2 + 
   a[[1]]   a[[2]];
avProto[args___] := avProtoList[{args}];

g1 = Derivative[1, 0][avProto];
g2 = Derivative[0, 1][avProto];

eqnlist = {Derivative[1][av[1]][t] == g1 @@ avFnsApplied, 
   Derivative[1][av[2]][t] == g2 @@ avFnsApplied, 
   av[1][0] == avInit[[1]], av[2][0] == avInit[[2]]};
solDEsuper = NDSolve[eqnlist, avFnsApplied, {t, 0, 1.4}]

and you said that it didn't work."

It didn't work for my actual problem for the same reason the previous didn't work. I tried the Real hack for this code and it produced an error (as it did for my examples with lists), but maybe I didn't do it right.

"When I look at eqnlist for each of them, I can't tell the difference. I thought if we used a simpler function, I could see the difference by inspection. But you don't want to provide a simpler function. Fine, just tell me what's different about these two. I'm sorry that I'm just not picking up on it, but that's where we are."

There is no difference for any function. Coming up with a simple yet non-analytic in terms of its variables function has eluded me, though I haven't tried very hard. Perhaps there are other ways to deal with this besides what has worked for me without lists (the Real hack--also other conditionals on the variables that leave the function unevaluated until its arguments are non-symbolic, like NumberQ)

"But then later, I forced you to tell me whether that expression was correct or not, and you said that it wasn't. So, I thought the problem was in generating eqnlist, and that maybe you could indicate the difference by giving me a reference. But now you seem to be saying that you don't know what eqnlist should even look like, you just know it's wrong. Okay, that's fair, but now we're talking about a mathematics problem, not a programming problem. So, you'll have to lead me through the mathematics before I can provide the code."

You can see what a good eqnlist should look like for either the simple file I initially posted or the more complicated ones that came later. Just type eqnlist in a separate cell after evaluating one of the cells that produced errors (because they had lists and the Real hack) or the ones that had the real hack, no lists and did not produce errors. Or take the semicolon out after the definition of eqnlist. It is something that has derivatives in it on the RHS of the equations, as opposed to explicit expressions in terms of the NDSolve variables.

"Now, you probably think I'm being stupid, and you'll say "no, no, that's not what I said/meant", and that's totally fine. Communication is hard. But I, as of right now, have no idea what/where the problem is. I know that for you, the problem is something about whether arguments are passed as a sequence or as a list. To me, that's a trivial problem, and I'm extremely confident that I can solve it. But I've been failing to produce a good result even though it seems to match the good results you've previously given me. It sounds like you're getting "good answers" with sequences, so I'm just trying to pin down what a good answer is."

It's a combination of TWO things. One is lists vs Sequence. The other is a function that can be algebraically written in terms of its arguments vs one that cannot. I want to deal with both simultaneously. I have a solution to either one by itself, but not when both are combined.

"So, at the end of the day, it sounds to me like we'd like to feed some inputs into NDSolve. We've got to generate those inputs somehow. You seem to be able to recognize when those inputs are good or not. I don't seem to be able to figure that part out. Also, I'm not really sure where we're starting here. It sounds like there are things "before" we start defining f, f1, etc. I know in your real world problem, those things are big and complicated, but in our toy problem, I would think you could give them to me explicitly. So, my brain is saying, "if he gives me the uber inputs, A, and then the inputs to NDSolve, B, then I can figure out how to transform A into B"."

The uber inputs would be a function that is not able to be written down explicitly in terms of its arguments (which also happen to be lists). The eigenvalue of a rank 5 matrix would be the simplest one I can think of. Or maybe a function defined implicitly as a solution to an equation that can only be solved numerically. But you can also look at the bigger files without having to reverse engineer them, just look at ffoutsuper as a black box function that is not possible to evaluate symbolically in terms of its arguments. Barring that, just make something work that uses the Real, or NumberQ hack as a conditional for one of the arguments to f. Or find some way to keep eqnlist without evaluating f or its derivatives. Or find a way to do what I was proposing at the beginning of this thread: take a list, turn it to a sequence before passing to f, then reconstruct it inside f, so that I can pass lists to other functions that I call from within f.

"If you can tell me where I'm going wrong in any of the above thinking, that would help greatly. If you can give me any concrete examples that I can compare to at any point in the computation, that would help greatly. If you can try different words to explain your intent, that might help."

I tried. I appreciate you trying to understand what I wrote and asking more questions if need be.

POSTED BY: Iuval Clejan
Posted 2 years ago

Okay, I think I see what you're saying now. I'll try to take a stab at it later. But in the meantime, here's the simplest thing I can think of to satisfy your suggestion to

take a list, turn it to a sequence before passing to f, then reconstruct it inside f, so that I can pass lists to other functions that I call from within f.

In fact, I'll show both "directions":

functionList[list_List] := dependencySeq @@ list;
functionList[{1, 2, 3}]
(* dependencySeq[1, 2, 3] *)

functionSeq[args___] := dependencyList[{args}];
functionSeq[1, 2, 3]
(* dependencyList[{1, 2, 3}] *)

inputList = {a, b, c};
functionSeq @@ inputList
(* dependencyList[{a, b, c}] *)

My intuition is that this is too simplistic to work, but without going back to look at eqnlist or ffoutsuper right now, that's the simplest thing that satisfies my best attempt to interpret your words here.

POSTED BY: Eric Rimbey
Posted 2 years ago

Okay, maybe this is what you're after. I changed variable names to help myself keep track of what's going on.

avInit = {1, 1};
avFns = Array[av, 2];
avFnsApplied = Through[avFns[t]]; (* {av[1][t], av[2][t]} *)

avProtoList[a_List] := 0.5 (1 - a[[2]]) a[[1]]^2 + (1 - a[[1]]) a[[2]]^2 + a[[1]]  a[[2]];
avProto[args___] := avProtoList[{args}];

g1 = Derivative[1, 0][avProto];
g2 = Derivative[0, 1][avProto];

eqnlist = {
  Derivative[1][av[1]][t] == avProtoList[avFnsApplied], 
  Derivative[1][av[2]][t] == avProtoList[avFnsApplied], 
  av[1][0] == avInit[[1]], 
  av[2][0] == avInit[[2]]};
solDEsuper = NDSolve[eqnlist, avFnsApplied, {t, 0, 1.4}]

I didn't try to check that the result is correct. I just tried to do a formal transformation into what I think you're asking for.

POSTED BY: Eric Rimbey
Posted 2 years ago

Not quite. Maybe somehow include g1 and g2 in the eqnlist. As it is now, the equation does not have the Derivatives (with respect to the list arguments, not time), and also eqnlist has done the evaluation symbolically of f, instead of keeping it unevaluated.

POSTED BY: Iuval Clejan
Posted 2 years ago

Ugh. Got wrapped around the axle in my translation. What about this?

eqnlist = {
  Derivative[1][av[1]][t] == g1 @@ avFnsApplied,
  Derivative[1][av[2]][t] == g2 @@ avFnsApplied,
  av[1][0] == avInit[[1]],
  av[2][0] == avInit[[2]]}
POSTED BY: Eric Rimbey
Posted 2 years ago

But you get the idea, right? One function to deal with lists and another to deal with sequences.

POSTED BY: Eric Rimbey
Posted 2 years ago
POSTED BY: Iuval Clejan
Posted 2 years ago

Okay, then I need more information. I can't tell the difference between this and what you had previously that I thought you said was good.

Is there anyway you can simplify the problem? Like just give a simple function whose derivative is just dead simple to look at and immediately recognize and then provide an actual correct solution that I can use as a test case?

I feel like we're getting lost in implementation details, and I haven't actually figured out what you really want.

Also, some commentary with your examples would be helpful. I'm not sure what's working as desired and what's not. You seem to set up an example just to indicate that it's not what you want, but it seems to work, so I don't know what the problem is.

Or maybe work backward. Hand-roll the entire NDSolve expression. Just provide the literal inputs that you want that work for NDSolve. Then show me what you have as inputs to this whole process. From there, maybe I can figure out how to get from your inputs to the final NDSolve expression.

POSTED BY: Eric Rimbey
Posted 2 years ago

I am willing to pay you $200 to solve this problem. OK, so we need two things: 1. Arguments to f have to be a bunch of lists (and some non-lists too) 2. eqnlist that is given to NDSolve should not attempt to evaluate f (or its non-time derivatives) but should be in symbolic, unevaluated Derivatives form. The reason is that f (and hence its derivatives) is not possible to evaluate symbolically, only numerically.

I don't know how to come up with a simple f that can't be evaluated symbolically (like it is in all the examples we have produced so far). I can send you two files that have the real f (called ffoutsuper in there, you will have to scroll down to see its definition which involves eigenvalues of a high rank matrix and calls to another ODE solver, and then scroll down even further to see where NDSolve is called): The first shows that as long as there are no lists in the arguments to f, NDSolve is happy and so am I.

The second doesn't work because there are lists in the args to f. You can see from these 2 files that f has no hope of being evaluated symbolically (maybe there is a clever way to do it using certain symmetries, but I will have cases in the future where these symmetries are not present that might make f be evaluatable symbolically)

POSTED BY: Iuval Clejan
Posted 2 years ago

I'm sorry, this isn't helping me. Please, please just give me literal concrete expressions that I can work with. I know it's obvious to you, but I'm not grokking. So, like in your original example, is the following even correct?

NDSolve[
  {Derivative[1][av[1]][t] == 1.*av[1][t]*(1 - av[2][t]) + av[2][t] - av[2][t]^2, 
   Derivative[1][av[2]][t] == av[1][t] - 0.5*av[1][t]^2 + 2*(1 - av[1][t])*av[2][t], 
   av[1][0] == 1., av[2][0] == 1.}, 
  {av[1][t], av[2][t]}, 
  {t, 0, 1.4}]

Does that produce the result you want? If not, show me an NDSolve expression that does produce the result you want. Then we can work backward from there. I can't figure out if this is the right "end game" and you're struggling to figure out how to get there, or if this is the wrong "end game" and you don't know where things went wrong.

POSTED BY: Eric Rimbey
Posted 2 years ago
POSTED BY: Iuval Clejan
Posted 2 years ago
POSTED BY: Eric Rimbey
Posted 2 years ago

Now you're just being funny, or sarcastic? I guess I need to think of a simple example of a function that can't be evaluated symbolically for you to "grok" what is going on. The example in those two files (nestedlevels4.3 and nestedlevels4.5 was too complicated apparently). This is probably just as frustrating for you as it is for me.

POSTED BY: Iuval Clejan
Posted 2 years ago

I'm very serious. I opened the notebooks, saw how large they were, and closed them. I'm not spending my day reverse-engineering all of that code.

You don't need to find a simpler function (although, I don't know why that's such a big deal), you just need to tell me what the "answer" is. Something I can use as a reference to check against. I'm not going to try to figure out the mathematics and I'd rather not reverse engineer a ton of code. I'm pretty sure there is a simple code issue here, but I'm tired of guessing. So, just show me exactly what a correct result would look like so that we don't just keep wasting time.

Look, you're the one with a problem to solve. I'm just trying to help out. My only investment here is just being curious about solving the programming problem. If it's not worth it to you to give me something explicit I can use as a test case, then it's not worth it. I can just move on to the rest of my life.

POSTED BY: Eric Rimbey
Posted 2 years ago

You might find a larger audience over at https://mathematica.stackexchange.com/ . Someone over there might just understand what you're asking for. Sorry I couldn't be of more help.

POSTED BY: Eric Rimbey
Posted 2 years ago
POSTED BY: Eric Rimbey
Posted 2 years ago

Maybe! Just to make sure I understand your suggestion, here is the test file I implemented it in. Do I need to combine this with your previous suggestions on the 2-way conversions of lists to sequences, so I can pass varex (there will be several of these) to other functions from f? I fear there will be scoping problems, as varex is global and not scoped within f (I could be wrong about this). All the lists need to be updated as NDSolve chugs along.

Also, I need to figure out how to automate taking derivatives before forming eqnlist. I was using such constructs as this, when I was hoping I can pass f lists directly, to differentiate f for forming eqnlist:

nderaR[i1_, i2_, m_, 
   f_] := (Derivative @@ {0, 0, ConstantArray[0, m], 
      ConstantArray[0, m], ConstantArray[0, {m, m}], 
      Normal[SparseArray[{{i1, i2} -> 1}, {m, m}]], 0, 
      ConstantArray[0, m], ConstantArray[0, m], 
      ConstantArray[0, {m, m}], ConstantArray[0, {m, m}]})[f];

one for each list

POSTED BY: Iuval Clejan
Posted 2 years ago

Do I need to combine this with your previous suggestions on the 2-way conversions of lists to sequences, so I can pass varex (there will be several of these) to other functions from f?

I don't think so. Just my opinion here, and I obviously am not an expert in the domain you're working with, but it seems to me to think of f and whatever other functions you want to take partial derivatives of as being a function of multiple variables (arguments in sequence) rather than a single list argument. So, I would write these functions that way (e.g. f[x_,y_,z_] := ...) and deal with the List <-> Sequence stuff somewhere else. All I was really showing you before is that Apply (shortcut @@) is how you replace the List head with your function f. So, the Derivative[0, 1][f] @@ varex bit is the key to that.

I fear there will be scoping problems, as varex is global and not scoped within f

I don't think that's a problem based on what I've seen so far. If you think there's a risk of that somewhere, point it out to me and I'll analyze it. Scoping in Mathematica isn't really true scoping, it's just playing games with names, so what we'd really be concerned about is actually name collisions.

All the lists need to be updated as NDSolve chugs along.

Not sure what you mean by this. We can't really control what's going on inside NDSolve, so I'm not sure what you're getting at.

Also, I need to figure out how to automate taking derivatives before forming eqnlist.

Yeah, I figured at some point we'd need a way to automate this. That should be doable, but honestly I'm confused by your derivatives. For example, if I evaluate this

nderaR[2, 1, 2, g]
(* Derivative[0, 0, {0, 0}, {0, 0}, {{0, 0}, {0, 0}}, {{0, 0}, {1, 0}}, 0, {0, 0}, {0, 0}, {{0, 0}, {0, 0}}, {{0, 0}, {0, 0}}][g] *)

I don't know how to interpret that result. I think I just don't have the mathematical knowledge, but I don't know what having all those sublists in Derivative means. But setting that aside, if you can articulate the rules for how to create that expression, we can figure out how to generalize that.

POSTED BY: Eric Rimbey
Posted 2 years ago

OK, should be able to work on it tonight and tomorrow. I will let you know if it works, and if you're amenable I still want to give you that financial reward. Thanks!

POSTED BY: Iuval Clejan
Posted 2 years ago
POSTED BY: Iuval Clejan
Posted 2 years ago

Yep, pretty sure we can take lists and transform them to sequences for Derivative.

POSTED BY: Eric Rimbey
Posted 2 years ago

In your third cell, why don't you just do the following?

f[a : {_Real, _}] := 0.5 (1 - a[[2]]) a[[1]]^2 + (1 - a[[1]]) a[[2]]^2 + a[[1]] a[[2]]
POSTED BY: Eric Rimbey
Posted 2 years ago
POSTED BY: Eric Rimbey
Posted 2 years ago
POSTED BY: Iuval Clejan
Posted 2 years ago

I'm not at all sure what you're trying to do, but here are some thoughts to get you started:

f1[args__] := {args}[[1]] + {args}[[2]];
f1[1, 2]
(* 3 *)

f2 = #1 + #2 &;
f2[1, 2]
(* 3 *)

Or, you can just overload your function:

f3[list : {_, _}] := list[[1]] + list[[2]];
f3[a1_, a2_] := f3[{a1, a2}];
f3[1, 2]
(* 3 *)

Or you can change the way you apply your function:

f4[a1_, a2_] := a1 + a2;
f4 @@ {1, 2}
(* 3 *)

But I don't understand why you think using Table and Array is creating some sort of impedance, so I don't have confidence in any of these approaches.

POSTED BY: Eric Rimbey
Posted 2 years ago

Thanks Eric for your help. I don't think I expressed what I need well, so your examples probably won't work. Here is a better explanation referring to the included notebook: The first evaluation cell has no problem because f1 and f2 are symbolically defined.

The second evaluation cell also has no problem because f1 and f2 are able to be symbolically evaluated in eqnlist, before being passed to NDSolve, by taking a symbolic Derivative of f.

The 3rd cell has a problem because I insist that the Derivative not be evaluated unless one of the arguments to f is a real number (instead of a symbol), which is the case once NDSolve gets going, but not initially. Though in this case f1 and f2 can be symbolically evaluated, in my real case they can't. If they are numerically evaluated before being passed to NDSOlve, then NDSolve will not get a list of symbolic equations. So they need to delay evaluation till NDSolve gets going (The real f is a conditional eigenvalue of a complicated large rank matrix that also depends on solving another ODE).

In the fourth cell, I show that as long as there is no list in the arguments of f, there is no problem with the same insistence on not evaluating eqnlist and keeping it symbolic so NDSolve is happy.

In the fifth cell, I try to convert the list to a sequence before passing to f, and then convert back to a list inside of f (It looks silly in this example, but in the real application keeping list structures is essential, there are many lists, they get passed on to other functions, and it becomes an unwieldy mess without them), but it doesn't work (I need to do the Extract while stripping the "Real" qualifier, I don't know how to do that yet)

POSTED BY: Iuval Clejan
Posted 2 years ago

So, which of these 5 examples is closest to what you actually want? You're demonstrating things that work, but apparently they aren't good enough. So what is your actual situation and what is it that you're actually trying to get to work?

POSTED BY: Eric Rimbey
Posted 2 years ago

The third cell would be ideal since it keeps the list structure. The fifth cell tries to get rid of the list structure (in reality I would also Flatten some Joined lists, some of which are also 2 dimentional, nested lists, to create args, I didn't bother showing that in this example), but it's far from ideal and also a hack, to compensate for the bug that Derivative can't handle qualifiers in lists. The other examples that actually work, either do not have lists (in arguments to f), or have functions that can be evaluated symbolically (and their derivatives too), which is not my case in the actual application. And I haven't gotten the fifth cell to work yet, though maybe it is close?

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