Search code examples
pythonarrayspython-3.xgenetic-algorithmcyclic

Use permutation cycles to form new arrays in python3


I have an array a = [[1,2,3,4,5,6,7,8,9,10],[4,1,6,2,3,5,8,9,7,10]], where lets say a1 = [1,2,3,4,5,6,7,8,9,10] and a2 = [4,1,6,2,3,5,8,9,7,10], from which I have constructed cyclic permutation. Note that a1 is a sorted array. For e.g in my case, the cycles are;

c = [[4, 2, 1], [6, 5, 3], [8, 9, 7], [10]]
  lets say c1 = [4, 2, 1]
           c2 = [6, 5, 3]
           c3 = [8, 9, 7]
           c4 = [10]

Now I want to form new arrays a11 and a22 as follow; enter image description here

I have a method that gives all the cycle in a given permutation, but constructing new arrays from it, seems to be complicated. Any ideas to implement this is in python3 would be much appreciated.

-------------------

To obtain cycles;

import numpy as np
import random

def cx(individual):
    c = {i+1: individual[i] for i in range(len(individual))}
    cycles = []

    while c:
        elem0 = next(iter(c)) # arbitrary starting element
        this_elem = c[elem0]
        next_item = c[this_elem]

        cycle = []
        while True:
            cycle.append(this_elem)
            del c[this_elem]
            this_elem = next_item
            if next_item in c:
                next_item = c[next_item]
            else:
                break

        cycles.append(cycle)

    return cycles
aa = cx([4,1,6,2,3,5, 8,9,7,10])
print("array: ", aa)

Solution

  • You can ues itertools.permutations to get different permutations of items of a, then use itertools.cycle to cycle through dicts that map items of sublists of a to their indices, and zip the sublists of c with the mappings to produce sequences that follow the indices specified by the cycling dicts:

    a = [[1,2,3,4,5,6,7,8,9,10],[4,1,6,2,3,5,8,9,7,10]]
    c = [[4, 2, 1], [6, 5, 3], [8, 9, 7], [10]]
    from itertools import cycle, permutations
    print([[d[i] for i in range(len(d))] for l in permutations(a) for d in ({p[n]: n for s, p in zip(c, cycle({n: i for i, n in enumerate(s)} for s in l)) for n in s},)])
    

    This outputs:

    [[1, 2, 6, 4, 3, 5, 7, 8, 9, 10], [4, 1, 3, 2, 5, 6, 8, 9, 7, 10]]