0
$\begingroup$

In Mathematica, often an expression involving matrices will encounter dimension mismatch errors, like we are multiplying a 3x2 matrix to a 3x4 matrix. Below we define a new symbol Dim, which can be passed through your algorithm as a fake parameter to detect errors.

Dim /: Dot[Dim[{x_, y_}], z_] /;
   MatrixQ[z] :=
  (checkEq[y, Dimensions[z][[1]]];
   Dim[{x, Dimensions[z][[2]]}]);

This method can handle most matrix operations, but failed on Table, which seems quite special. In fact, I failed to pattern match with Table by writing:

Dim /: Times[Dim[{x_, y_}], Table[z_]] := Dim[x, y];(*incorrect, just for syntax*)
Dim /: Times[Table[z_], Dim[{x_, y_}]] := Dim[x, y];

The expected result should be:

Dim[{3, 2}] Table[Sin[i + j], {i, 3}, {j, 2}] == Dim[{3, 2}]

But now Dim is multiplied over every element of table and it returns:

{{Dim[{3, 2}] Sin[2], Dim[{3, 2}] Sin[3]}, {Dim[{3, 2}] Sin[3], Dim[{3, 2}] Sin[4]}, {Dim[{3, 2}] Sin[4], Dim[{3, 2}] Sin[5]}} == Dim[{3, 2}]

Full code:

Clear[Dim];
checkEq =
  Function[{x, y},
   If[x != y, Print[ToString[x] <> "!=" <> ToString[y]]; Abort[]]];
Dim /: Dimensions[Dim[x_]] := x;
Dim /: MatrixQ[Dim[_]] := True;
Dim /: Dot[Dim[{x_, y_}], z_] /;
   MatrixQ[z] :=
  (checkEq[y, Dimensions[z][[1]]];
   Dim[{x, Dimensions[z][[2]]}]);
Dim /: Dot[z_, Dim[{x_, y_}]] /;
   MatrixQ[z] :=
  (checkEq[Dimensions[z][[2]], x];
   Dim[{Dimensions[z][[1]], y}]);
Dim /: Times[z_, Dim[{x_, y_}]] /;
   MatrixQ[z] :=
  (checkEq[Dimensions[z], {x, y}]; Dim[{x, y}]);
Dim /: Times[Dim[{x_, y_}], z_] /;
   MatrixQ[z] :=
  (checkEq[Dimensions[z], {x, y}]; Dim[{x, y}]);
Dim /: Plus[z_, Dim[{x_, y_}]] /;
   MatrixQ[z] :=
  (checkEq[Dimensions[z], {x, y}]; Dim[{x, y}]);
(*Dim/:Dot[Dim[{x_,y_}],Dim[{z_,w_}]]:=(checkEq[y,z];Dim[{x,w}]);
Dim/:Times[Dim[{x_,y_}],Dim[{z_,w_}]]:=(checkEq[x,z];checkEq[y,w];Dim[{x,y}]);\
Dim/:Plus[Dim[{x_,y_}],Dim[{z_,w_}]]:=(checkEq[x,z];checkEq[y,w];Dim[{x,y}]);*)
Dim /: Times[x_, Dim[{y_, z_}]] /; NumberQ[x] := Dim[{y, z}];

(*Below are tests that should return true.*)
MatrixQ[Dim[{2, 3}]]
Dimensions@Dim[{1, 2}] == {1, 2}
Dim[{3, 2}].Dim[{2, 4}] == Dim[{3, 4}]
Dim[{3, 2}].RandomReal[1, {2, 4}] == Dim[{3, 4}]
RandomReal[1, {2, 4}].Dim[{4, 3}] == Dim[{2, 3}]
Dim[{3, 2}] Dim[{3, 2}] == Dim[{3, 2}]
2 Dim[{3, 2}] == Dim[{3, 2}]
Dim[{3, 2}] - Dim[{3, 2}] == Dim[{3, 2}]

(*Below are tests that should raise errors.*)
Dim[{3, 2}] - Dim[{2, 4}]
Dim[{3, 2}] Dim[{2, 4}]
Dim[{5, 3}].Dim[{2, 4}]
$\endgroup$
1
  • $\begingroup$ I'm not sure I understand what underlying problem you're trying to solve here, let alone why this particular approach is being used... That said, Table[z_] expressions in code seem to be where your problem is... If you're trying to match a 'list of lists' that can be done; if you're trying to match an expression with the Head 'Table', that too can be done, although evaluation control will probably be needed. Advice: do some prototyping with MatchQ. This will force you to make explicit what you're trying to match, and will enable you to identify what will work. $\endgroup$ May 27, 2013 at 21:59

1 Answer 1

2
$\begingroup$

I believe you have an evaluation order problem. I suspect that you are unaware of the order of evaluation regarding UpValues definitions. Allow me to give a few illustrations.

I'll make a generic UpValue rule using UpSetDelayed:

_[___, up[1], ___] ^:= "one"

Arguments are evaluated before UpValues rules are triggered, unless the function has a Hold attribute such as HoldAll:

List[Print[1 + 1], up[1], Print[2 + 2]]

2

4

"one"

For this reason your Table is evaluated before your Dim rule is checked. Perhaps the most direct way around this is to use Unevaluated for every instance of Table. Using a simplified rule:

dim /: Times[dim[], _Table] := "Table found"

Times[dim[], Table[x[n], {n, 5}]] (* this doesn't match *)
{dim[] x[1], dim[] x[2], dim[] x[3], dim[] x[4], dim[] x[5]}
Times[dim[], Unevaluated @ Table[x[n], {n, 5}]] (* this does *)
"Table found"

Of course this isn't very convenient.

I must admit I don't understand how you are intending to use Dims and why you don't merely check the data with Dimensions. If you explain that perhaps I can suggest a different implementation.

$\endgroup$
1
  • $\begingroup$ +1, for taking the time to figure out something helpful to say. $\endgroup$
    – Michael E2
    Jun 8, 2013 at 18:06

Your Answer

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

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