7

How to quickly determine if a square logical matrix is a permutation matrix? For instance,

enter image description here

is not a permutation matrix since the 3rd row have 2 entries 1.

PS: A permutation matrix is a square binary matrix that has exactly one entry 1 in each row and each column and 0s elsewhere.

I define a logical matrix like

numpy.array([(0,1,0,0), (0,0,1,0), (0,1,1,0), (1,0,0,1)])

Here is my source code:

#!/usr/bin/env python
import numpy as np

### two test cases
M1 = np.array([
    (0, 1, 0, 0),
    (0, 0, 1, 0),
    (0, 1, 1, 0),
    (1, 0, 0, 1)]);

M2 = np.array([
    (0, 1, 0, 0),
    (0, 0, 1, 0),
    (1, 0, 0, 0),
    (0, 0, 0, 1)]);

### fuction 
def is_perm_matrix(M) :
    for sumRow in np.sum(M, axis=1) :
        if sumRow != 1 :
            return False
    for sumCol in np.sum(M, axis=0) :
        if sumCol != 1 :
            return False
    return True

### print the result
print is_perm_matrix(M1) #False
print is_perm_matrix(M2) #True

Is there any better implementation?

SparkAndShine
  • 17,001
  • 22
  • 90
  • 134
  • 5
    How is your matrix defined? What have you done so far? – d6bels Mar 06 '15 at 09:36
  • 2
    what do you mean by quickly do you mean it in terms of big O or something else ? – advocateofnone Mar 06 '15 at 09:38
  • 2
    Are you storing a matrix as a list of lists? Can you guarantee that the matrix only contains the integers 0 and 1, or does the code need to check that? Can you post some code to show us what you've tried? – PM 2Ring Mar 06 '15 at 09:42
  • @PM 2Ring, the input matrix is "a square logical matrix". – SparkAndShine Mar 06 '15 at 09:44
  • 2
    @QiankunSU "a square logical matrix" is not a Python type. – Peter Wood Mar 06 '15 at 09:45
  • 1
    What Peter Wood said. Also, saying that it's a _logical_ matrix implies that its elements are Booleans, i.e., `True` and `False`, but your example matrix contains _integers_. – PM 2Ring Mar 06 '15 at 09:49
  • @PeterWood define a logical matrix like numpy.array([(0,1,0,0), (0,0,1,0), (0,1,1,0), (1,0,0,1)]) – SparkAndShine Mar 06 '15 at 09:50
  • @QiankunSU Put that in the question and show what you've tried. You got an extremely generous answer to [this similar question](http://stackoverflow.com/questions/28816627/how-to-find-linearly-independent-rows-from-a-matrix), which you haven't accepted. – Peter Wood Mar 06 '15 at 09:52

3 Answers3

4

What about this:

def is_permuation_matrix(x):
    x = np.asanyarray(x)
    return (x.ndim == 2 and x.shape[0] == x.shape[1] and
            (x.sum(axis=0) == 1).all() and 
            (x.sum(axis=1) == 1).all() and
            ((x == 1) | (x == 0)).all())

Quick test:

In [37]: is_permuation_matrix(np.eye(3))
Out[37]: True

In [38]: is_permuation_matrix([[0,1],[2,0]])
Out[38]: False

In [39]: is_permuation_matrix([[0,1],[1,0]])
Out[39]: True

In [41]: is_permuation_matrix([[0,1,0],[0,0,1],[1,0,0]])
Out[41]: True

In [42]: is_permuation_matrix([[0,1,0],[0,0,1],[1,0,1]])
Out[42]: False

In [43]: is_permuation_matrix([[0,1,0],[0,0,1]])
Out[43]: False
Bas Swinckels
  • 18,095
  • 3
  • 45
  • 62
4

Here's a simple non-numpy solution that assumes that the matrix is a list of lists and that it only contains integers 0 or 1. It also functions correctly if the matrix contains Booleans.

def is_perm_matrix(m):
    #Check rows
    if all(sum(row) == 1 for row in m):
        #Check columns
        return all(sum(col) == 1 for col in zip(*m))
    return False

m1 = [
    [0, 1, 0],
    [1, 0, 0],
    [0, 0, 1],
]

m2 = [
    [0, 1, 0],
    [1, 0, 0],
    [0, 1, 1],
]

m3 = [
    [0, 1, 0],
    [1, 0, 0],
    [1, 0, 0],
]

m4 = [
    [True, False, False],
    [False, True, False],
    [True, False, False],
]

print is_perm_matrix(m1)
print is_perm_matrix(m2)
print is_perm_matrix(m3)
print is_perm_matrix(m4)

output

True
False
False
False
PM 2Ring
  • 54,345
  • 6
  • 82
  • 182
0

One method is to call np.sum and pass an axis param, this should generate an array with all ones if not then you don't have a permutation matrix:

In [56]:

a = np.array([[0,1,0,0],[0,0,1,0],[0,1,1,0],[1,0,0,1]])
a
Out[56]:
array([[0, 1, 0, 0],
       [0, 0, 1, 0],
       [0, 1, 1, 0],
       [1, 0, 0, 1]])

In [57]:

np.all(np.sum(a,axis=0) == np.ones((1,4)), True)
Out[57]:
array([False], dtype=bool)

In [58]:

np.all(np.sum(a,axis=1) == np.ones((1,4)), True)
Out[58]:
array([False], dtype=bool)

In [60]:

np.sum(a, axis=1) == np.ones([1,4])
Out[60]:
array([[ True,  True, False, False]], dtype=bool)
In [59]:

np.sum(a, axis=0) == np.ones([1,4])
Out[59]:
array([[ True, False, False,  True]], dtype=bool)

In [61]:

np.sum(a,axis=0)
Out[61]:
array([1, 2, 2, 1])
In [62]:

np.sum(a,axis=1)
Out[62]:
array([1, 1, 2, 2])
EdChum
  • 376,765
  • 198
  • 813
  • 562