2
$\begingroup$

I'm doing a small project and I've encountered a problem while using Mathematica. I should mention that I'm kinda new to this software, so maybe it's just something I haven't grasped yet.

Anyway, I have a 9x9 matrix P and a 9D vector q0Dot.

Evaluating

projected = P.q0Dot

ended up taking a very long computational time. My laptop is quite powerful, but after I waited for like 10-15 minutes, I aborted the evaluation. I was kinda expecting slow evaluation, since the computational time of products is not linear.

So I reverted to calculate one element at a time, like:

a = P[[1, All]] . q0Dot

and so on (just one is enough for the sake of this post).

Now, the problem I've encountered is that a (and other elements of the result vector) is not a 9D vector, as it should be. is not a scalar.

I don't think it's related to the fact that Mathematica doesn't treat lists as row or column vectors. Correct me if I'm wrong.

To show what happened:

Dimensions[P]
Dimensions[q0Dot]
Dimensions[a]
{9, 9}
{9}
{8}

Note that almost every element of P cointains sine and cosine expressions and is fairly complicated.

So I was wondering what the problem is and made a couple of theories, but have found out nothing so far.

  • maybe one element (maybe the last one) was null, so it got ignored at the end, but that's not the case;
  • maybe the computational time is exceeding the maximum allowed and it stops computing without a warning, but I don't really know how to check that;
  • maybe there's some Mathematica behaviour I don't know about

I'd be really really grateful if any of you could point me out at the solution!

EDIT: I'm adding my code, which I didn't do at first because I thought it would have been too detailed for the post itself. Also, it's making use of an external library, which I'm adding too.
My code + library - Google Drive

Now: it's an Inverse Kinematics problem, dealing with an industrial robotic arm. The matrix P (along with the others) contains only sines and cosines, but quite an amount, since it has 9 variables.

Unless you're doing something considerably more complicated than just having a dot product of integers or Reals, It should be super fast to calculate

In fact, I've tried that and didn't encounter any problems, as morbo stated.

