5
$\begingroup$

I am working on a Mathematica program to construct unitary matrices satisfying specified properties. To complete this construction I need to find where a row of 0's and a column of 0's intersect and place a 1 there. Any ideas on an elegant way to do this?

As an example, consider

{{0,0,-(1/Sqrt[2]),1/Sqrt[2]},{0,0,1/Sqrt[2],1/Sqrt[2]},{0,0,0,0},{0,0,0,0}}

and making it unitary like

{{0,0,-(1/Sqrt[2]),1/Sqrt[2]},{0,0,1/Sqrt[2],1/Sqrt[2]},{1,0,0,0},{0,1,0,0}}
$\endgroup$
1
  • 1
    $\begingroup$ Seems not unique. What is you want, m1 or m2 ? m = {{0, 0, 0, 3}, {0, 0, 0, 0}, {0, 0, 0, 2}, {0, 0, 0, 0}, {0, 0, 0, 0}, {0, 0, 0, 0}}; {(m1 = {{0, 0, 0, 3}, {1, 0, 0, 0}, {0, 0, 0, 2}, {0, 1, 0, 0}, {0, 0, 1, 0}, {0, 0, 0, 0}}) // MatrixForm , (m2 = {{0, 0, 0, 3}, {0, 0, 0, 0}, {0, 0, 0, 2}, {1, 0, 0, 0}, {0, 1, 0, 0}, {0, 0, 1, 0}}) // MatrixForm} $\endgroup$
    – cvgmt
    Commented Nov 5 at 9:47

6 Answers 6

2
$\begingroup$
MatrixForm[mat = {
   {0, 0, -(1/Sqrt[2]), 1/Sqrt[2]},
   {0, 0, 1/Sqrt[2], 1/Sqrt[2]},
   {0, 0, 0, 0},
   {0, 0, 0, 0}}]

MapIndexed[(row[First[#2]] = Union[#1] == {0}) &, mat];
MapIndexed[(col[First[#2]] = Union[#1] == {0}) &, Transpose[mat]];
f[r_, c_] := If[row[r] && col[c], Sow[{r, c}]];
pos = Reap[Outer[f, Sequence @@ Range /@ Dimensions[mat]]][[-1, 1]];
MatrixForm[ReplacePart[mat, pos -> 1]]
{{0, 0, -(1/Sqrt[2]), Sqrt[2]}, 
 {0, 0, 1/Sqrt[2], 1/Sqrt[2]}, 
 {1, 1, 0, 0}, 
 {1, 1, 0, 0}}

not quite the desired result

version 2

MatrixForm[mat = {
   {0, 0, -(1/Sqrt[2]), 1/Sqrt[2]},
   {0, 0, 1/Sqrt[2], 1/Sqrt[2]},
   {0, 0, 0, 0},
   {0, 0, 0, 0}}]

MapIndexed[(row[First[#2]] = Union[#1] == {0}) &, mat];
MapIndexed[(col[First[#2]] = Union[#1] == {0}) &, Transpose[mat]];

f[r_, c_] := If[row[r] && col[c],
   mat = ReplacePart[mat, {r, c} -> 1];
   row[r] = col[c] = False];

Outer[f, Sequence @@ Range /@ Dimensions[mat]];
MatrixForm[mat]
{{0, 0, -(1/Sqrt[2]), Sqrt[2]}, 
 {0, 0, 1/Sqrt[2], 1/Sqrt[2]}, 
 {1, 0, 0, 0}, 
 {0, 1, 0, 0}}

as a function

place[$mat_] := Module[{row, col, f, mat = $mat},

  MapIndexed[(row[First[#2]] = Union[#1] == {0}) &, mat];
  MapIndexed[(col[First[#2]] = Union[#1] == {0}) &, Transpose[mat]];

  f[r_, c_] := If[row[r] && col[c],
    mat = ReplacePart[mat, {r, c} -> 1];
    row[r] = col[c] = False];

  Outer[f, Sequence @@ Range /@ Dimensions[mat]];
  mat]

place[{
  {0, 0, -(1/Sqrt[2]), 1/Sqrt[2]},
  {0, 0, 1/Sqrt[2], 1/Sqrt[2]},
  {0, 0, 0, 0},
  {0, 0, 0, 0}}] // MatrixForm
{{0, 0, -(1/Sqrt[2]), Sqrt[2]}, 
 {0, 0, 1/Sqrt[2], 1/Sqrt[2]}, 
 {1, 0, 0, 0}, 
 {0, 1, 0, 0}}
$\endgroup$
6
  • $\begingroup$ Thank you for your contribution. Both versions have "Set::write: Tag List in {2}[1] is Protected" errors. I'm using Mathematica 11.3 if that matters. Your version 2 output is what I'm looking for. If you can help me getting it to execute on my computer I will be able to study how your code works. $\endgroup$ Commented Nov 5 at 16:30
  • $\begingroup$ Hi, maybe try Clear[f, row, col] before executing the code. $\endgroup$ Commented Nov 5 at 16:42
  • $\begingroup$ That fixed it, thanks. $\endgroup$ Commented Nov 5 at 16:51
  • $\begingroup$ Chris, I am really intrigued by this code. The closer I look at it, the closer it looks like voodoo to me. I'm trying to put this code in to a Module so that I can use it like MakeMatUnitary[mat_]. It is not simply copy and paste! I can set aside the function f[r,c] as a independent function call, but there is something strange about the MapIndexed functions. How can I put this in a module? $\endgroup$ Commented Nov 5 at 17:46
  • $\begingroup$ Hi, I've added a module version. $\endgroup$ Commented Nov 5 at 18:51
4
$\begingroup$
(mat = {{0, 0, -(1/Sqrt[2]), 1/Sqrt[2]}, {0, 0, 1/Sqrt[2], 
     1/Sqrt[2]}, {0, 0, 0, 0}, {0, 0, 0, 0}}) // MatrixForm

$\left( \begin{array}{cccc} 0 & 0 & -\frac{1}{\sqrt{2}} & \frac{1}{\sqrt{2}} \\ 0 & 0 & \frac{1}{\sqrt{2}} & \frac{1}{\sqrt{2}} \\ 0 & 0 & 0 & 0 \\ 0 & 0 & 0 & 0 \\ \end{array} \right)$


umat[mat_?MatrixQ] := Module[{
   tr = DiscreteDelta @@@ mat
   , tc = DiscreteDelta @@@ Transpose@mat, pr, pc, ml},
  pr = Flatten@Position[tr, 1];
  pc = Flatten@Position[tc, 1];
  ml = Min@(Length /@ {pr, pc});
  idx = Thread[{pr[[1 ;; ml]], pc[[1 ;; ml]]}];
  SubsetMap[# + 1 &, mat, idx]
  ]

umat[mat] // MatrixForm

$\left( \begin{array}{cccc} 0 & 0 & -\frac{1}{\sqrt{2}} & \frac{1}{\sqrt{2}} \\ 0 & 0 & \frac{1}{\sqrt{2}} & \frac{1}{\sqrt{2}} \\ 1 & 0 & 0 & 0 \\ 0 & 1 & 0 & 0 \\ \end{array} \right)$

$\endgroup$
3
  • $\begingroup$ Thank you for your contribution! I am however using Mathematica 11.3 which does not know SubsetMap. Can you please provide a definition or substitute for the earlier version? $\endgroup$ Commented Nov 5 at 16:39
  • 1
    $\begingroup$ @PhillipDukes You can use MapAt instead of SubsetMap. $\endgroup$ Commented Nov 5 at 19:13
  • $\begingroup$ I'll try it. Thank you. $\endgroup$ Commented Nov 5 at 19:31
3
$\begingroup$
mat = {
       {0, 0, -(1/Sqrt[2]), 1/Sqrt[2]},
       {0, 0, 1/Sqrt[2], 1/Sqrt[2]},
       {0, 0, 0, 0}, 
       {0, 0, 0, 0}
      };

TeXForm@mat

$\left( \begin{array}{cccc} 0 & 0 & -\frac{1}{\sqrt{2}} & \frac{1}{\sqrt{2}} \\ 0 & 0 & \frac{1}{\sqrt{2}} & \frac{1}{\sqrt{2}} \\ 0 & 0 & 0 & 0 \\ 0 & 0 & 0 & 0 \\ \end{array} \right)$


I was inquiring about the possibilities you have for constructing the unitary matrix because it’s clear that the answer is not unique, given, of course, what you're asking for—that is, to keep adding ones at the intersections between rows and columns of zeros. My attempt is as follows:

Umatrices[mat_] := Module[{zeroRows, zeroCols, positions, allSubsets, matrices},
  matrices = {};
  zeroRows = Flatten[Position[Total[Abs[mat], {2}], 0]];
  zeroCols = Flatten[Position[Total[Abs[mat], {1}], 0]];
  positions = Tuples[{zeroRows, zeroCols}];
  allSubsets = Subsets[positions];
  Do[Module[{result = mat, det}, 
    Scan[(result[[#[[1]], #[[2]]]] = 1) &, subset];
    det = Det[result];
    If[det != 0, AppendTo[matrices, result]]], {subset, allSubsets}];
  Pick[#, UnitaryMatrixQ /@ #] &@matrices];

Testing Umatrices:

Row[Map[MatrixForm]@Umatrices[mat], " "] // TeXForm

$\left( \begin{array}{cccc} 0 & 0 & -\frac{1}{\sqrt{2}} & \frac{1}{\sqrt{2}} \\ 0 & 0 & \frac{1}{\sqrt{2}} & \frac{1}{\sqrt{2}} \\ 1 & 0 & 0 & 0 \\ 0 & 1 & 0 & 0 \\ \end{array} \right)\, \left( \begin{array}{cccc} 0 & 0 & -\frac{1}{\sqrt{2}} & \frac{1}{\sqrt{2}} \\ 0 & 0 & \frac{1}{\sqrt{2}} & \frac{1}{\sqrt{2}} \\ 0 & 1 & 0 & 0 \\ 1 & 0 & 0 & 0 \\ \end{array} \right)$

In this way, you obtain the possible unitary matrices that result from adding ones at the intersections between rows and columns of zeros. You then select the one that best matches your requirements; for instance, the first matrix in the output of Umatrices is the one you provided as an example.

$\endgroup$
1
  • 1
    $\begingroup$ Yes, there are many ways that a "partial unitary" can be made unitary. Your contribution gives results that provide determinates that are -1 and +1, which is nice. $\endgroup$ Commented Nov 5 at 18:04
2
$\begingroup$
mat = {{0, 0, 0}, {0, 2, 2}, {0, 0, 0}}

enter image description here

We want a 1 to be placed where the norm of the row and column is 0. In other words, the row norm + column norm is 0. We can then use Unitize to replace any numerical values other and 0 with 1, and subtract 1 from it to get a matrix that is 1 where the row and column norm are 0, and 0 everywhere else. We then add this to the original mat:

mat +=  1 - 
  Unitize@Outer[Plus, Norm /@ mat, Norm /@ (mat\[Transpose])]

enter image description here

Note this matrix is not unitary, so I'm guessing that this is just a part of a bigger algorithm for making unitary matrices.

$\endgroup$
5
  • $\begingroup$ Thank you, your idea is instructive but not applicable to my application. I've edited to make my problem clearer. $\endgroup$ Commented Nov 5 at 4:01
  • 3
    $\begingroup$ I think you might need to reword your question because your target matrix is no longer "find where a row of 0's and a column of 0's intersect and place a 1 there" in relation to your starting matrix. $$ $$ Do you want to find where columns and rows intersect iteratively by row, and replace the first occurrence of a zero column/zero row with a 1 and then move on to checking the next row (instead of finding and replacing them all at once)? $\endgroup$
    – ydd
    Commented Nov 5 at 4:34
  • 1
    $\begingroup$ @PhillipDukes If you add a 1 in position (3, 2) and another in position (4, 1), it is also a unitary matrix. My question is, why not that option? $\endgroup$ Commented Nov 5 at 5:06
  • $\begingroup$ @E.Chan-López Yes, generally there would be many ways strategically placed 1's would complete a unitary matrix. Making it unitary is really all I require. $\endgroup$ Commented Nov 5 at 16:10
  • $\begingroup$ @ydd Your proposed method of "find where columns and rows intersect iteratively by row, and replace the first occurrence of a zero column/zero row with a 1 and then move on to checking the next row" would indeed work. $\endgroup$ Commented Nov 5 at 16:13
2
$\begingroup$

Assuming we "mark" one intersection at a time recursively, we could do something like this:

MarkFirstIntersection[matrix_?MatrixQ] :=
  With[
    {intersection = Flatten[FirstPosition[0] /@ {Total[matrix, {2}], Total[matrix, {1}]}]},
    If[FreeQ[intersection, _Missing], ReplacePart[matrix, intersection -> 1], matrix]];

list = {{0, 0, -(1/Sqrt[2]), 2/Sqrt[2]}, 
        {0, 0, 1/Sqrt[2], 1/Sqrt[2]}, 
        {0, 0, 0, 0}, 
        {0, 0, 0, 0}};

FixedPoint[MarkFirstIntersection, list]
(* {{0, 0, -(1/Sqrt[2]), Sqrt[2]}, 
    {0, 0, 1/Sqrt[2], 1/Sqrt[2]}, 
    {1, 0, 0, 0}, 
    {0, 1, 0, 0}} *)
$\endgroup$
2
$\begingroup$

This method is more like brute force:

(mat = {{0, 0, -(1/Sqrt[2]), 1/Sqrt[2]}, {0, 0, 1/Sqrt[2], 
     1/Sqrt[2]}, {0,0,0, 0}, {0,0, 0, 0}}) // MatrixForm

Clear[unitize]
unitize[m_] := m + SparseArray[
    With[{n = Count[m, ConstantArray[0, Length[m]]]},
          Transpose[{OrderingBy[m, Max@*Abs][[;;n]],
                     OrderingBy[Transpose[m], Max@*Abs][[;;n]]}]
    ] -> 1, Dimensions[m]]
   
unitize[mat] // UnitaryMatrixQ   (* True *)

An explanation of the various phrases --

Count[m, ConstantArray[0, Length[m]]] counts the number of zero rows in the matrix $m$. This count, which is 2 in the example, is stored the variable $n$.

OrderingBy[m, Max@*Abs][[;;n] finds the row numbers of the first $n$ zero rows. In the example, this expression returns {3,4}, since rows 3 and 4 are all zeroes.

OrderingBy[Transpose[m], Max@*Abs][[;;n]] finds the column numbers of the first $n$ zero columns. In the example, this expression returns {1,2}, since columns 1 and 2 are all zeroes.

The With expression returns the transpose of {{3,4}, {1,2}}, which gives the subscripts of the matrix elements that must change to ones.

SparseArray[{{3,1}, {4,2}} -> 1, Dimensions[m] gives the matrix $S$ with the same dimensions as $m$, and having element $S_{3\,1} = 1$ and element $S_{4\,2} = 1$ and zeros elsewhere.

Adding the sparse array to the original array gives the completed unitary matrix.

$\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.