1

I've done this function, changesOfSign, which takes as argument a matrix and returns the matrix whose rows are all possible combinations of the original rows with the + or - sign associated to the entries:

import itertools
import numpy as np

def expandgrid(*itrs): # https://stackoverflow.com/a/12131385/1100107
   product = list(itertools.product(*itrs))
   return [[x[i] for x in product] for i in range(len(itrs))]

def changesOfSign(mat):
    maps = np.apply_along_axis(
        lambda r: map(lambda x: [0] if x==0 else [-x,x], r), 
        1, mat
    )
    lists = [list(m) for m in maps]
    mats = [np.transpose(expandgrid(*lists[i])) for i in range(len(lists))]
    return np.vstack(tuple(mats))

arr = np.array([
    [1, 0, 3],
    [5, 2, 4]
])

For example:

changesOfSign(arr)
Out[22]: 
array([[-1,  0, -3],
       [-1,  0,  3],
       [ 1,  0, -3],
       [ 1,  0,  3],
       [-5, -2, -4],
       [-5, -2,  4],
       [-5,  2, -4],
       [-5,  2,  4],
       [ 5, -2, -4],
       [ 5, -2,  4],
       [ 5,  2, -4],
       [ 5,  2,  4]])

Now I want to generalize this function to have the possibility to choose for which columns I want the changes of sign. I've done:

cols = [0, 1] # columns for which changes of sign are desired
lists = np.apply_along_axis(
    lambda r: [[x] if (x==0 or i not in cols) else [-x,x] for i,x in enumerate(r)], 
    1, arr
)
mats = [np.transpose(expandgrid(*lists[i])) for i in range(len(lists))]
np.vstack(tuple(mats))

It works:

array([[-1,  0,  3],
       [ 1,  0,  3],
       [-5, -2,  4],
       [-5,  2,  4],
       [ 5, -2,  4],
       [ 5,  2,  4]])

but I have this warning when I run np.apply_along_axis:

VisibleDeprecationWarning: Creating an ndarray from ragged nested sequences (which is a list-or-tuple of lists-or-tuples-or ndarrays with different lengths or shapes) is deprecated. If you meant to do this, you must specify 'dtype=object' when creating the ndarray.

I don't know where I can put dtype=object. Any idea?


EDIT

I have a solution:

def f(cols):
    return lambda r: [[x] if (x==0 or i not in cols) else [-x,x] for i,x in enumerate(r)]
lists = [f(cols)(r) for r in arr]
mats = [np.transpose(expandgrid(*lists[i])) for i in range(len(lists))]
np.vstack(tuple(mats))
Stéphane Laurent
  • 75,186
  • 15
  • 119
  • 225

1 Answers1

0

Here is my solution. Set cols=None (default) for all columns.

def changesOfSign(mat, cols=None):
    def f(r):
        return (
            [[x] if (x==0 or i not in cols) else [-x,x] 
             for i,x in enumerate(r)]
        )
    def g(r):
        return (
            [[0] if x==0 else [-x,x] for x in r]
        )
    h = g if cols is None else f
    lists = [h(r) for r in mat]
    mats = [np.transpose(expandgrid(*l)) for l in lists]
    return np.vstack(tuple(mats))
Stéphane Laurent
  • 75,186
  • 15
  • 119
  • 225