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.
|
|
|
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?
|
|
|
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.
|
|
|
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:
nderaR[i1_, i2_, m_,
f_] := (Derivativ@@ {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}], ConstantArvFnsApplied]];
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]]};
soper = 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.
|
|
|
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.
|
|
|
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.
|
|
|
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]]}
|
|
|
But you get the idea, right? One function to deal with lists and another to deal with sequences.
|
|
|
So close! It works, but unfortunately eqnlist has evaluated the derivative of f symbolically. Recall that in the actual case this cannot be done, since f can only be evaluated numerically. If I recall, what happens if I don't use the "Real" hack (which gives me a "non-numerical derivative at t=0 when I have lists, but works without lists), which is also what will happen if I use your solution in the actual case, is that it keeps trying to evaluate Eqnlist symbolically, never even getting to evaluate NDSolve and just doesn't give me output.
|
|
|
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.
|
|
|
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)
Attachments:
|
|
|
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.
|
|
|
Hmm... I don't know how to make it simpler. If you look at the two big files I included, the first has no lists and it works, the second has lists and it doesn't work. The same is true for the simpler file I included originally, but in that one there is an f that can have its derivative be taken symbolically (but can be prevented from doing so by the "Real" hack). In the more complex files, in both cases there is an f that is not able to have its derivatives be taken symbolically. The code snippet you posted:
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}]
has explicit expressions for the equations in eqnlist (effectively evaluating derivatives of f), so it it NOT what is needed.
|
|
|
so it it NOT what is needed.
Excellent! That's progress. So, what is needed? Clearly we're having a communication issue. You think you've provided me with enough info, but I don't understand. Why can't you literally just manually change the thing that doesn't work to the thing that does work and show me that? If you do that, I can almost guarantee that I can show you how to get there.
|
|
|
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.
|
|
|
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.
|
|
|
You said
The first shows that as long as there are no lists in the arguments to f, NDSolve is happy and so am I.
and
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)
I know you think you're being helpful, but this is just a distraction. I need to know the actual things you want to pass in to NDSolve. Just forget about the list versus non-list arguments for now. I just need to have a target to shoot for. These informal descriptions are just not helping me. I'm like 95% sure this is doable in a very easy way, but so far I've failed to hit your target, and I don't know what my errors are. Don't tell me in words like "evaluate f symbolically". Just give me a concrete target that I can shoot for.
|
|
|
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
|
|
|
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.
|
|
|
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!
|
|
|
As far as the derivatives, they have to have the same number of arguments as the function f. But I want to be able to have them applied in a systematic way to the list elements. So I will need something to convert the lists to sequences that I can pass to Derivative, while manipulating the lists.
|
|
|
Yep, pretty sure we can take lists and transform them to sequences for Derivative.
|
|
|
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]]
|
|
|
The only reason I want at least one of the elements of the list of arguments passed to f to be real, is a hack. I want to pass NDSolve a list of symbolic equations. Since f in my actual problem can't be symbolically evaluated, the Real qualifier prevents evaluation when the derivatives are taken (the ones with respect to the arguments of f, not the ones with respect to t), to produce acceptable (to NDSolve) symbolic equations. Once NDSolve gets going, it replaces the arguments by real numbers, and then f can be evaluated. This can be seen to work in the fourth cell, which does not have a list of arguments passed to f. But I need to have a bunch of lists passed to f in my real (meaning actual, not as in real vs complex vs symbolic) example. Perhaps this could be done with Hold and Release as well (instead of the Real hack) but I have been so far unsuccessful in achieving that.
|
|
|
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.
|
|
|
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)
|
|
|
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?
|
|
|
Reply to this discussion
in reply to
|