1
$\begingroup$

I'm trying to take the determinant of an 11x11 matrix, constructed out of some functions I've defined

lagz[n_, m_, z_, zbar_] := 
 1/Sqrt[Pi*a^2*n!*m!]* E^(z*zbar/(2.*a^4)) * (a)^(m + n)*
  D[ E^(-(z*zbar)/a^4), {z, n}, {zbar, m}]
lagnlz[n_, l_, z_, zbar_] := 
 Sqrt[n!/(Pi*a^2*(n + l)!)]* (z/a)^l LaguerreL[n, l, z*zbar/a^2]*
  E^(-z*zbar/(2.*a^2))

lag[n_, l_, r_, θ_] := 
 lagnlz[n, l, z, zbar] /. {z -> r*E^(I*θ), 
   zbar -> r*E^(-I*θ)}
lagcc[n_, l_, r_, θ_] := 
 lagnlz[n, l, z, zbar] /. {z -> r*E^(-I*θ), 
   zbar -> r*E^(I*θ)}

The main functions are lag and lagcc, functions of n, l, z, and zbar (n and l are integers that specificy the function and z and zbar are coordinates). I pick which of these enter the matrix with the following code:

MaxEn = 5;
MaxState = Binomial[MaxEn + 1, 2];
nlBasis = {{0, 0}};
part = 10;
For[En = 1, En < MaxEn, En++, 
 instances = 
  FindInstance[2 n + l == En && n + l >= 0 && n >= 0, {n, l}, 
   Integers, En + 1];
 For[iter = 1, iter <= En + 1, iter++,
  nlBasis = Join[nlBasis, {{n, l}} /. instances[[iter]]]
  ]
 ]
nlBasis // MatrixForm;
Ω = .0001;
stateEnergy = 
  Table[2*nlBasis[[i, 1]] + 
    nlBasis[[i, 2]] *(1 - Ω), {i, 1, MaxState}];
stateEnergy // MatrixForm;
lowest = Ordering[stateEnergy, part]; 

The variable in the above code named "part" determines the size of the matrix (for part = 10 corresponds to a 10x10 matrix). Also, each row is a function of a different set of coordinates z and zbar (meaning z1, zbar1, ...). Actually to be more clear, I substitute z and zbar for x and theta. I then construct the matrix with the code:

Table[ lag[nlBasis[[lowest[[j]], 1]], nlBasis[[lowest[[j]], 2]], 
  Subscript[x, i], Subscript[\[Theta], i]], {i, 1, part}, {j, 1, 
  part}]

All of this runs very quickly. I use the Subscript[x,i] and Subscript[theta,i] as variables However, when I try to find the determinant of this matrix, it takes a relatively long time (on the order of a few minutes). For the 11x11 case, it takes much longer and often just Aborts mid computation. Is there any reason this determinant takes so long to compute, and is there any way to make it faster? Ultimately, I intend to find the maximum of this determinant in all 2*part variables. I was thinking perhaps it's the symbolic aspect of this determinant that is taking so long and that if the numbers were already plugged in, it might find the determinant faster. However, I don't know how to make the "FindMaximum" function plug in the coordinates into the matrix before it computes the determinant, unless it is doing this already and it's still this slow. Regardless, I'm curious as to why this takes so long and if there is any way to speed this up.

Edit:

Here is the code I am using to find the maximum:

FindMaximum[
 Re[Det[Table[ 
      lag[nlBasis[[lowest[[j]], 1]], nlBasis[[lowest[[j]], 2]], 
       Subscript[x, i], Subscript[\[Theta], i]], {i, 1, part}, {j, 1, 
       part}]]*
    Det[Table[ 
      lag[nlBasis[[lowest[[j]], 1]], nlBasis[[lowest[[j]], 2]], 
       Subscript[x, i], -1*Subscript[\[Theta], i]], {i, 1, part}, {j, 
       1, part}]]] /. {a -> 1.}, {Subscript[x, 1], 
  0.6177749722153458`}, {Subscript[\[Theta], 1], 
  3.1764648902647084`}, {Subscript[x, 2], 
  1.6214044657570879`}, {Subscript[\[Theta], 2], 
  4.408949980461034`}, {Subscript[x, 3], 
  1.7324468379727702`}, {Subscript[\[Theta], 3], 
  2.8394499241840543`}, {Subscript[x, 4], 
  1.608504613583385`}, {Subscript[\[Theta], 4], 
  2.053895206806825`}, {Subscript[x, 5], 
  1.711949337839623`}, {Subscript[\[Theta], 5], 
  3.623549054621504`}, {Subscript[x, 6], 
  1.651555081698822`}, {Subscript[\[Theta], 
   6], -0.30239485773757546`}, {Subscript[x, 7], 
  1.6779859650024196`}, {Subscript[\[Theta], 7], 
  0.4829787551630289`}, {Subscript[x, 8], 
  0.6177981188047424`}, {Subscript[\[Theta], 
   8], -1.0122013299822765`}, {Subscript[x, 9], 
  1.7591542070326502`}, {Subscript[\[Theta], 
   9], -1.0881131166350275`}, {Subscript[x, 10], 
  1.751786033459686`}, {Subscript[\[Theta], 10], 
  1.2679475660945354`}, {Subscript[x, 11], 
  0.6177768006365136`}, {Subscript[\[Theta], 11], 
  1.0804940116342638`}]