Now I'm a bit confused. P . q0Dot should be a 9D vector, since it's a 9x9 matrix multiplied by a 9D (column) vector. As all of you stated, multiplying one row of P, which is a 9D (row) vector, by q0Dot should result in a scalar.
Well, blame my stupidty for this one, since I made a gaffe (which I'm going to highlight): maybe I didn't focus enough, since this should be obvious, duh.
So why isn't it? Now I'm concerned about two things: one, is why that doesn't result in a scalar; two, what kind of computation Mathematica did to achieve that 8D result. Which may be the same problem in my case.

I think this is everything you asked for, to improve my question. If not, I'll surely add some more!

$\endgroup$

closed as off-topic by Daniel Lichtblau, LCarvalho, yohbs, José Antonio Díaz Navas, bbgodfrey Mar 24 at 14:18

This question appears to be off-topic. The users who voted to close gave this specific reason:

  • "This question cannot be answered without additional information. Questions on problems in code must describe the specific problem and include valid code to reproduce it. Any data used for programming examples should be embedded in the question or code to generate the (fake) data must be included." – Daniel Lichtblau, LCarvalho, yohbs, José Antonio Díaz Navas
If this question can be reworded to fit the rules in the help center, please edit the question.

  • 4
    $\begingroup$ If you can show the actual matrices, we could help better. A dot product ought to execute extremely fast for a 9 x 9 problem. $\endgroup$ – MikeY Mar 16 at 21:59
  • $\begingroup$ Also, you are right that Mathematica's handling of "vectors" is quirky. In my own work, I write my vectors as (for example) 9 x 1 matrices in order to ensure Mathematica is doing the exact matrix function I want. $\endgroup$ – MikeY Mar 16 at 22:03
  • $\begingroup$ With the dimensions you show, p[[1, All]].q should be a scalar, not a 9D vector. p[[1,All]] is the first row of p. Taking the dot product of a 9D row and the 9D q gives a scalar quantity. $\endgroup$ – bill s Mar 16 at 22:18
  • $\begingroup$ As a test, try: Do[Print[n, " ", Timing[projected = Take[P, {1, n}, {1, n}].Take[q0Dot, n]][[1]]], {n, 9}] to see the increase in timing and where it gets bogged down. $\endgroup$ – Somos Mar 16 at 23:48
  • 2
    $\begingroup$ The first mistake in your notebook is that you use sin[theta] instead of Sin[theta]. Symbols in Mathematica are case sensitive. $\endgroup$ – bill s Mar 17 at 15:33
1
$\begingroup$

Here's a fix

Although I agree with @MichaelE2 that inverting a symbolic matrix is asking for trouble!

First, in your W matrix, write 1/2 instead of 0.5 and some odd numerical behaviors downstream are averted. When it is time to simplify things, the algorithms can do a little better.

Second, it doesn't hurt to keep simplifying your code as you go, so for example using FullSimplify early and simplifying JRNonInv helps keep the bloat down when you invert the matrix.

JTransposed = Transpose[J];
JSimplified = J // FullSimplify;  (* was just a simplify here *)
JTSimplified = Transpose@JSimplified ;   (* no need to simplify JTransposed *)  

JRNonInv = (JSimplified.WInverse.JTSimplified) // Simplify; (* added a simplify *)

To your point on the code not working, if you replace q0Dot with a "proper" vector...

qvec = Transpose@{q0Dot};
qvec // Dimensions

{9,1}

Your code now works, at least in creating the correct sized matrices.

Dimensions[P]
Dimensions[qvec]
Dimensions[a]

{9, 9}

{9, 1}

{1}

You can also skip the intermediate variables and go

 projected = P.qvec
 Dimensions@projected

{9,1}

I firmly believe how Mathematica allows you to define a vector as a simple list when dealing with linear algebra is the Devil's work, and has caused many a heartbreak for me.

EDIT

@ slim71, here's an example of what I mean. Define a simple "vector"

vsimp = {1,1,1};
vsimp//TeXForm

$$ \{1,1,1\} $$

If you just do MatrixForm it looks like a vector, but it's not really one. Now make a full-blown column vector, which is a $3 \times 1$ matrix.

vector = Transpose@{{1, 1, 1}};
vector//TeXForm

$$ \left( \begin{array}{c} 1 \\ 1 \\ 1 \\ \end{array} \right) $$

Create a simple matrix to play with

mat = Table[i,{i,3},{3}];
mat//TeXForm

$$ \left( \begin{array}{ccc} 1 & 1 & 1 \\ 2 & 2 & 2 \\ 3 & 3 & 3 \\ \end{array} \right) $$

Now in theory we can do mat.vector but not vector.mat since the dimensions would be incompatible in the second case.

mat.vector

$$ \left( \begin{array}{c} 3 \\ 6 \\ 9 \\ \end{array} \right) $$

The command vector.mat fails, complaining about incompatible shapes. Give it a try.

In the other case, we can execute both vsimp.mat and mat.vsimp, depending on Mathematica to interpret vsimp either as a row vector or column vector given the context. You can easily get burned with a mistake here. Writing the vector as a matrix helps to prevent these mistakes, and it appears to fix the error in your code, which ought to work correctly. Not sure why it doesn't, other than that you've got a monstrous term for the inverse of the matrix.

Finally, you can't just do Transpose@vsimp since you transpose matrices, and vsimp is just a list.

Transpose@vsimple
(* Transpose::nmtx: The first two levels of {1,1,1} cannot be transposed. *)

Instead you are constructing a matrix to represent your column vector.

$\endgroup$
  • $\begingroup$ I haven't seen the format Transpose@{q0Dot} before, is it the same of q0Dot // Transpose? If not, could you please point out some reference? I've tried searching it but I don't know if that use has a "name" itself, so to speak.. <br> I agree with simplifying the code as I go: I guess FullSimplify is better than Simplify in the end, so I might as well use that. What I didn't know was this behaviour with 1/2 instead of 0.5 and similar! Thanks for the suggestion! <br> Finally, I don't quite like Mathematica vector usage myself, since I'm used to other languages.. Gonna try! $\endgroup$ – slim71 Mar 17 at 20:55
  • $\begingroup$ OK, tried and it works as expected for now! I had to avoid some FullSimplifys and Simplifys because the computations were going on for too long (it even reported "Computational time exceeded" or something like that, I don't remember the actual text), but so far this is the solution I've searched for! $\endgroup$ – slim71 Mar 17 at 22:01
  • $\begingroup$ too many comments maybe, sorry about that... But @MikeY A suggestion: should I do the Transpose of a list every time I want to use it as a column vector like in this occasion? $\endgroup$ – slim71 Mar 17 at 22:13
1
$\begingroup$

It'd be great if you posted/would show your code and matrices to see exactly what you're doing. It's a good habit to post your attempt (and your data) for us to play with.

Unless you're doing something considerably more complicated than just having a dot product of integers or Reals, It should be super fast to calculate,

matA = Table[RandomReal[], {i, 1, 9}, {j, 1, 9}];
vectorB = Table[RandomReal[], {i, 1, 9}];
vectorC = MatrixForm[Dot[matA, vectorB]]

It took me 0.000014 to calculate...even a 20k x 20k matrix took less than a second.

Your second bit of code is giving you a scalar because you are doing a scalar product of the first column of your 9x9 matrix with a 9 element vector, thus giving you a scalar product.

With Table you can populate the scalar products into the solution:

test = Table[matA[[i, All]] . matB, {i, 1, 9}] // MatrixForm

This gives the same result, which can be verified so:

vectorC == test

(*True*)

So, I'm guessing you're code is a bit wonky. Please give your working (or none working code) and I will update accordingly.

Addendum

I just saw that you're also dealing with some trig functions, without knowing which they are, I made a completely symbolic example

params = {x -> RandomReal[], y -> RandomReal[], z -> RandomReal[]};
AbsoluteTiming[
 var = {Cos[x], Cos[x] + Sin[y], Tanh[z], ArcSin[x], E^z, 
   ArcSinh[x] Cos[y]};
 smatA = Table[var[[RandomInteger[{1, 6}]]], {i, 1, 9}, {j, 1, 9}];
 svectorB = Table[var[[RandomInteger[{1, 6}]]], {i, 1, 9}];
 svectorC = MatrixForm[Dot[smatA, svectorB]];
 test = Table[smatA[[i, All]].svectorB, {i, 1, 9}] // MatrixForm;]
svectorC == test /. params

(*{0.000805, Null}*)
(*True*)

This also took via AbsoluteTiming[] 0.000805 seconds to generate randomly all equations, params, and solve.

; If you didn't know is shorthand for no output.

$\endgroup$
  • $\begingroup$ The code in your addendum is incorrect. It never uses smatA and svevtorB, so the timing is suspect. $\endgroup$ – m_goldberg Mar 17 at 3:05
  • $\begingroup$ Ah! you're right, my apologies, it was a lazy copy and paste. I've added new codes. and then replaced all x y z values...to a total of still less than a second in time. $\endgroup$ – morbo Mar 17 at 7:58
  • $\begingroup$ Thanks for the answer! I'm going to add my code, so bear a moment please.. I'll add some other consideration there, since I think are helpful (I knew about the ;) $\endgroup$ – slim71 Mar 17 at 13:28
  • 1
    $\begingroup$ MatrixForm should not be used this way. It is a common source of problems for new users. See this Q&A, para. 8 of this answer to the pitfall question, and this reference. $\endgroup$ – Michael E2 Mar 17 at 13:41
1
$\begingroup$

Edit

Since morbo has corrected his code, I no longer have any criticism of it to make, and simply offer this as alternative way of coding which is more concise and a little faster.

AbsoluteTiming[
  exprs = {Cos[x], Cos[x] + Sin[y], Tanh[z], ArcSin[x], E^z, ArcSinh[x] Cos[y]}; 
  matA = RandomChoice[exprs, {9, 9}];
  vecB = RandomChoice[exprs, 9];
  dot1 = matA.vecB;
  dot2 = Table[matA[[i]].vecB, {i, 9}];
  dot1 == dot2]

{0.000688, True}

$\endgroup$
  • $\begingroup$ Well, one could have waited for me to wake up and correct my code, but there's no reason to attack my quality and style versus your own, or was there a point that I could learn besides you could gain 0.00005 seconds? $\endgroup$ – morbo Mar 17 at 8:10
  • 1
    $\begingroup$ @morbo. I did not mean to criticize your style, but only of your errors. Since you have corrected your code, I have edited this answer and removed the criticism. $\endgroup$ – m_goldberg Mar 17 at 12:30
  • 2
    $\begingroup$ @morbo, m_goldberg: While I appreciate helpful attitude motivating your answers, my criticism would be that neither actually post answers the question. Your special case does not reproduce the problem of the OP's special case. The OP seems to know already how it should work, and there is nothing wrong with the OP's syntax and usage. Now, I don't believe the OP has accurately presented the case, esp. the Dimensions[] output given the descriptions of the variables. The OP needs to present the full code for this question to be answered. $\endgroup$ – Michael E2 Mar 17 at 13:33
1
$\begingroup$

Note:

Head[P[[1]].q0Dot]
(*  Plus  *)

And:

ecnt = 0;
Replace[P[[1]].q0Dot, e_ :> ToString[Head[e]][++ecnt], 1]
(*
"Times"[1] + "Times"[2] + "Times"[3] + "Times"[4] + "Times"[5] + 
 "Times"[6] + "Times"[7] + "Times"[8]
*)

What's going on is that Dimensions[] is returning the dimensions of the expression with the head Plus, which expression consists of 8 terms being added. Dimensions works with any head, not just List.

ArrayQ[P]
ArrayQ[q0Dot]
ArrayQ[a]
(*
  True
  True
  False
*)

Finally consider:

ByteCount[P] // AbsoluteTiming
(*  {10.5235, 19394763312}  *)

That's 19GB, which is more than my system can handle effectively. It also takes 10.5 sec for a simple operation. Currently, many of the subexpressions appear to be shared (since the MemoryInUse is a couple hundred MB). Almost any operation that causes P to be traversed (such as Dot) would take a long time, and if subexpressions need copying, it would require swapping. The kernel might even run out of memory and crash.

Maybe if you have 64+GB of RAM, things will work better. Otherwise, see if you can deal more effectively with P. One culprit is taking the Inverse[] of a symbolic matrix. It's unlikely that one would be able to analyze such large symbolic expressions, so if you're ultimately going to do things numerically, then wait to construct P when all parameters are numeric. (Then you'll probably want to use LinearSolve[] instead of Inverse[].) It should be much, much faster.

$\endgroup$
  • $\begingroup$ So you're saying (if I understand it correctly) that Dimensions takes account of the actual format of the object, and this is the reason a results in a 8D object? Also, unfortunately I kinda need the Inverse[] of the symbolic matrix W, otherwise I would have done it numerically as you suggested.. $\endgroup$ – slim71 Mar 17 at 20:41
  • $\begingroup$ @slim71 I think you've got it right. Dimensions[h[x,y,z]] gives {3} and Dimensions[h[h[1,2],h[3,4],h[5,6]]] gives {3, 2} (provided h does not evaluate to something else). But it has to be a rectangular array with the same head h: Both Dimensions[h[h[1, 2], h[3, 4], g[5, 6]]] and Dimensions[h[h[1, 2], h[3, 4], h[5, 6, 7]]] yield {3} So in fact, your a is a scalar, which I should have emphasized in my $\endgroup$ – Michael E2 Mar 17 at 20:53

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