English is not my native language: sorry for my mistakes. Thank you in advance for your answers.
Two Bijections and an Array...

Here is a 2D array (in this particular example: rows: 1 to 4; columns: A to D) nonrandomly and nonarbitrary filled with integers.
$$ \left[ \begin{array}{cc|cc} 7 & 1 & 1 & 7 \\ 4 & 4 & 1 & 1 \\ 5 & 1 & 1 & 5 \\ 3 & 3 & 5 & 5 \end{array} \right]. $$
These numbers can be handled, but only one kind of move is allowed: You can move the numbers on the left or the right in each row, but you cannot shuffle them and you cannot move them vertically.
Example (first row):
Right: 7 1 1 7 → 7 7 1 1 (shift)
Wrong: 7 1 1 7 → 7 1 7 1 (shuffle)
By the nature of the data in this model (here is the nonrandom and nonarbitrary part), it is possible to have the same number of identical integers in columns A and B, and in column C and D, respectively. In other words, two bijections (or perfect one-to-one correspondences).
That is: if you have 3 '1' in column A, then you need to have 3 '1' in column B, and so on, in order to have a solution.
An example is worth a thousand words. Applying allowed moves on our array, we can produce this result:
$$ \left[ \begin{array}{cc|cc} 1 & 1 & 7 & 7 \\ 1 & 1 & 4 & 4 \\ 1 & 1 & 5 & 5 \\ 3 & 3 & 5 & 5 \end{array} \right]. $$
It is easy to see that columns A and B share the same number of identical integers (1, 3), and columns C and D, too (7, 4, 5).
Then, a solution is valid when there is a perfect one-to-one correspondence between the numbers of A and B (bijection 1), regardless their order, on the one side; as well as a perfect one-to-one correspondence between the numbers of C and D (bijection 2), regardless their order, on the other side.
The values can be sorted, but do not need to. The following example is then a valid one:
$$ \left[ \begin{array}{cc|cc} 6 & 23 & 5 & 0 \\ 4 & 3 & 7 & 5 \\ 23 & 4 & 2 & 7 \\ 3 & 6 & 0 & 2 \end{array} \right]; $$
but the next one is invalid because there is no bijection:
$$ \left[ \begin{array}{cc|cc} 6 & 23 & 5 & 0 \\ 4 & 3 & 7 & 5 \\ 4 & 2 & 7 & 23 \\ 3 & 6 & 0 & 2 \end{array} \right]. $$
My question is: Do you know a way to solve this problem without a brute-force approach (totally inefficient for large arrays)?
A Connection With Graph Theory?
Thanks to a link provided by EvilTeach, I am trying to make connections between this problem and graph theory. I am not an expert in this field, but I think I may have “discovered” a little something.
In order to transform my array into a graph, I take each different value and make directional links between them.
For example: if the first row is 6 23 5 0, I create a link (inside columns A and B) between 6 and 23 with an arrow to show the direction from 6 to 23. Then, I draw another link between 5 and 0 (inside columns C and D, then), with an arrow.
At the end, I count the number of times each value is designated by an arrow (“IN”) and also the number of times this same value designates another value (“OUT”).
The graph is then:

With a valid array, we can see that the number of INs equals the number of OUTs for each value.
What happens with an invalid array?
Something like that:

Here, for some values, the number of IN is not equal to the number of OUT.
So let's see if there are any links between these values (here: 2, 4, 7, and 23).
- Between 2 and 4: the link created thanks to row 3
- Between 2 and 7: none
- Between 2 and 23: none
- Between 4 and 7: none
- Between 4 and 23: none
- Between 7 and 23: only one: row 3
Then, in this example, the graph seems to indicate that there is a problem with row 3. And this is indeed the case.
So... This approach can be seen as very naive. Indeed, some values will have self-recursive links, some will have more than 1 IN and 1 OUT, and it becomes more complex with a lot of values and links. Moreover, I do not prove anything here. Maybe it is just a lot of chance. But perhaps it is a clue of a deep connection between this problem and graph theory.
As I said earlier in this message, I am not familiar with graph theory, so you are welcome to give your remarks!
A More Complex Example
I have decided to see what happens with a more complex array:
$$ \left[ \begin{array}{cc|cc} 6 & 3 & 4 & 1 \\ 8 & 8 & 3 & 2 \\ 5 & 2 & 1 & 5 \\ 8 & 5 & 7 & 12 \\ 7 & 11 & 2 & 7 \\ 3 & 12 & 5 & 1 \\ 8 & 2 & 13 & 4 \\ 2 & 6 & 4 & 4 \\ 3 & 8 & 7 & 3 \\ 20 & 3 & 2 & 13 \\ 6 & 6 & 4 & 4 \\ 2 & 6 & 1 & 2 \\ 11 & 7 & 12 & 7 \\ 4 & 8 & 3 & 8 \\ 6 & 20 & 7 & 7 \\ 12 & 4 & 8 & 3 \end{array} \right]. $$
This array is valid: the bijections in columns A and B, and C and D, respectively, are perfect.
I have tried to create an intelligible graph which confirms the validity of the bijections (blue lines: links between A and B; orange lines: links between C and D):

Now, let's experiment two shifts negating the bijections, and affecting rows 7 and 12:
$$ \left[ \begin{array}{cc|cc} 6 & 3 & 4 & 1 \\ 8 & 8 & 3 & 2 \\ 5 & 2 & 1 & 5 \\ 8 & 5 & 7 & 12 \\ 7 & 11 & 2 & 7 \\ 3 & 12 & 5 & 1 \\ 13 & 4 & 2 & 8 \\ 2 & 6 & 4 & 4 \\ 3 & 8 & 7 & 3 \\ 20 & 3 & 2 & 13 \\ 6 & 6 & 4 & 4 \\ 6 & 1 & 2 & 2 \\ 11 & 7 & 12 & 7 \\ 4 & 8 & 3 & 8 \\ 6 & 20 & 7 & 7 \\ 12 & 4 & 8 & 3 \end{array} \right], $$
and its corresponding graph (purple for the new links between A and B; green for C and D):

At first glance, the errors revealed by the imbalance between the INs and the OUTs are not very efficient: the inequality concerns the integers 1, 2 and 6 linked between them such as:
- Link between 1 and 2: none,
- Link between 1 and 6: row 12 [great!],
- Link between 2 and 6: row 8 [so close...].
The present “method” is half full. One the one hand, it seems to allow to detect which rows are likely to be displaced, “out of sync” with the ideal of bijection (and then, how correct them); on the other hand, it really needs to be improved in order to, perhaps, implement an algorithm allowing to solve this problem. That is why I need your help.
A quick update.
I have solved this problem using a genetic algorithm I wrote in C++. It is able to find a solution in 1 or 2 hour(s). It is not even optimized (I am new to C++; my program is not even parallelized).
Initialization: DNA: encodage of the shift (for each line: 0 to 3, 0 for no shift, 3 for max shift to the right).
E.g. :
Evaluation: std::set_intersection for the number of bijections; fitness = 1/(# bijections max-#bijections in the DNA+1); if fitness = 1, break (we have a solution).
Selection: a simple 50|50 one-point crossover.
Mutation: 1%
GA gives amazing results for this NP-complete problem.
If you want more information, feel free to contact me.