I’d like for this to work in general, with several lists (adj, famadj, etc, which actually look like matrices) of varying sizes. I’d like to not have to define local variables inside the function totaladj, as shown in the code that is commented out. Right now it doesn’t work (unless I use the commented out code). Any help would be greatly appreciated.
I don’t understand the NMinimize at the end, because you’re not passing arguments of the right shape for that. But I’ve made my best guess at what totaladj is supposed to do, and I’d recommend something like the following.
First, break the problem into smaller pieces. You eventually want to work and a bunch of matrices at once, but solve the problem for a single matrix first.
MatrixCost[m_?MatrixQ] :=
With[
{threshold = 0.1*Times @@ Dimensions[m]},
Count[Map[GreaterThan[threshold], m, {2}], True, {2}]]
I saw “cost” in your code, so I thought maybe that would be a good name. We can test this:
SeedRandom[25];
testA = RandomReal[{0, 4}, {3, 4}]
(* {{0.0395876, 0.93185, 0.802464, 0.737812},
{1.11064, 0.253445, 2.87187, 3.85676},
{0.764152, 2.42748, 0.915865, 3.21226}} *)
MatrixCost[testA]
(* 4 *)
testB = RandomReal[{0, 4}, {2, 2}]
(* {{0.0495114, 2.80439}, {3.05848, 1.00112}} *)
MatrixCost[testB]
(* 3 *)
Now let’s use this for a function that works with several matrices.
MatricesCost[ms___?MatrixQ] := Total[MatrixCost /@ {ms}];
MatricesCost[]
(* 0 *)
MatricesCost[testA]
(* 4 *)
MatricesCost[testA, testB]
(* 7 *)
MatricesCost[testA, testB, testA]
(* 11 *)
Hi Eric! Thanks for that. I modified things a bit to fit what is needed (like I want to give a variable list of matrices to the function to be optimized totaladj, so I added {} in its definition). I just want to make sure that NMinimize is doing the right thing, can you please check if I am giving it the right format? In the example file (vastly simplified) it doesn’t have the constraints that make this problem bounded, so I can’t check if it’s the right format. Note that Nminimize has all the matrices flattened and the variables are the matrix elements, whereas totaladj expects matrices.
I think that given your definitions
NMinimize[totaladj[{Adj, Adjfam}], vars]
is a correct form for NMinimize. As you say, in the specific case you provide, the there is no bounded solution.
It seems to work, though I don’t know for sure yet. Running the full file, so far no errors. I also tried to have the list input when calling the function, but without the args list in the function definition, by adding function[Sequence[args]], but it didn’t work. So I had to add the list in the function definition.
Still not working. NMinimize doesn’t send numeric variables to MatrixBenefit and MatrixCost. I added a Print[m[[1,1]]] line to demonstrate this.
argsexample3.nb (9.65 KB)
You’re going to need to step back and explain what you’re trying to do. I have no idea what you’re talking about, and I have no idea what you think is going wrong. I see print output when I run your code, so I don’t know why you think arguments aren’t being passed. I’ve already reverse engineered your code once, and I’m not going to do it again. Can’t you just explain what you’re trying to do and what your expected output should be? Like, give us a sample problem where you know the expected output and walk us through it.
I am trying to do a constrained minimization of a utility function where the variables are matrix elements for different matrices. The utility function I have is more complicated than in the example, but even in the simple example, the matrix elements passed to MatrixCost and MatrixBenefit need to be numerical for those functions to do the right thing (the greater than threshold condition is never satisfied, if the matrix elements are symbolic, for example). For some reason they aren’t, as demonstrated by m[[1,1]] being symbolic when printed.
Do you want to know the. big picture of what this minimization is about? I can’t see why that is relevant, but I can tell you if you’re interested.
No, I don’t want to see the big picture. I want you to explain your code. What do you think it’s doing? What should it do? What output, exactly what output, do you expect to see in this example? I don’t know what you think is wrong. What exactly is wrong? How is it different, exactly, from what you expect? you choose variable names that mean nothing to me, so I don’t’ know what I’m looking at. Can you reduce the clutter at all? Do I really need to see numnodes? numfamilies? nlevel? L[0] and other Ls? B[0] and other Bs? You keep saying you need something numeric, but then you pass everything around as symbols. So, what do I need to trace through? Again, tell me exactly what output you expect so I can see how your actual output is different.
If I had a function like totaladj[{ms___?MatrixQ}] := ..., I would write a test with an empty list. Then a test with exactly on matrix, probably a 2x2. I would only move on if those worked as expected. Just simplify everything before moving on. You’re asking me to reverse engineer your code to figure out the problem rather than just tell me exactly, exactly, what the problem is.
See attached even simpler example, where I sent totaladj a list of just 1 2x2 matrix, instead of several matrices. The minimum would occur if all matrix elements were less than 1/4. They are instead set to one by the minimization, the value of totaladj should be 4 (not 0 for those values, as returned by NMinimize), and the print statement prints a symbol instead of a number. See it do the right thing for both the call to MtarixCost and totaladj.
I have to pass the NMimimize a symbolic list of variables, don’t I? But it doesn’t pass totaladj a numeric list, for some reason.
I still have zero idea what you’re trying to do, but let’s just look at one function:
MatrixCost[m_?MatrixQ] :=
With[{threshold = 1/Times @@ Dimensions[m]}, Print[m[[1, 1]]];
Count[Map[GreaterThan[threshold], m, {2}], True, {2}]]
In your scenario, the m will be
{{adj[1,1],adj[1,2]},{adj[2,1],adj[2,2]}}
So, for each of those entries we’re trying to compute something like
adj[1,1]>1/4
That does not evaluate to True for any of the entries. So, your count will be 0. So, totaladj will be 0. So
NMinimize[totaladj[args], constraints, vars]
Will actually be
NMinimize[0, {-1 <= adj[1, 1] <= 1, -1 <= adj[1, 2] <= 1, -1 <=
adj[2, 1] <= 1, -1 <= adj[2, 2] <= 1}, {adj[1, 1], adj[1, 2],
adj[2, 1], adj[2, 2]}]
So, why are your passing 0 to NMinimize? I don’t understand. I don’t know what else to tell you, because I don’t understand what you’re trying to do.
this is a duplicate reply, because the first time it just quoted Eric’s reply.
Yes, so how do I pass totaladj a list of numerical matrices instead of symbolic ones? I have to go through NMinimize, because that is what I am trying to do (I’ll say it again: Minimize a function of many matrix elements, subject to some constraints, it’s really not complicated, I don’t know how to make it simpler for you). Why is NMinimize not passing totaladj numbers? I don’t know! You would think the N in NMinimize means it would do a numerical minimization instead of an algebraic one.
So How can I tell NMinimize to pass numbers to totaladj?
bug in reply software
Yes, so how do I pass totaladj a list of numerical matrices instead of symbolic ones? I have to go through NMinimize, because that is what I am trying to do (I’ll say it again: Minimize a function of many matrix elements, subject to some constraints, it’s really not complicated, I don’t know how to make it simpler for you). Why is NMinimize not passing totaladj numbers? I don’t know! You would think the N in NMinimize means it would do a numerical minimization instead of an algebraic one.
So How can I tell NMinimize to pass numbers to totaladj?
Okay. Write out for me the single NMinimize expression that you want to generate. Just pretend that all of your code that preceded the NMinimize worked and show me what you’re trying to minimize. Do it by hand. Just forget about totaladj. Just show me the goal. Feel free to explain the semantics of whatever you come up with, or even relate it back to your original code, but do all of that as exposition, not code. The only code I want to see is a complete and valid NMinimize expression that you want to eventually be able to generate from your data and definitions.
Thanks for your patience. I am simplifying what I really want, for the sake of exposition.
I want totaladj to take all the matrix elements in all the matrices passed to it (which can vary as to their number and size, though they are always square matrices), and add up the number of times a matrix element exceeds a threshold (itself determined by the size of the matrix it comes from, so for each matrix a different threshold, in the sample code it was 1/size_of_matrix^2 or something proportional to that). I believe this part you had no trouble understanding. For a specific case of 1 2x2 matrix, what I want to minimize would be a function of 4 variables (m[1,1],m[1,2],m[2,1] and m[2,2] with appropriate double bracket syntax), outputting how many of them exceed 0.25.
I want NMinimum to numerically find the value at the minimum of this function under the simple constraints that each matrix element can only vary between -1 and 1, as well as the values of all the dependent variables (all the matrix elements) at the minimum, which NMinimum does as a matter of course. For the specific example above, the minimum would occur anywhere in the region where these variables are between -1 and 0.25, and the value at the minimum would be 0. But for some reason, NMinimum seems to pass totaladj symbolic variables instead of numerical ones. Maybe it only does it once before it switches to numerical? That would be OK, but tests I’ve done with the more complicated real problem suggest otherwise.
The real function to minimize involves other additional operations on these matrices, such as adding up all the elements (the MatrixBenefit part), and splitting them into block matrices along the diagonal that have different operations done inside them than outside, and much more complicated constraints. I have all the code for that written, and it works. The only part that doesn’t work is NMinimum passing symbolic arguments to the utility function (totaladj) instead of numerical ones.
I emphasize that the error is mathematical. It is not a programming error, nor a question of numerical method. If the function should theoretically be bounded, then I suggest there’s an error in its code somewhere. The code defines totaladj[args] to be a linear function, which clearly is unbounded.
OTOH, if you just want it to try see what happens when NMinimize[] runs an numerical algorithm on your function, clear totaladj and use NumericQ with MatrixQ in its definition:
totaladj[{ms___?(MatrixQ[#,NumericQ]&)}]:= …
You should get the following (mathematical!) error, which numerically confirms the error NMinimize detected when NMinimize[] evaluated totaladj[args] with symbolic arguments:
NMinimize::cvdiv: Failed to converge to a solution. The function may be unbounded.
I emphasize that the error is mathematical. It is not a programming error, nor a question of numerical method. If the function should theoretically be bounded, then I suggest there’s an error in its code somewhere. The code defines totaladj[args] to be a linear function, which clearly is unbounded.
OTOH, if you just want it to try see what happens when NMinimize[] runs an numerical algorithm on your function, clear totaladj and use NumericQ with MatrixQ in its definition:
totaladj[{ms___?(MatrixQ[#,NumericQ]&)}]:= …
You should get the following (mathematical!) error, which numerically confirms the error NMinimize detected when NMinimize[] evaluated totaladj[args] with symbolic arguments:
NMinimize::cvdiv: Failed to converge to a solution. The function may be unbounded.
I am not even seeing your latest reply here, so I will quote from the email:
Michael said: I emphasize that the error is mathematical. It is not a programming error, nor a question of numerical method. If the function should theoretically be bounded, then I suggest there’s an error in its code somewhere. The code defines totaladj[args] to be a linear function, which clearly is unbounded.
Iuval repiies: NO! THe function is bounded by the constraint that all its args are between -1 and 1. This constraint is passed to NMinimize in the code.
Michael said: "OTOH, if you just want it to try see what happens when NMinimize[] runs an numerical algorithm on your function, clear totaladj and use NumericQ with MatrixQ in its definition:
totaladj[{ms___?(MatrixQ[#,NumericQ]&)}]:= …
You should get the following (mathematical!) error, which numerically confirms the error NMinimize detected when NMinimize[] evaluated totaladj[args] with symbolic arguments:
NMinimize::cvdiv: Failed to converge to a solution. The function may be unbounded."
Iuval replies: I do NOT see that, because in my example I have constraints which bound the function. So it does the right thing with this extra NumericQ addition. However, for any sizable problem, the time it takes to run is way too slow, making it completely impractical. Maybe I should send this to the developers as a bug?
I’m going to try Method->“DifferentialEvolution” or “NelderMead”, to see if it speeds things up. Gradient methods will not work here.