tags:

views:

385

answers:

6

I have a binary matrix of size m-by-n. Given below is a sample binary matrix (the real matrix is much larger):

1010001
1011011
1111000
0100100

Given p = m*n, I have 2^p possible matrix configurations. I would like to get some patterns which satisfy certain rules. For example:

  1. I want not less that k cells in the jth column as zero
  2. I want the sum of cell values of the ith row greater than a given number Ai
  3. I want at least g cells in a column continuously as one
  4. etc....

How can I get such patterns satisfying these constraints strictly without sequentially checking all the 2^p combinations?

In my case, p can be a number like 2400, giving approximately 2.96476e+722 possible combinations.

+1  A: 

If you have enough constraints, exploring all possible matrices could be attempted:

// Explore all possibilities starting at POSITION (0..P-1)
explore(int position)
{
   // Check if one or more constraints can't be verified anymore with
   // all values currently set.
   invalid = ...;
   if (invalid) return;

   // Do we have a solution?
   if (position >= p)
   {
     // print the matrix
     return;
   }   

   // Set one more value and continue exploring
   for (int value=0;value<2;value++)
   { matrix[position] = value; explore(position+1); }
}

If the number of constraints is low, this approach will take too much time.

In this case, for the kind of constraints you gave as examples, simulated annealing may be a good solution. You must design an energy function, high when all constraints are met. That would be something like that:

  1. Generate a random matrix
  2. Compute energy E0
  3. Change one cell
  4. Compute energy E1
  5. If E1>E0, or E0-E1 is smaller than f(temperature), keep it, otherwise reverse the move
  6. Update temperature, and goto 2 unless stop criterion is reached
Eric Bainville
A: 

I might be way off here, but I remember doing something similar once with some genetic algorithm.

hyperboreean
A: 

Check out pseudo boolean constraints (also called 0-1 integer programming).

starblue
+1  A: 

If all the contraints relate to columns (as is the case in the question), then you can find all possible valid columns and check that each column in the matrix is in this set. (i.e. when you consider each column independently, you reduce the number of possibilities a lot.)

Richie Cotton
+1  A: 

Instead of iterating over all 2^p combinations, one way you could generate such binary matrices is by performing repeated row- and column-wise operations based on the given constraints you have. As an example, I'll post some code that will generate a matrix based on the three constraints you have listed above:

  • A minimum number of zeroes per column
  • A minimum sum for each row
  • A minimum sequential length of ones per column

Initializations:

First start by initializing a few parameters:

nRows = 10;         % Row size of matrix
nColumns = 10;      % Column size of matrix
minZeroes = 5;      % Constraint 1 (for columns)
minRowSum = 5;      % Constraint 2 (for rows)
minLengthOnes = 3;  % Constraint 3 (for columns)

Helper functions:

Next, create a couple of functions for generating column vectors that match constraints 1 and 3 from above:

function vector = make_column
  vector = [false(minZeroes,1); true(nRows-minZeroes,1)];  % Create vector
  [vector,maxLength] = randomize_column(vector);           % Randomize order
  while maxLength < minLengthOnes,      % Loop while constraint 3 is not met
    [vector,maxLength] = randomize_column(vector);         % Randomize order
  end
end

function [vector,maxLength] = randomize_column(vector)
  vector = vector(randperm(nRows));          % Randomize order
  edges = diff([false; vector; false]);      % Find rising and falling edges
  maxLength = max(find(edges == -1)-find(edges == 1));  % Find longest
                                                        % sequence of ones
end

The function make_column will first create a logical column vector with the minimum number of 0 elements and the remaining elements set to 1 (using the functions TRUE and FALSE). This vector will undergo random reordering of its elements until it contains a sequence of ones greater than or equal to the desired minimum length of ones. This is done using the randomize_column function. The vector is randomly reordered using the RANDPERM function to generate a random index order. The edges where the sequence switches between 0 and 1 are detected using the DIFF function. The indices of the edges are then used to find the length of the longest sequence of ones (using FIND and MAX).

Generate matrix columns:

With the above two functions we can now generate an initial binary matrix that will at least satisfy constraints 1 and 3:

binMat = false(nRows,nColumns);  % Initialize matrix
for iColumn = 1:nColumns,
  binMat(:,iColumn) = make_column;  % Create each column
end

Satisfy the row sum constraint:

Of course, now we have to ensure that constraint 2 is satisfied. We can sum across each row using the SUM function:

rowSum = sum(binMat,2);

If any elements of rowSum are less than the minimum row sum we want, we will have to adjust some column values to compensate. There are a number of different ways you could go about modifying column values. I'll give one example here:

while any(rowSum < minRowSum),            % Loop while constraint 2 is not met
  [minValue,rowIndex] = min(rowSum);      % Find row with lowest sum
  zeroIndex = find(~binMat(rowIndex,:));  % Find zeroes in that row
  randIndex = round(1+rand.*(numel(zeroIndex)-1));
  columnIndex = zeroIndex(randIndex);     % Choose a zero at random
  column = binMat(:,columnIndex);
  while ~column(rowIndex),                % Loop until zero changes to one
    column = make_column;                 % Make new column vector
  end
  binMat(:,columnIndex) = column;         % Update binary matrix
  rowSum = sum(binMat,2);                 % Update row sum vector
end

This code will loop until all the row sums are greater than or equal to the minimum sum we want. First, the index of the row with the smallest sum (rowIndex) is found using MIN. Next, the indices of the zeroes in that row are found and one of them is randomly chosen as the index of a column to modify (columnIndex). Using make_column, a new column vector is continuously generated until the 0 in the given row becomes a 1. That column in the binary matrix is then updated and the new row sum is computed.

Summary:

For a relatively small 10-by-10 binary matrix, and the given constraints, the above code usually completes in no more than a few seconds. With more constraints, things will of course get more complicated. Depending on how you choose your constraints, there may be no possible solution (for example, setting minRowSum to 6 will cause the above code to never converge to a solution).

Hopefully this will give you a starting point to begin generating the sorts of matrices you want using vectorized operations.

gnovice
A: 

This is virtually impossible if your constraint set is complex enough. You might try to use a stochastic optimizer, like simulated annealing, particle swarm optimization, or a genetic algorithm to find a feasible solution.

However, if you can generate one (non-random) solution to such a problem, then often you can generate others by random permutations made to the existing solution.

woodchips

related questions