Search code examples
arrayssortingswapconstraint-programmingminizinc

Is there a way to swap columns of a 2d array (matrix) in MiniZinc, and keep track of that?


I'm currently working on MiniZinc.

I got the following 2d array (matrix):

0  1  0  0  0  0 
0  1  1  1  0  1 
0  0  0  0  1  1

Suppose that it has some order. That the very first column on the left is first, the next one at the right is the second one, and so on, like:

1  2  3  4  5  6
----------------
0  1  0  0  0  0 
0  1  1  1  0  1 
0  0  0  0  1  1

I need a way (like a constraint or something) that helps me to reduce the distance between the very first 1 in a row and the last 1 on that same row. For example, an ideal matrix to that is:

1  2  3  4  6  5
----------------
0  1  0  0  0  0 
0  1  1  1  1  0 
0  0  0  0  1  1

As you can see, it is by swapping column 5 and column 6 each together. But i don't know how to do this, and keeping track of the order, knowing that the first matrix has [1 2 3 4 5 6] and the second one is [1 2 3 4 6 5]

I really don't know how to model that kind of swapping columns in a 2d variable array.

Thanks for the help!


Solution

  • Here is a simple way: Say your original data matrix is data. You can use an array (say x) to keep track of the new order of the columns. To use the new order you use data[row,x[col]], e.g.

     [data[row,x[col]] | row in 1..num_rows, col in 1..num_cols]
    

    Here is a small example of this. Note that you have to add constraints on x to make it more interesting.

    include "globals.mzn"; 
    int: num_rows;
    int: num_cols;
    array[1..num_rows, 1..num_cols] of int: data;
    
    % decision variables
    array[1..num_cols] of var 1..num_cols: x; 
    
    solve satisfy;
    
    constraint
      all_different(x)
      % /\ more constraints on x  ....
    ;
    
    output [
        "data:\n",
        show2d(data) ++ "\n" ++ 
        "x: \(x)\n",
        "new_data:\n",
        show2d(array2d(1..num_rows, 1..num_cols, [data[i,x[j]] | i in          1..num_rows,j in 1..num_cols])) ++ "\n"
    ];
    
    % data
    num_rows = 3;
    num_cols = 6;
    data = array2d(1..num_rows,1..num_cols,
      [
      0,1,0,0,0,0,
      0,1,1,1,0,1,
      0,0,0,0,1,1
      ]);
    

    One of the solutions is:

     data:
     [| 0, 1, 0, 0, 0, 0 |
        0, 1, 1, 1, 0, 1 |
        0, 0, 0, 0, 1, 1 |]
    
     x: [3, 1, 4, 5, 2, 6]
     new_data:
     [| 0, 0, 0, 0, 1, 0 |
        1, 0, 1, 0, 1, 1 |
        0, 0, 0, 1, 0, 1 |]