Search code examples
vectorparipari-gp

Removing items from a vector in a loop - PARI/GP


I am looking at vectors [a,b,c], for a,b,c in [-1,0,1] along with a function, cycle, which shifts each entry of a vector one to the left: cycle( v ) = [v[3], v[1], v[2]].

I want to only consider vectors such that no two vectors are "cycle-equivalent"; ie: if I look at vectors x, y, I don't want y = cycle( x ).

What I tried was setting up a vector V which had all 27 of my possible vectors, and then defining the following:

removecycle( V, n ) = {
local( N );
N = setsearch( V, cycle( V[n] ) );
return( V[^N] );
}

This allows me to specify a specific vector, apply the function, and then return a new vector with the outcome, if there is one, removed. The issue of course is then I have to repeat this with the new vector, and repeat again and again, and opens myself up to human error.

How can I automate this? I imagine it is possible to set it up to have my vector of vectors V, test cycle( V[1] ), throw away the result, return a new vector W, then test cycle( W[2] ), etc etc until all possibilities have been tested. But I'm just not sure how to set it up!


Edit: MNWE, with numbers changed to above for convenience.

V=[[1, 1, 1], [1, 1, 2], [1, 1, 3], [1, 2, 1], [1, 2, 2], [1, 2, 3], [1, 3, 1], [1, 3, 2], [1, 3, 3], [2, 1, 1], [2, 1, 2], [2, 1, 3], [2, 2, 1], [2, 2, 2], [2, 2, 3], [2, 3, 1], [2, 3, 2], [2, 3, 3], [3, 1, 1], [3, 1, 2], [3, 1, 3], [3, 2, 1], [3, 2, 2], [3, 2, 3], [3, 3, 1], [3, 3, 2], [3, 3, 3]];

vecsort(vecsort(V),are_cycles,8)
> [[1, 1, 1], [1, 1, 2], [1, 1, 3], [1, 2, 2], [1, 2, 3], [1, 3, 2], [1, 3, 3], [2, 1, 1], [2, 1, 2], [2, 1, 3], [2, 2, 1], [2, 2, 2], [2, 2, 3], [2, 3, 1], [2, 3, 3], [3, 1, 1], [3, 1, 2], [3, 1, 3], [3, 2, 1], [3, 2, 2], [3, 2, 3], [3, 3, 1], [3, 3, 3]]
#vecsort(vecsort(V),are_cycles,8)
> 23

In my case, I would have cycle( [1, 1, 2] ) = [2, 1, 1], so I would want [2, 1, 1] removed as well, but this hasn't happened. As said, I guess the comparator needs improving, but I'm not sure how!


Solution

  • You can remove the duplicates with help of the custom comparator via vecsort(_, _, 8). See the MWE below:

    all_cycles(v) = [[v[3], v[1], v[2]], [v[2], v[3], v[1]]];
    
    contains(list, value) = {
        #select(n -> n == value, list) > 0
    };
    
    \\ your comparator here.
    are_cycles(v1, v2) = {
        if(contains(all_cycles(v1), v2), 0, lex(v1, v2));
    };
    
    
    V = [];
    vecsort(vecsort(V), are_cycles, 8)
    > []
    
    V = all_cycles([1, 2, 3]);
    vecsort(vecsort(V), are_cycles, 8)
    > [[2, 3, 1]]
    
    V = concat([[1, 2, 3], [3, 2, 1]], all_cycles([1, 2, 3]));
    vecsort(vecsort(V), are_cycles, 8)
    > [[1, 2, 3], [3, 2, 1]]
    
    V = concat(V, all_cycles([3, 2, 1]));
    vecsort(vecsort(V), are_cycles, 8)
    > [[1, 2, 3], [1, 3, 2]]
    

    Edit: much easier approach is to substitute each element with the representative of equivalence class it belongs to. Now no custom comparator is required.

    all_cycles(v) = [v, cycle(v), cycle(cycle(v))];
    representative(v) = vecsort(all_cycles(v))[1];
    
    V=[[1, 1, 1], [1, 1, 2], [1, 1, 3], [1, 2, 1], [1, 2, 2], [1, 2, 3], [1, 3, 1], [1, 3, 2], [1, 3, 3], [2, 1, 1], [2, 1, 2], [2, 1, 3], [2, 2, 1], [2, 2, 2], [2, 2, 3], [2, 3, 1], [2, 3, 2], [2, 3, 3], [3, 1, 1], [3, 1, 2], [3, 1, 3], [3, 2, 1], [3, 2, 2], [3, 2, 3], [3, 3, 1], [3, 3, 2], [3, 3, 3]];
    
    #vecsort(apply(representative, V),,8)
    > 11
    vecsort(apply(representative, V),,8)
    > [[1, 1, 1], [1, 1, 2], [1, 1, 3], [1, 2, 2], [1, 2, 3], [1, 3, 2], [1, 3, 3], [2, 2, 2], [2, 2, 3], [2, 3, 3], [3, 3, 3]]