6
$\begingroup$

I am given a list of square matrices (with non numeric entries but abstract symbols which are assumed to take real values) and I want to write a function that returns True if the following condition is satisfied:

  • All rows and columns of each matrix have at most one nonzero element.

In other words, a row or column can either have all elements zero, or all but one. Otherwise, the function should return False.

I could of course write a triple loop that goes through each matrix in the list, then each row and column, and counts non-zero elements, but I am wondering what would be the most clever and efficient way to do it.

Note that even if only one matrix in that list has a row or column with more than one non-zero elements, then there would be no need to check for the rest.

$\endgroup$

2 Answers 2

5
$\begingroup$
ClearAll[f]
f[mat_?(MatrixQ[#, NumericQ]&)] :=
 FreeQ[
  Through[{Total, Map[Total]} @ Unitize[mat]], 
  _?(# > 1 &)
 ]

The code uses Unitize to turn any non-zero number into 1. Total sums the columns of the unitized matrix; Map[Total] sums the rows. The sums are therefore counts of non-zero elements in each column vs. row. FreeQ checks whether any of those counts is higher than 1, which indicates that there was more than one non-zero element in that column vs. row.

Let's make some matrices to test:

SeedRandom[4563]
MatrixForm /@ 
 (list = 
   RandomChoice[{200, 10, 10, 10} -> {0, 1, 2, 3}, {10, 5, 5}])

random matrices generated for test

and apply our test function f to each:

f /@ list

(* Out: {False, True, False, False, False, False, False, True, False, True} *)

Following the comment and edit mentioning the presence of symbols rather than numbers, here is an alternative function:

ClearAll[fSym]
fSym[mat_] :=
 FreeQ[
   Through[{Total, Map[Total]}@mat],
   _Plus,
   -1
 ]

Same test, but with symbolic variables:

SeedRandom[4563]
MatrixForm /@ (listSym = 
   RandomChoice[{200, 10, 10, 10} -> {0, a, b, c}, {10, 5, 5}])

list of matrices with symbols instead of numbers

fSym /@ listSym

(* Out: {False, True, False, False, False, False, False, True, False, True} *)
$\endgroup$
6
  • $\begingroup$ Thank you for your answer. However, there is the following issue. My matrices do not have numeric elements but abstract symbols (that take real values). E.g. I would have something like {{a,0,0},{b,c,0},{0,0,0}}. In this case, your code does not work $\endgroup$
    – AG1123
    Commented Dec 4, 2020 at 6:52
  • 1
    $\begingroup$ @AG1123 I added an edit to the answer to take that into account. $\endgroup$
    – MarcoB
    Commented Dec 4, 2020 at 7:04
  • $\begingroup$ Great, thanks! That works as needed $\endgroup$
    – AG1123
    Commented Dec 4, 2020 at 7:17
  • $\begingroup$ How would I modify the code if I wanted the property to hold only for rows (or columns) instead of both? Thanks @MarcoB $\endgroup$
    – AG1123
    Commented Dec 6, 2020 at 5:50
  • 1
    $\begingroup$ @AG1123 As mentioned in the description, Total sums the columns of the matrix; Map[Total] sums the rows. So instead of Through[{Total, Map[Total]}@mat] you can just have one of those only: e.g. Total @ mat will do the check over the columns; whereas Total /@ mat will do it over the rows (note the difference between @ and /@). $\endgroup$
    – MarcoB
    Commented Dec 6, 2020 at 20:43
4
$\begingroup$
m = {{0, a, 0}, {b, 0, 0}, {0, 0, c}};
f[m_] := AllTrue[
  Count[#, 0] & /@ Join[m, Transpose[m]], # >= Length@m - 1 &]

True

Original

f[m_] := Nor @@ (AllTrue[#, EqualTo[0]] & /@ Join[m, Transpose[m]]);
m = {{0, 0, 1}, {1, 0, 1}, {2, 0, 0}};
n = {{1, 1, 1}, {0, 0, 1}, {0, 1, 0}};
f[m]
f[n]

False

True

$\endgroup$
3
  • $\begingroup$ Thanks but your code does not return the correct result. Both example matrices should return False, since they both have a row or column with more than one non zero elements. $\endgroup$
    – AG1123
    Commented Dec 4, 2020 at 6:49
  • 1
    $\begingroup$ @AG1123 Thanks! I have fixed it. $\endgroup$
    – cvgmt
    Commented Dec 4, 2020 at 9:11
  • $\begingroup$ Thanks! I like how concise your solution is, even though I don't really understand it. $\endgroup$
    – AG1123
    Commented Dec 4, 2020 at 10:33

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.