The starting points for the maximization are points I found using NMaximize, and I wanted to use FindMaximum to try to see if it's truly accurate/make it more accurate.

$\endgroup$
7
  • $\begingroup$ Perhaps most simply, I am trying to run FindMinimum on a determinant of a matrix. I would like FindMinimum to plug in the coordinates before mathematica takes the determinant, as it seems taking the determinant symbolically is very costly. $\endgroup$
    – Zonova
    Commented Jun 1, 2020 at 4:42
  • $\begingroup$ Can you give the code you are using FindMinimum in. $\endgroup$
    – SPPearce
    Commented Jun 1, 2020 at 5:12
  • 2
    $\begingroup$ Define a function that calculates your determinant only after injection of numerical values. For instance imagine you have a matrix m containing symbols a and b. You could write: detm[aval_?NumericQ, bval_?NumericQ] := Det[m /. {a -> aval, b -> bval}]. This will only execute if the arguments are numbers, then inject those numbers into your matrix before calculating the determinant numerically. You could also use Det[N[m /. {a -> ...}]] to make sure that your matrix is at machine precision. $\endgroup$
    – MarcoB
    Commented Jun 1, 2020 at 5:12
  • 3
    $\begingroup$ What @MarcoB suggested is the right way to go about this, for more than one reason. As for 11x11, that is the upper end for which cofactor expansion is used. You can try to fool Det by adding a last row and column with just a 1 in the (12,12) position and zeros elsewhere. But this might get bogged down for other reasons, because this type of computation is notorious for intermediate (and sometimes final) swell. (Basically: small input can give rise to huge output.) $\endgroup$ Commented Jun 1, 2020 at 15:23
  • 3
    $\begingroup$ @Zach Glad it helped! You could write a self-answer to your question to explain what you did. It would be useful to future visitors of the site to see exactly what you implemented! Comments are never a safe place to store information, and self-answers are encouraged here! $\endgroup$
    – MarcoB
    Commented Jun 2, 2020 at 18:21

1 Answer 1

2
$\begingroup$

Thank you to @MarcoB for the solution in the comments! It ended up making the code significantly faster and use far less memory. To give some detail about precisely what I did, let me first reiterate the problem. The function I want to maximize is the determinant of a matrix, where the matrix is defined symbolically and each row has functions of a different variable (for those familiar, it is the Slater determinant for this matrix is wavefunction).

When trying to maximize using NMaximize or FindMaximum, if the matrix were large enough (ie of enough different variables), the process of finding the determinant would use up all of the memory on my PC and cause a crash. This is (I believe) because it was computing the determinant symbolically first and then plugging in numbers to try and maximize is second. However you may know that finding the determinant of a numerical matrix is relatively fast. So ideally NMaximize would first plug in the numbers into the matrix and then compute the determinant.

I dynamically generate my list of variables. I generate two identical lists, var and tvar, where the latter is what I write my Matrix in terms of, and the former is what I use as the variables when I call NMaximize:

var = Flatten[
   Table[{Subscript[x, i], Subscript[y, i]}, {i, 1, numbPart}]];
tvar = Flatten[
   Table[{Subscript[x, i], Subscript[y, i]}, {i, 1, numbPart}]];

Then I generate my matrix where each element is a function of a variable in tvar. Func[] takes 3 inputs [j,x,y], and for me j is labelling the column (in this matrix, each column is a different function and each row has the same functions as the other rows, but with different variables):

waveM = Table[ 
   Func[j, 
    tvar[[2*i - 1]], tvar[[2*i]]]
   , {i, 1, numbPart}, {j, 1, numbPart}];

Now the important part. To make it so that the determinant is computed after numbers are plugged into the variables, I define the alternative determinant function:

detM[var_?(VectorQ[#, NumericQ] &)] := Det[waveM /. {tvar -> var}];

The input to detM is a list of numbers. This makes it so that the numerics are plugged in first and then the determinant of waveM (my matrix) is computed. Then when running NMaximize, I simply do:

AbsoluteTiming[NMaximize[{Re[detM[var]*detMBar[var]]
    }, var]] 

Note that here detM is a function of var, which are also the variables NMaximize is plugging in to my matrix. I am not certain that defining two identical lists of variables was necessary, but this worked for me!

$\endgroup$

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Not the answer you're looking for? Browse other questions tagged or ask your own question.