text:
local reps,tori,labels,I,II,ords,blocks;

reps:=[[[1,1],[2,1],[3,1],[4,1],[5,1],[6,1],[7,1],[8,1]],              # E_8
#       [[1,1],[2,1],[10,1],[11,1],[5,1],[6,1],[7,1],[8,1]],            # E_8(a_1)
       [[1,1],[2,1],[10,1],[11,1],[5,1],[6,1],[7,1],[8,1]],            # E_8(a_1)
#       [[1,1],[2,1],[3,1],[10,1],[12,1],[13,1],[14,1],[8,1]],          # E_8(a_2)
       [[1,1],[2,1],[3,1],[10,1],[12,1],[13,1],[14,1],[8,1]],          # E_8(a_2)
       [[1,1],[4,1],[6,1],[7,1],[8,1],[17,1],[18,1],[19,1]],           # E_8(a_3) e cel de mai jos dar ordonat
#       [[8,1],[18,1],[7,1],[6,1],[19,1],[1,1],[17,1],[4,1]],           # E_8(a_3)  merge si in char 5
#       [[7,1],[8,1],[9,1],[10,1],[11,1],[12,1],[13,1],[19,1]],         # E_8(a_3)
       [[1,1],[4,1],[6,1],[8,1],[17,1],[18,1],[19,1],[21,1]],          # E_8(a_4) e cel de mai jos dar ordonat
#       [[18,1],[6,1],[19,1],[1,1],[17,1],[21,1],[4,1],[8,1]],          # E_8(a_4) merge si in char 5
#       [[9,1],[10,1],[11,1],[12,1],[13,1],[14,1],[15,1],[19,1]],       # E_8(a_4)
       [[1,1],[2,1],[3,1],[4,1],[5,1],[6,1],[7,1]],                    # E_7
       [[1,1],[4,1],[7,1],[8,1],[14,1],[17,1],[19,1],[26,1]],          # E_8(b_4) e cel de mai jos dar ordonat
#       [[8,1],[7,1],[14,1],[26,1],[19,1],[1,1],[17,1],[4,1]],          # E_8(b_4) merge si in char 5
#       [[7,1],[8,1],[9,1],[17,1],[18,1],[19,1],[20,1],[21,1]],         # E_8(b_4)
#       [[18,1],[22,1],[19,1],[1,1],[17,1],[20,1],[21,1],[4,1],[6,1]],  # E_8(a_5)
       [[1,1],[12,1],[14,1],[15,1],[17,1],[21,1],[26,1],[27,1]],       # E_8(a_5) D_8(a_1) in a D_8: deduced from Seitz' E_8(a_6) used in proof
#       [[9,1],[14,1],[15,1],[17,1],[18,1],[19,1],[20,1],[26,1]],       # E_8(a_5)
#       [[1,1],[2,1],[11,1],[10,1],[5,1],[6,1],[7,1]],                  # E_7(a_1)
       [[1,1],[3,1],[10,1],[11,1],[5,1],[6,1],[7,1]],                  # E_7(a_1)
#       [[18,1],[8,1],[31,1],[7,1],[33,1],[4,1],[19,1],[23,1]],         # E_8(b_5) # works in char 5
       [[4,1],[7,1],[8,1],[18,1],[19,1],[23,1],[31,1],[33,1]],         # E_8(b_5) # e cel de sus ordonat
#       [[8,1],[16,1],[17,1],[18,1],[20,1],[21,1],[24,1],[33,1]],       # E_8(b_5)
       [[8,1],[7,1],[6,1],[5,1],[4,1],[2,1],[3,1]],                    # D_7
#       [[18,1],[31,1],[7,1],[33,1],[4,1],[29,1],[23,1],[19,1]],        # E_8(a_6) # works in char 5
       [[4,1],[7,1],[18,1],[19,1],[23,1],[29,1],[31,1],[33,1]],        # E_8(a_6) # e cel de sus ordonat
#       [[4,1],[10,1],[12,1],[14,1],[15,1],[26,1],[27,1],[30,1]],       # E_8(a_6)
#       [[1,1],[2,1],[3,1],[10,1],[12,1],[13,1],[14,1]],                # E_7(a_2)
       [[1,1],[2,1],[3,1],[10,1],[12,1],[13,1],[14,1]],                # E_7(a_2)
       [[1,1],[2,1],[3,1],[4,1],[5,1],[6,1],[8,1]],                    # E_6A_1

#      [[2,1],[3,1],[10,1],[12,1],[6,1],[7,1],[8,1],[83,1]],            # (D_7(a_1))^{(2)}    char 2
#       [[8,1],[7,1],[6,1],[5,1],[10,1],[11,-1],[2,1],[3,1]],            # D_7(a_1)
       [[2,1],[3,1],[10,1],[12,1],[6,1],[7,1],[8,1]],                   # D_7(a_1)
#       [[4,1],[15,1],[18,1],[19,1],[23,1],[31,1],[33,1],[39,1]],       # E_8(b_6) # deduced from E_8(b_5) ?gp de componente?
       [[4,1],[8,1],[18,1],[19,1],[23,1],[31,1],[33,1],[39,-1],[41,1]], # E_8(b_6) # cel de mai jos ordonat
#       [[31,1],[33,1],[18,1],[4,1],[39,-1],[41,1],[8,1],[19,1],[23,1]], # E_8(b_6) # cu - merge si in char 5
#       [[4,1],[17,1],[12,1],[29,1],[30,1],[31,1],[34,1],[35,1]],        # E_8(b_6) Seitz' used in proof
#       [[15,1],[22,1],[23,1],[24,1],[25,1],[26,1],[27,1],[28,1]],       # E_8(b_6)
       [[1,1],[4,1],[6,1],[7,1],[17,1],[18,1],[19,1]],                  # E_7(a_3) e cel de mai jos dar ordonat
#       [[17,1],[1,1],[19,1],[6,1],[7,1],[18,1],[4,1]],                  # E_7(a_3) merge si in char 5
#       [[1,1],[4,1],[7,1],[12,1],[13,1],[17,1],[19,1]],                 # E_7(a_3)
#       [[3,1],[5,1],[1,1],[6,1],[11,1],[12,1],[2,1],[8,1]],             # E_6(a_1)A_1
       [[1,1],[2,1],[11,1],[12,1],[5,1],[6,1],[8,1]],                   # E_6(a_1)+A_1
#       [[1,1],[3,1],[4,1],[5,1],[6,1],[7,1],[8,1],[67,1]],             # (A_7)^{(3)}     char 3
       [[1,1],[3,1],[4,1],[5,1],[6,1],[7,1],[8,1]],                     # A_7
#       [[8,1],[7,1],[13,1],[10,1],[11,-1],[12,1],[2,1],[3,1]],          # D_7(a_2)
       [[2,1],[3,1],[10,1],[12,1],[13,1],[14,1],[8,1]],                 # D_7(a_2)
       [[1,1],[2,1],[3,1],[4,1],[5,1],[6,1]],                           # E_6
       [[7,1],[6,1],[5,1],[4,1],[2,1],[3,1]],                           # D_6
#       [[1,1],[2,1],[3,1],[4,1],[5,1],[7,1],[8,1],[51,1]],             # (D_5+A_2)^{(2)}     char 2
       [[1,1],[3,1],[4,1],[2,1],[5,1],[7,1],[8,1]],                     # D_5A_2
#       [[3,1],[5,1],[1,1],[6,1],[11,1],[12,1],[2,1]],                   # E_6(a_1)
       [[1,1],[2,1],[11,1],[12,1],[5,1],[6,1]],                         # E_6(a_1)
       [[1,1],[4,1],[7,1],[14,1],[17,1],[18,1],[19,1],[26,1]],          # E_7(a_4) e cel de mai jos dar ordonat
#       [[17,1],[1,1],[19,1],[14,1],[26,1],[7,1],[18,1],[4,1]],          # E_7(a_4) merge si in char 5
#       [[1,1],[4,1],[7,1],[11,1],[25,1],[26,1],[27,1]],                 # E_7(a_4)
       [[2,1],[4,1],[5,1],[6,1],[7,1],[8,1],[1,1]],                     # A_6A_1
#       [[7,1],[6,1],[5,1],[10,1],[11,-1],[2,1],[3,1]],                  # D_6(a_1)
       [[2,1],[3,1],[10,1],[12,1],[6,1],[7,1]],                         # D_6(a_1)
       [[2,1],[4,1],[5,1],[6,1],[7,1],[8,1]],                           # A_6
#       [[47,1],[49,1],[5,1],[45,1],[44,1],[42,1],[27,1],[46,1]],        # E_8(a_7)
       [[30,1],[33,1],[35,1],[36,1],[40,1],[45,1],[53,1],[58,1]],       # E_8(a_7)

       [[1,1],[3,1],[4,1],[2,1],[5,1],[7,1]],                # D_5A_1
#       [[24,1],[26,1],[7,1],[27,1],[23,1],[4,1],[25,1]],     # E_7(a_5)
       [[4,1],[7,1],[23,1],[24,1],[25,1],[26,1],[27,1]],     # E_7(a_5) e cel de sus ordonat
#       [[4,1],[11,1],[14,1],[16,1],[24,1],[25,1],[26,1]],    # E_7(a_5)
       [[1,1],[4,1],[6,1],[8,1],[17,1],[18,1],[19,1]],       # E_6(a_3)A_1  e cel de mai jos dar ordonat
#       [[17,1],[1,1],[19,1],[6,1],[18,1],[4,1],[8,1]],       # E_6(a_3)A_1 merge si in char 5
#       [[4,1],[6,1],[9,1],[11,1],[18,1],[19,1],[8,1]],       # E_6(a_3)+A_1
#       [[7,1],[13,1],[10,1],[11,-1],[12,1],[2,1],[3,1]],     # D_6(a_2)
       [[2,1],[3,1],[10,1],[12,1],[13,1],[14,1]],            # D_6(a_2)
#       [[1,1],[3,1],[10,1],[12,1],[2,1],[5,1],[7,1],[8,1]],  # D_5(a_1)A_2
       [[1,1],[10,1],[11,1],[2,1],[5,1],[7,1],[8,1]],        # D_5(a_1)+A_2
       [[2,1],[4,1],[5,1],[6,1],[7,1],[1,1]],                # A_5A_1
       [[1,1],[3,1],[4,1],[2,1],[6,1],[7,1],[8,1]],          # A_4A_3
       [[1,1],[3,1],[4,1],[2,1],[5,1]],                      # D_5
       [[1,1],[4,1],[6,1],[17,1],[18,1],[19,1]],             # E_6(a_3)  e cel de mai jos dar ordonat
#       [[17,1],[1,1],[19,1],[6,1],[18,1],[4,1]],             # E_6(a_3) merge si in char 5
#       [[4,1],[6,1],[9,1],[11,1],[18,1],[19,1]],             # E_6(a_3)
#       [[2,1],[3,1],[4,1],[5,1],[7,1],[8,1],[63,1]],        # (D_4+A_2)^{(2)}     char 2
       [[3,1],[4,1],[2,1],[5,1],[7,1],[8,1]],                # D_4A_2
       [[5,1],[6,1],[7,1],[8,1],[1,1],[3,1],[2,1]],          # A_4A_2A_1
#       [[1,1],[3,1],[10,1],[12,1],[2,1],[5,1],[7,1]],        # D_5(a_1)A_1
       [[1,1],[10,1],[11,1],[2,1],[5,1],[7,1]],              # D_5(a_1)+A_1
       [[1,1],[3,1],[4,1],[5,1],[6,1]],                      # A_5
       [[1,1],[3,1],[4,1],[2,1],[6,1],[7,1]],                # A_4A_2
       [[1,1],[3,1],[4,1],[2,1],[6,1],[8,1]],                # A_4A_1^2
#       [[1,1],[3,1],[10,1],[12,1],[2,1],[5,1]],              # D_5(a_1)
       [[1,1],[10,1],[11,1],[2,1],[5,1]],                    # D_5(a_1)

       [[1,1],[3,1],[4,1],[6,1],[7,1],[8,1]],          # A_3^2
       [[1,1],[3,1],[4,1],[2,1],[6,1]],                # A_4A_1
#       [[3,1],[10,1],[12,1],[2,1],[5,1],[7,1],[8,1]],  # D_4(a_1)A_2
       [[2,1],[3,1],[10,1],[12,1],[7,1],[8,1]],        # D_4(a_1)+A_2
       [[3,1],[4,1],[2,1],[5,1],[7,1]],                # D_4A_1
       [[5,1],[6,1],[7,1],[1,1],[3,1],[2,1]],          # A_3A_2A_1
       [[1,1],[3,1],[4,1],[2,1]],                      # A_4
#       [[1,1],[3,1],[4,1],[6,1],[7,1],[44,1]],        # (A_3+A_2)^{(2)}     char 2
       [[3,1],[4,1],[2,1],[6,1],[7,1]],                # A_3A_2
#       [[3,1],[10,1],[12,1],[2,1],[5,1],[7,1]],        # D_4(a_1)A_1
       [[2,1],[3,1],[10,1],[12,1],[7,1]],              # D_4(a_1)+A_1 Ross'
#       [[2,1],[5,1],[10,1],[11,1],[7,1]],              # D_4(a_1)+A_1 Seitz'
       [[5,1],[6,1],[7,1],[2,1],[3,1]],                # A_3A_1^2
       [[1,1],[3,1],[5,1],[6,1],[2,1],[8,1]],          # A_2^2A_1^2
       [[3,1],[4,1],[2,1],[5,1]],                      # D_4
#       [[3,1],[10,1],[12,1],[2,1],[5,1]],              # D_4(a_1)
       [[2,1],[3,1],[10,1],[12,1]],                    # D_4(a_1)
       [[1,1],[3,1],[4,1],[6,1]],                      # A_3A_1
       [[1,1],[3,1],[5,1],[6,1],[2,1]],                # A_2^2A_1
       [[1,1],[3,1],[5,1],[6,1]],                      # A_2^2
       [[1,1],[3,1],[2,1],[5,1],[7,1]],                # A_2A_1^3
       [[1,1],[3,1],[4,1]],                            # A_3
       [[2,1],[4,1],[1,1],[6,1]],                      # A_2A_1^2
       [[1,1],[3,1],[2,1]],                            # A_2A_1
       [[2,1],[3,1],[5,1],[7,1]],                      # A_1^4
       [[1,1],[3,1]],                                  # A_2
       [[1,1],[4,1],[6,1]],                            # A_1^3
       [[1,1],[6,1]],                                  # A_1^2
       [[1,1]]                                         # A_1
       ];

I:=[[],
    [4],           #??? E_8(a_1)
    [4,6],         #??? E_8(a_2)
    [2,3,5],       # E_8(a_3)
    [2,3,5,7],     # E_8(a_4)
    [],            # E_7
    [2,3,5,6],     # E_8(b_4)
    [2,3,5,6,8],   # E_8(a_5)
    [4],           # E_7(a_1)
    [1,2,3,5,6],   # E_8(b_5)
    [],            # D_7
    [1,2,3,5,6,8], # E_8(a_6)
    [4,6],         #??? E_7(a_2)
    [],            # E_6A_1

#    [4],             # (D_7(a_1))^{(2)}     char 2
    [4],             # D_7(a_1)
    [1,2,3,5,6,7],   # E_8(b_6)
    [2,3,5],         # E_7(a_3)
    [4],             # E_6(a_1)A_1
#    [],              # (A_7)^{(3)}     char 3
    [],              # A_7
    [4,5],           #??? D_7(a_2)
    [],              # E_6
    [],              # D_6
#    [],              # (D_5+A_2)^{(2)}     char 2
    [],              # D_5A_2
    [4],             # E_6(a_1)
    [2,3,5,6],       # E_7(a_4)
    [],              # A_6A_1
    [4],             # D_6(a_1)
    [],              # A_6
    [1,2,3,4,6,7,8], # E_8(a_7)

    [],          # D_5A_1
    [1,2,3,5,6], # E_7(a_5)
    [2,3,5],     # E_6(a_3)A_1
    [4,5],       #??? D_6(a_2)
    [4],         # D_5(a_1)A_2
    [],          # A_5A_1
    [],          # A_4A_3
    [],          # D_5
    [2,3,5],     # E_6(a_3)
#    [],          # (D_4+A_2)^{(2)}     char 2
    [],          # D_4A_2
    [],          # A_4A_2A_1
    [4],         # D_5(a_1)A_1
    [],          # A_5
    [],          # A_4A_2
    [],          # A_4A_1
    [4],         # D_5(a_1) check this also

    [],  # A_3^2
    [],  # A_4A_1
    [4], # D_4(a_1)A_2
    [],  # D_4A_1
    [],  # A_3A_2A_1
    [],  # A_4
#    [],  # (A_3+A_2)^{(2)}     char 2
    [],  # A_3A_2
    [4], # D_4(a_1)A_1
    [],  # A_3A_1^2
    [],  # A_2^2A_1^2
    [],  # D_4
    [4], # D_4(a_1)
    [],  # A_3A_1
    [],  # A_2^2A_1
    [],  # A_2^2
    [],  # A_2A_1^3
    [],  # A_3
    [],  # A_2A_1^2
    [],  # A_2A_1
    [],  # A_1^4
    [],  # A_2
    [],  # A_1^3
    [],  # A_1^2
    []   # A_1
    ];

#
# The parabolic where the representative is distinguished
#
II:=[[1,2,3,4,5,6,7,8], # E_8
     [1,2,3,4,5,6,7,8], # E_8(a_1)
     [1,2,3,4,5,6,7,8], # E_8(a_2)
     [1,2,3,4,5,6,7,8], # E_8(a_3)
     [1,2,3,4,5,6,7,8], # E_8(a_4)
     [1,2,3,4,5,6,7],   # E_7
     [1,2,3,4,5,6,7,8], # E_8(b_4)
     [1,2,3,4,5,6,7,8], # E_8(a_5)
     [1,2,3,4,5,6,7],   # E_7(a_1)
     [1,2,3,4,5,6,7,8], # E_8(b_5)
     [2,3,4,5,6,7,8],   # D_7
     [1,2,3,4,5,6,7,8], # E_8(a_6)
     [1,2,3,4,5,6,7],   # E_7(a_2)
     [1,2,3,4,5,6,8],   # E_6A_1

#     [2,3,4,5,6,7,8],   # D_7(a_1)^{(2)}     char 2
     [2,3,4,5,6,7,8],   # D_7(a_1)
     [1,2,3,4,5,6,7,8], # E_8(b_6)
     [1,2,3,4,5,6,7],   # E_7(a_3)
     [1,2,3,4,5,6,8],   # E_6(a_1)A_1
#     [1,3,4,5,6,7,8],   # A_7^{(3)}     char 3
     [1,3,4,5,6,7,8],   # A_7
     [2,3,4,5,6,7,8],   # D_7(a_2)
     [1,2,3,4,5,6],     # E_6
     [2,3,4,5,6,7],     # D_6
#     [1,2,3,4,5,7,8],   # D_5A_2^{(2)}     char 2
     [1,2,3,4,5,7,8],   # D_5A_2
     [1,2,3,4,5,6],     # E_6(a_1)
     [1,2,3,4,5,6,7],   # E_7(a_4)
     [1,2,4,5,6,7,8],   # A_6A_1
     [2,3,4,5,6,7],     # D_6(a_1)
     [2,4,5,6,7,8],     # A_6
     [1,2,3,4,5,6,7,8], # E_8(a_7)

     [1,2,3,4,5,7],   # D_5A_1
     [1,2,3,4,5,6,7], # E_7(a_5)
     [1,2,3,4,5,6,8], # E_6(a_3)A_1
     [2,3,4,5,6,7],   # D_6(a_2)
     [1,2,3,4,5,7,8], # D_5(a_1)A_2
     [1,2,4,5,6,7],   # A_5A_1
     [1,2,3,4,6,7,8], # A_4A_3
     [1,2,3,4,5],     # D_5
     [1,2,3,4,5,6],   # E_6(a_3)
#     [2,3,4,5,7,8],   # D_4A_2^{(2)}     char 2
     [2,3,4,5,7,8],   # D_4A_2
     [1,2,3,5,6,7,8], # A_4A_2A_1
     [1,2,3,4,5,7],   # D_5(a_1)A_1
     [1,3,4,5,6],     # A_5
     [1,2,3,4,6,7],   # A_4A_2
     [1,2,3,4,6,8],   # A_4A_1^2
     [1,2,3,4,5],     # D_5(a_1)

     [1,3,4,6,7,8], # A_3^2
     [1,2,3,4,6],   # A_4A_1
     [2,3,4,5,7,8], # D_4(a_1)A_2
     [2,3,4,5,7],   # D_4A_1
     [1,2,3,5,6,7], # A_3A_2A_1
     [1,2,3,4],     # A_4
#     [2,3,4,6,7],   # A_3A_2^{(2)}     char 2
     [2,3,4,6,7],   # A_3A_2
     [2,3,4,5,7],   # D_4(a_1)A_1
     [2,3,5,6,7],   # A_3A_1^2
     [1,2,3,5,6,8], # A_2^2A_1^2
     [2,3,4,5],     # D_4
     [2,3,4,5],     # D_4(a_1)
     [1,3,4,6],     # A_3A_1
     [1,2,3,5,6],   # A_2^2A_1
     [1,3,5,6],     # A_2^2
     [1,2,3,5,7],   # A_2A_1^3
     [1,3,4],       # A_3
     [1,2,4,6],     # A_2A_1^2
     [1,2,3],       # A_2A_1
     [2,3,5,7],     # A_1^2
     [1,3],         # A_2
     [1,4,6],       # A_1^3
     [1,6],         # A_1^2
     [1]            # A_1
     ];

labels:=["E_8",
         "E_8(a_1)",
         "E_8(a_2)",
         "E_8(a_3)",
         "E_8(a_4)",
         "E_7",
         "E_8(b_4)",
         "E_8(a_5)",
         "E_7(a_1)",
         "E_8(b_5)",
         "D_7",
         "E_8(a_6)",
         "E_7(a_2)",
         "E_6A_1",

#         "D_7(a_1)^{(2)}",
         "D_7(a_1)",
         "E_8(b_6)",
         "E_7(a_3)",
         "E_6(a_1)A_1",
#         "A_7^{(3)}",
         "A_7",
         "D_7(a_2)",
         "E_6",
         "D_6",
#         "D_5A_2^{(2)}",
         "D_5A_2",
         "E_6(a_1)",
         "E_7(a_4)",
         "A_6A_1",
         "D_6(a_1)",
         "A_6",
         "E_8(a_7)",

         "D_5A_1",
         "E_7(a_5)",
         "E_6(a_3)A_1",
         "D_6(a_2)",
         "D_5(a_1)A_2",
         "A_5A_2",
         "A_4A_3",
         "D_5",
         "E_6(a_3)",
#         "D_4A_2^{(2)}",
         "D_4A_2",
         "A_4A_2A_1",
         "D_5(a_1)A_1",
         "A_5",
         "A_4A_2",
         "A_4A_1^2",
         "D_5(a_1)",

         "A_3^2",
         "A_4A_1",
         "D_4(a_1)A_2",
         "D_4A_1",
         "A_3A_2A_1",
         "A_4",
#         "A_3A_2^{(2)}",
         "A_3A_2",
         "D_4(a_1)A_1",
         "A_3A_1^2",
         "A_2^2A_1^2",
         "D_4",
         "D_4(a_1)",
         "A_3A_1",
         "A_2^2A_1",
         "A_2^2",
         "A_2A_1^3",
         "A_3",
         "A_2A_1^2",
         "A_2A_1",
         "A_1^4",
         "A_2",
         "A_1^3",
         "A_1^2",
         "A_1"
         ];

tori:=[
    [2,2,2,2,2,2,2,2],   # E_8
    [2,2,2,0,2,2,2,2],   # E_8(a_1)
    [2,2,2,0,2,0,2,2],   # E_8(a_2)
    [2,0,0,2,0,2,2,2],   # E_8(a_3)
    [2,0,0,2,0,2,0,2],   # E_8(a_4)
    [2,2,2,2,2,2,2,-27], # E_7
    [2,0,0,2,0,0,2,2],   # E_8(b_4)
    [2,0,0,2,0,0,2,0],   # E_8(a_5)
    [2,2,2,0,2,2,2,-21], # E_7(a_1)
    [0,0,0,2,0,0,2,2],   # E_8(b_5)
    [-21,2,2,2,2,2,2,2], # D_7
    [0,0,0,2,0,0,2,0],   # E_8(a_6)
    [2,2,2,0,2,0,2,-17], # E_7(a_2)
    [2,2,2,2,2,2,-17,2], # E_6A_1

#    [-16,2,0,2,2,2,2,2],   # D_7(a_1)^{(2)}     char 2
    [-16,2,2,0,2,2,2,2],   # D_7(a_1)
    [0,0,0,2,0,0,0,2],     # E_8(b_6)
    [2,0,0,2,0,2,2,-15],   # E_7(a_3)
    [2,2,2,0,2,2,-13,2],   # E_6(a_1)A_1
#    [2,-15,2,2,2,2,2,2],   # A_7^{(3)}     char 4
    [2,-15,2,2,2,2,2,2],   # A_7
    [-13,2,2,0,2,0,2,2],   # D_7(a_2)
    [2,2,2,2,2,2,-16,0],   # E_6
    [-15,2,2,2,2,2,2,-10], # D_6
#    [2,2,2,2,2,-12,2,2],   # D_5A_2^{(2)}     char 2
    [2,2,2,2,2,-12,2,2],   # D_5A_2
    [2,2,2,0,2,2,-12,0],   # E_6(a_1)
    [2,0,0,2,0,0,2,-11],   # E_7(a_4)
    [2,2,-11,2,2,2,2,2],   # A_6(a_1)
    [-11,2,2,0,2,2,2,-8],  # D_6(a_1)
    [0,2,-10,2,2,2,2,2],   # A_6
    [0,0,0,0,2,0,0,0],     # E_8(a_7)

    [2,2,2,2,2,-11,2,-1], # D_5A_1
    [0,0,0,2,0,0,2,-9],   # E_7(a_5)
    [2,0,0,2,0,2,-9,2],   # E_6(a_3)A_1
    [-9,2,2,0,2,0,2,-6],  # D_6(a_2)
    [2,2,2,0,2,-9,2,2],   # D_5(a_1)A_2
    [2,2,-9,2,2,2,2,-5],  # A_5A_1
    [2,2,2,2,-9,2,2,2],   # A_4A_3
    [2,2,2,2,2,-10,0,0],  # D_5
    [2,0,0,2,0,2,-8,0],   # E_6(a_3)
#    [-6,2,2,2,2,-8,2,2],  # D_4A_2^{(2)}     char 2
    [-6,2,2,2,2,-8,2,2],  # D_4A_2
    [2,2,2,-7,2,2,2,2],   # A_4A_2A_1
    [2,2,2,0,2,-8,2,-1],  # D_5(a_1)A_1
    [2,-9,2,2,2,2,-5,0],  # A_5
    [2,2,2,2,-8,2,2,-2],  # A_4A_2
    [2,2,2,2,-7,2,-2,2],  # A_4A_1^2
    [2,2,2,0,2,-7,0,0],    # D_5(a_1)

    [2,-3,2,2,-6,2,2,2],   # A_3^2
    [2,2,2,2,-7,2,-1,0],   # A_4A_1
    [-4,2,2,0,2,-6,2,2],   # D_4(a_1)A_2
    [-6,2,2,2,2,-7,2,-1],  # D_4A_1
    [2,2,2,-6,2,2,2,-3],   # A_3A_2A_1
    [2,2,2,2,-6,0,0,0],    # A_4
#    [-3,2,2,2,-6,2,2,-2],  # A_3A_2^{(2)}     char 2
    [-3,2,2,2,-6,2,2,-2],  # A_3A_2
    [-4,2,2,0,2,-5,2,-1],  # D_4(a_1)A_1
    [-1,2,2,-5,2,2,2,-3],  # A_3A_1^2
    [2,2,2,-5,2,2,-3,2],   # A_2^2A_1^2
    [-6,2,2,2,2,-6,0,0],   # D_4
    [-4,2,2,0,2,-4,0,0],   # D_4(a_1)
    [2,-3,2,2,-4,2,-1,0],  # A_3A_1
    [2,2,2,-5,2,2,-2,0],   # A_2^2A_1
    [2,0,2,-4,2,2,-2,0],   # A_2^2
    [2,2,2,-4,2,-2,2,-1],  # A_2A_1^3
    [2,-3,2,2,-3,0,0,0],   # A_3
    [2,2,-3,2,-3,2,-1,0],  # A_2A_1^2
    [2,2,2,-3,0,0,0,0],    # A_2A_1
    [-1,2,2,-3,2,-2,2,-1], # A_1^4
    [2,0,2,-2,0,0,0,0],    # A_2
    [2,-1,-2,2,-2,2,-1,0], # A_1^3
    [2,0,-1,0,-1,2,-1,0],  # A_1^2
    [2,0,-1,0,0,0,0,0]     # A_1
    ];

#blocks:=[];
blocks:=[
    [[51, 1], [47, 1], [35, 1], [25, 4], [15, 1]],
    [[25, 9], [23, 1]],
    [[25, 7], [23, 1], [20, 2], [5, 2]],
    [[25, 5], [23, 2], [21, 1], [15, 2], [10, 2], [3, 2]],
    [[25, 3], [23, 1], [20, 2], [15, 4], [10, 4], [5, 2]],
    [[25, 4], [24, 2], [22, 2], [15, 2], [10, 2], [3, 1], [1, 3]],
    [[25, 2], [23, 1], [21, 1], [19, 1], [17, 2], [15, 2], [13, 1], [11, 3], [7, 2], [5, 1], [3, 2]],
    [[23, 2], [21, 1], [19, 1], [17, 1], [15, 3], [13, 2], [11, 3], [10, 2], [7, 1], [5, 1], [3, 3]],
    [[25, 2], [22, 2], [19, 1], [17, 1], [16, 2], [15, 1], [12, 2], [11, 2], [7, 1], [6, 2], [3, 1], [1, 3]],
    [[23, 1], [19, 2], [17, 3], [15, 3], [11, 1], [10, 4], [9, 1], [7, 2], [5, 1], [3, 4]],
    [[23, 1], [22, 2], [19, 1], [16, 2], [15, 1], [13, 3], [12, 2], [11, 1], [10, 2], [7, 1], [4, 2], [3, 1], [1, 3]],
    [[19, 2], [15, 5], [11, 1], [10, 8], [9, 1], [5, 7]],
    [[23, 1], [19, 1], [18, 2], [17, 1], [16, 2], [15, 2], [11, 1], [10, 4], [8, 2], [7, 1], [4, 2], [3, 2], [1, 3]],
    [[23, 1], [18, 2], [17, 3], [16, 2], [15, 1], [11, 1], [10, 2], [9, 3], [8, 2], [3, 2], [2, 4], [1, 3]],
    [[19, 1], [17, 2], [15, 3], [13, 1], [11, 3], [10, 6], [7, 2], [5, 4], [3, 3], [1, 1]],
    [[17, 1], [15, 3], [13, 2], [11, 3], [10, 6], [7, 3], [5, 8], [3, 2]],
    [[19, 1], [17, 1], [16, 2], [15, 2], [12, 2], [11, 2], [10, 6], [7, 1], [6, 2], [5, 3], [3, 1], [2, 2], [1, 3]],
    [[17, 1], [15, 1], [14, 2], [13, 2], [12, 2], [11, 1], [10, 4], [9, 2], [8, 2], [7, 1], [5, 7], [3, 2], [2, 2], [1, 1]],
    [[16, 2], [15, 1], [13, 3], [12, 2], [11, 1], [10, 2], [9, 3], [8, 4], [7, 1], [5, 7], [3, 1], [1, 3]],
    [[15, 1], [14, 2], [11, 1], [10, 10], [9, 2], [5, 15], [1, 1]],
    [[23, 1], [17, 7], [15, 1], [11, 1], [9, 7], [3, 1], [1, 14]],
    [[19, 1], [16, 4], [15, 1], [11, 6], [10, 4], [6, 4], [5, 2], [1, 10]],
    [[15, 1], [13, 2], [11, 3], [10, 8], [9, 1], [7, 2], [5, 11], [3, 5], [1, 1]],
    [[17, 1], [15, 1], [13, 6], [11, 1], [10, 2], [9, 6], [7, 1], [5, 7], [3, 1], [1, 8]],
    [[15, 1], [13, 1], [12, 2], [11, 2], [10, 8], [8, 2], [7, 1], [5, 10], [4, 2], [3, 2], [2, 2], [1, 3]],
    [[13, 3], [12, 2], [11, 1], [10, 2], [9, 3], [8, 4], [7, 5], [6, 4], [5, 3], [4, 2], [3, 2], [2, 2], [1, 3]],
    [[15, 1], [12, 4], [11, 1], [10, 6], [9, 4], [7, 1], [5, 10], [3, 5], [1, 6]],
    [[13, 3], [11, 5], [9, 3], [7, 13], [5, 3], [3, 5], [1, 6]],
    [[11, 1], [10, 6], [9, 3], [7, 5], [5, 20], [3, 5]],
    [[15, 1], [12, 2], [11, 5], [10, 4], [9, 3], [8, 2], [5, 10], [3, 1], [2, 6], [1, 6]],
    [[11, 1], [10, 6], [9, 1], [8, 4], [7, 2], [6, 2], [5, 18], [4, 2], [3, 3], [1, 3]],
    [[11, 1], [10, 4], [9, 3], [8, 4], [7, 3], [6, 2], [5, 17], [3, 3], [2, 4], [1, 3]],
    [[11, 1], [10, 6], [8, 4], [7, 5], [5, 17], [4, 4], [3, 1], [1, 6]],
    [[11, 1], [10, 2], [9, 3], [8, 6], [7, 4], [6, 4], [5, 10], [4, 2], [3, 7], [2, 4], [1, 3]],
    [[11, 1], [10, 4], [9, 3], [8, 2], [7, 4], [6, 6], [5, 13], [4, 2], [3, 1], [2, 4], [1, 6]],
    [[5, 48], [4, 2]],
    [[15, 1], [11, 9], [9, 7], [5, 10], [1, 21]],
    [[11, 1], [10, 2], [9, 7], [7, 7], [5, 17], [3, 2], [1, 14]],
    [[11, 1], [9, 6], [7, 14], [5, 7], [3, 14], [1, 8]],
    [[5, 46], [4, 2], [3, 2], [2, 2]],
    [[11, 1], [9, 3], [8, 6], [7, 8], [6, 6], [5, 3], [4, 2], [3, 7], [2, 10], [1, 6]],
    [[11, 1], [10, 2], [9, 7], [6, 14], [5, 9], [4, 2], [1, 17]],
    [[5, 46], [3, 5], [1, 3]],
    [[5, 45], [3, 4], [2, 4], [1, 3]],
    [[11, 1], [9, 1], [8, 8], [7, 8], [6, 8], [5, 1], [3, 8], [2, 8], [1, 15]],
    [[5, 38], [4, 12], [1, 10]],
    [[5, 45], [3, 1], [2, 6], [1, 8]],
    [[5, 36], [3, 20], [1, 8]],
    [[11, 1], [8, 6], [7, 14], [6, 6], [3, 2], [2, 14], [1, 21]],
    [[5, 32], [4, 8], [3, 10], [2, 10], [1, 6]],
    [[5, 45], [1, 23]],
    [[5, 30], [4, 8], [3, 13], [2, 8], [1, 11]],
    [[5, 29], [4, 6], [3, 14], [2, 14], [1, 9]],
    [[5, 25], [4, 10], [3, 14], [2, 14], [1, 13]],
    [[5, 18], [4, 12], [3, 20], [2, 20], [1, 10]],
    [[11, 1], [7, 26], [3, 1], [1, 52]],
    [[5, 29], [3, 25], [1, 28]],
    [[5, 21], [4, 16], [3, 9], [2, 14], [1, 24]],
    [[5, 14], [4, 14], [3, 23], [2, 18], [1, 17]],
    [[5, 14], [3, 50], [1, 28]],
    [[5, 7], [4, 14], [3, 28], [2, 28], [1, 17]],
    [[5, 13], [4, 32], [1, 55]],
    [[5, 3], [4, 16], [3, 27], [2, 32], [1, 24]],
    [[5, 1], [4, 12], [3, 32], [2, 32], [1, 35]],
    [[4, 8], [3, 28], [2, 48], [1, 36]],
    [[5, 1], [3, 55], [1, 78]],
    [[4, 2], [3, 27], [2, 52], [1, 55]],
    [[3, 14], [2, 64], [1, 78]],
    [[3, 1], [2, 56], [1, 133]]
    ];

#ords:=[];
ords:=[ 125, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 5, 25, 25,  25, 5, 25, 25, 5, 5, 25, 5, 5, 5, 25, 5, 5, 5, 5, 5, 5, 25, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5 ];

return [reps,tori,labels,I,II,ords,blocks];


text:
#############################################################################
##
##
#W  json.gi                  json Package                Chris Jefferson
##
##  Installation file for functions of the json package.
##
#Y  Copyright (C) 2013-2014 University of St. Andrews, North Haugh,
#Y                          St. Andrews, Fife KY16 9SS, Scotland
##

####
# Functions and variables beginning '_JSON_' are only called
# from C++ by the json package.
####

_JSON_Globals := [];

_JSON_addRef := function(obj)
  Add(_JSON_Globals, obj);
end;

_JSON_clearRefs := function()
  _JSON_Globals := [];
end;

InstallMethod(_GapToJsonStreamInternal, [IsOutputStream, IsInt],
function(o, d)
  PrintTo(o, String(d));
end );

InstallMethod(_GapToJsonStreamInternal, [IsOutputStream, IsFloat],
function(o, d)
  PrintTo(o, String(d));
end );

InstallMethod(_GapToJsonStreamInternal, [IsOutputStream, IsBool],
function(o, b)
  if b = true then
    PrintTo(o, "true");
  elif b = false then
    PrintTo(o, "false");
  else
    Error("Invalid Boolean");
  fi;
end );

InstallMethod(_GapToJsonStreamInternal, [IsOutputStream, IsString],
function(o, s)
  if IsEmpty(s) then
    if IsStringRep(s) then
      PrintTo(o, "\"\"");
    else
      PrintTo(o, "[]");
    fi;
  else
    PrintTo(o, "\"", JSON_ESCAPE_STRING(s), "\"");
  fi;
end );

InstallMethod(_GapToJsonStreamInternal, [IsOutputStream, IsList],
function(o, l)
  local i, first;
  first := true;
  PrintTo(o, "[");
  for i in l do
    if first then
      first := false;
    else
      PrintTo(o, ",");
    fi;
    _GapToJsonStreamInternal(o, i);
  od;
  PrintTo(o, "]");
end );

InstallMethod(_GapToJsonStreamInternal, [IsOutputStream, IsRecord],
function(o, r)
  local i, first;
  first := true;
  PrintTo(o, "{");
  for i in Set(RecNames(r)) do # sort for output stability across GAP sessions
    if first then
      first := false;
    else
      PrintTo(o, ",");
    fi;
    _GapToJsonStreamInternal(o, i); # a string or small integer
    PrintTo(o, " : ");
    _GapToJsonStreamInternal(o, r.(i)); # an arbitrary GAP object
  od;
  PrintTo(o, "}");
end );

InstallGlobalFunction(GapToJsonStream,
function(stream, obj)
  local streamformat;
  streamformat := PrintFormattingStatus(stream);
  SetPrintFormattingStatus(stream, false);
  _GapToJsonStreamInternal(stream, obj);
  SetPrintFormattingStatus(stream, streamformat);
end );

InstallGlobalFunction(GapToJsonString,
function(obj)
  local str, s;
  str := "";
  s := OutputTextString(str, true);
  SetPrintFormattingStatus(s, false);
  GapToJsonStream(s, obj);
  return str;
end );

InstallGlobalFunction(JsonStringToGap,
function(str)
  return JSON_STRING_TO_GAP(str);
end );

InstallGlobalFunction(JsonStreamToGap,
function(str)
  return JSON_STREAM_TO_GAP(str);
end );

ext: gi

max_stars_repo_name: gap-system/json

max_issues_repo_name: gap-system/json

max_forks_repo_name: gap-system/json


text:
expon := function(a, n, one, mul)
	local p;
	p := one;
	while n > 0 do
		if IsOddInt(n) then
			p := mul(a, p);
		fi;
		a := mul(a, a);
		n := QuoInt(n, 2);
	od;
	return p;
end;

expon(2, 10, 1, \*);
# 1024

# a more creative use of exponentiation
List([0 .. 31], n -> (1 - expon(0, n, 1, \-))/2);
# [ 0, 1, 1, 0, 1, 0, 0, 1, 1, 0, 0, 1, 0, 1, 1, 0,
#   1, 0, 0, 1, 0, 1, 1, 0, 0, 1, 1, 0, 1, 0, 0, 1 ]

ext: gap

max_issues_repo_name: seanwallawalla-forks/RosettaCodeData

max_forks_repo_name: seanwallawalla-forks/RosettaCodeData


text:
InstallGlobalFunction(TCP_AddrToString,
addr -> JoinStringsWithSeparator(List(addr{[5..8]},
                                      x -> String(INT_CHAR(x))), "."));

InstallGlobalFunction( StartTCPServer,
function(hostname, port, handlerCallback)
    local socket, addr, client, stream;
    socket := ListeningTCPSocket(hostname, port);
    while true do
        # Currently we accept connections from anyone.
        addr := IO_MakeIPAddressPort( "0.0.0.0", 0 );

        # Accept connection, and open stream.
        client := IO_accept(socket, addr);

        # TODO: prettier
        Info(InfoTCPSockets, 5, "Accepted connection from: ",
             TCP_AddrToString(addr));
        stream := AcceptInputOutputTCPStream(client);

        # Handle connection
        handlerCallback(addr, stream);
    od;
end);

InstallGlobalFunction( ListeningTCPSocket,
function(hostname, port)
    local socket, client, desc, stream, res, bindaddr, listenname;

    res := IO_gethostbyname(hostname);
    if res = fail then
        ErrorNoReturn("ListeningTCPSocket: lookup failed on address ",
                      hostname);
    fi;
    bindaddr := res.addr[1];
    listenname := res.name;

    if not IsPosInt(port) or (port > 65535) then
        ErrorNoReturn("ListeningTCPSocket:\n<port> must be ",
                      "a positive integer no greater than 65535");
    fi;

    # Create TCP socket
    Info(InfoTCPSockets, 5, "MitM server listening for connections...");
    socket := IO_socket( IO.PF_INET, IO.SOCK_STREAM, "tcp" );
    if socket = fail then
        ErrorNoReturn("ListeningTCPSocket: failed to open socket:\n",
                      LastSystemError().message);
    fi;

    res := IO_bind(socket, IO_make_sockaddr_in(bindaddr, port));
    if res = fail then
        ErrorNoReturn("ListeningTCPSocket: failed to bind:\n",
                      LastSystemError().message);
    fi;

    Info(InfoTCPSockets, 5, "MitM server listening on ", listenname, " ", port);
    # TODO: make the queue length a parameter
    IO_listen(socket, 5);
    return socket;
end);

InstallGlobalFunction( ConnectInputOutputTCPStream,
function( hostname, port )
    local lookup, sock, res, err, fio;

    if not IsString( hostname ) then
        Error("ConnectInputOutputTCPStream: <hostname> must be a string");
    fi;
    if not (IsInt(port) and port >= 0) then
        Error("ConnectInputOutputTCPStream: <port> must be a non-negative integer");
    fi;
    lookup := IO_gethostbyname( hostname );
    if lookup = fail then
        Error("ConnectInputOutputTCPStream: cannot find hostname ", hostname);
    fi;
    sock := IO_socket( IO.PF_INET, IO.SOCK_STREAM, "tcp" );
    res := IO_connect( sock, IO_make_sockaddr_in( lookup.addr[1], port ) );
    if res = fail then
        err := LastSystemError();
        IO_close(sock);
        Error("ConnectInputOutputTCPStream: ", err.message);
    else
        fio := IO_WrapFD( sock, IO.DefaultBufSize, IO.DefaultBufSize );
        return Objectify( InputOutputTCPStreamDefaultType,
                          [ fio, hostname, [ port ], false ] );
    fi;
end);

InstallGlobalFunction( AcceptInputOutputTCPStream,
function(socket_descriptor)
    local fio;
    if not (IsInt(socket_descriptor) and socket_descriptor >= 0) then
        Error("AcceptInputOutputTCPStream: argument must be a non-negative integer");
    fi;
    fio := IO_WrapFD(socket_descriptor, IO.DefaultBufSize, IO.DefaultBufSize);
    return Objectify( InputOutputTCPStreamDefaultType,
                      [ fio, "socket descriptor", [ socket_descriptor ], false ] );
end);

InstallMethod( ViewObj, "for ioTCPstream",
               [ IsInputOutputTCPStreamRep and IsInputOutputStream ],
function(stream)
    Print("<");
    if IsClosedStream(stream) then
        Print("closed ");
    fi;
    Print("input/output TCP stream to ",stream![2],":", stream![3][1], ">");
end);

InstallMethod( PrintObj, "for ioTCPstream",
               [ IsInputOutputTCPStreamRep and IsInputOutputStream ],
               ViewObj);

InstallMethod( ReadByte, "for ioTCPstream",
               [ IsInputOutputTCPStreamRep and IsInputOutputStream ],
function(stream)
    local buf;
    buf := IO_Read( stream![1], 1 );
    if buf = fail or Length(buf) = 0 then
        stream![4] := true;
        return fail;
    else
        stream![4] := true;
        return INT_CHAR(buf[1]);
    fi;
end);

InstallMethod( ReadLine, "for ioTCPstream",
               [ IsInputOutputTCPStreamRep and IsInputOutputStream ],
function( stream )
    local sofar, chunk;
    sofar := IO_Read( stream![1], 1 );
    if sofar = fail or Length(sofar) = 0 then
        stream![4] := true;
        return fail;
    fi;
    while sofar[ Length(sofar) ] <> '\n' do
        chunk := IO_Read( stream![1], 1);
        if chunk = fail or Length(chunk) = 0 then
            stream![4] := true;
            return sofar;
        fi;
        Append( sofar, chunk );
    od;
    return sofar;
end);

BindGlobal( "ReadAllIoTCPStream",
function(stream, limit)
    local sofar, chunk, csize;
    if limit = -1 then
        csize := 20000;
    else
        csize := Minimum(20000,limit);
        limit := limit - csize;
    fi;
    sofar := IO_Read(stream![1], csize);
    if sofar = fail or Length(sofar) = 0 then
        stream![4] := true;
        return fail;
    fi;
    while limit <> 0  do
        if limit = -1 then
            csize := 20000;
        else
            csize := Minimum(20000,limit);
            limit := limit - csize;
        fi;
        chunk := IO_Read( stream![1], csize);
        if chunk = fail or Length(chunk) = 0 then
            stream![4] := true;
            return sofar;
        fi;
        Append(sofar,chunk);
    od;
    return sofar;
end);

InstallMethod( ReadAll, "for ioTCPstream",
               [ IsInputOutputTCPStreamRep and IsInputOutputStream ],
               stream ->  ReadAllIoTCPStream(stream, -1) );

InstallMethod( ReadAll, "for ioTCPstream",
               [ IsInputOutputTCPStreamRep and IsInputOutputStream, IsInt ],
function( stream, limit )
    if limit < 0 then
        Error("ReadAll: negative limit not allowed");
    fi;
    return  ReadAllIoTCPStream(stream, limit);
end);

InstallMethod( WriteByte, "for ioTCPstream",
               [ IsInputOutputTCPStreamRep and IsInputOutputStream, IsInt ],
function(stream, byte)
    local ret,s;
    if byte < 0 or 255 < byte  then
        Error( "<byte> must an integer between 0 and 255" );
    fi;
    s := [CHAR_INT(byte)];
    ConvertToStringRep( s );
    ret := IO_Write( stream![1], s );
    if ret <> 1 then
        return fail;
    else
        return true;
    fi;
end);

InstallMethod( WriteLine, "for ioTCPstream",
               [ IsInputOutputTCPStreamRep and IsInputOutputStream, IsString ],
function( stream, string )
    return IO_WriteLine( stream![1], string );
end);

InstallMethod( WriteAll, "for ioTCPstream",
               [ IsInputOutputTCPStreamRep and IsInputOutputStream, IsString ],
function( stream, string )
    local byte;
    for byte in string  do
        if WriteByte( stream, INT_CHAR(byte) ) <> true  then
            return fail;
        fi;
    od;
    return true;
end);

InstallMethod( IsEndOfStream, "iostream",
               [ IsInputOutputTCPStreamRep and IsInputOutputStream ],
stream -> not IO_HasData( stream![1] ) );
# TODO: when does this return true? -MT

InstallMethod( CloseStream, "for ioTCPstream",
               [ IsInputOutputTCPStreamRep and IsInputOutputStream ],
function(stream)
    IO_Close( stream![1] );
    SetFilterObj( stream, IsClosedStream );
end);

InstallMethod( FileDescriptorOfStream, "for ioTCPstream",
               [ IsInputOutputTCPStreamRep and IsInputOutputStream ],
               stream -> IO_GetFD( stream![1] ) );

max_stars_repo_name: markuspf/MathsInTheMiddle

max_issues_repo_name: markuspf/MathsInTheMiddle

max_forks_repo_name: markuspf/MathsInTheMiddle


text:
# Copyright (c) 2018-2021, Carnegie Mellon University
# See LICENSE for details

IsContainer := x -> IsRec(x) and IsBound(x.isContainer) and x.isContainer;

Class(BaseContainer, BaseOperation, rec(

    isContainer := true,

    new := meth(self, spl)
        local res;
	res := SPL(WithBases(self, rec(_children:=[spl])));
	res.dimensions := res.dims();
	return res;
    end,

    dims := meth(self) return self._children[1].dims(); end,
    area := meth(self) return self._children[1].area(); end,

    isPermutation := meth(self) return IsPermutationSPL(self._children[1]); end,
    isReal := meth(self) return IsRealSPL(self._children[1]); end,
    toAMat := meth(self) return AMatSPL(self._children[1]); end,

    transpose := self >>
        CopyFields(self, rec(_children:=[self._children[1].transpose()],
	                     dimensions:=Reversed(self.dimensions))),
    conjTranspose := self >>
        CopyFields(self, rec(_children:=[self._children[1].conjTranspose()],
	                     dimensions:=Reversed(self.dimensions))),

    normalizedArithCost := self >> self._children[1].normalizedArithCost(),
));


text:
#
# Read("~/Workspace/Chevalley.gap/init.gi"); Read(Filename(home_dir,"load.gi")); Read(Filename(test_dir,"algU.test.gi"));
#
# Read("~/Workspace/Chevalley.gap/init.gi"); Read(Filename(test_dir,"algU.test.init.gi")); Read(Filename(test_dir,"algU.test.gi"));
#
# Read(Filename(test_dir,"algU.test.gi"));
#

sys:=AlgebraicU(ChevalleyAdj("F",4,GF(2)));
Print("Created AlgebraicU (1) ",sys,"\n");
Print("\t[",IsAlgebraicU(sys)=true,"] IsAlgebraicU(sys)=true\n");

sys:=AlgebraicU("F",4,GF(2));
Print("Created AlgebraicU (2) ",sys,"\n");
Print("\t[",IsAlgebraicU(sys)=true,"] IsAlgebraicU(sys)=true\n");


text:
##  Copyright (c) 2018-2021, Carnegie Mellon University
##  See LICENSE for details

max_stars_repo_name: franzfranchetti/spiral-package-fftx

max_issues_repo_name: franzfranchetti/spiral-package-fftx

max_forks_repo_name: franzfranchetti/spiral-package-fftx


text:
#
# Read("~/Workspace/groupsSB/epi/B2/case.5.gi");
#

type:="B";
rank:=2;
nr_pos_roots:=4;

Read("~/Workspace/groupsSB/epi/group.gi");

highest_weight:=[0,2];# corresponding highest weight module is the Lie algebra

Read("~/Workspace/groupsSB/epi/ext.gi");

#
# p>3
#

getRep:=function(k,t)
    local u,ua,ub,uab,uabb;
    #ua:=ext_root_group(k,1,t);
    ub:=ext_root_group(k,2,t);
    #uab:=ext_root_group(k,3,t);
    uabb:=ext_root_group(k,4,t);
    u:=ub*uabb;

    return u;
end;

#
# k:=3; # power of exterior algebra
#
handle:=function(k)
    local id_mat,u,e,h,h1,h2,ese,evh1,esh1,evh2,esh2,esh01,index_ev01,esh02,index_ev02,si,si1,si2,inter;
    u:=getRep(k,1);
    id_mat:=u^0;
    e:=u-id_mat;
    ese:=Eigenspaces(Rationals,e)[1]; #eigenvalues 0, centralizer

    # torus
    # centralizer of T1
    h1:=ext_e(k,cb0[7]);
    esh1:=Eigenspaces(Rationals,h1);
    evh1:=Eigenvalues(Rationals,h1);
    esh01:=[];
    index_ev01:=Position(evh1,0);
    esh01:=esh1[index_ev01];

    # centralizer of T1
    h2:=ext_e(k,cb0[8]);
    esh2:=Eigenspaces(Rationals,h2);
    evh2:=Eigenvalues(Rationals,h2);
    esh02:=[];
    index_ev02:=Position(evh2,0);
    esh02:=esh2[index_ev02];

    #
    # sum and intersection
    #
    #return [ese,esh01,esh02];
    si1:=SumIntersectionMat(Basis(ese),Basis(esh01));
    si2:=SumIntersectionMat(Basis(ese),Basis(esh02));
    si:=SumIntersectionMat(si1[2],si2[2]);
    inter:=si[2];
    return inter;
    #return [inter,esh01,esh02];
end;

max_stars_repo_name: iuliansimion/groupsSB

max_issues_repo_name: iuliansimion/groupsSB

max_forks_repo_name: iuliansimion/groupsSB


text:
LucasLehmer := function(n)
    local i, m, s;
    if n = 2 then
        return true;
    elif not IsPrime(n) then
        return false;
    else
        m := 2^n - 1;
        s := 4;
        for i in [3 .. n] do
            s := RemInt(s*s, m) - 2;
        od;
        return s = 0;
    fi;
end;

Filtered([1 .. 2000], LucasLehmer);
[2, 3, 5, 7, 13, 17, 19, 31, 61, 89, 107, 127, 521, 607, 1279]

max_stars_repo_name: mullikine/RosettaCodeData


text:
# Copyright (c) 2018-2021, Carnegie Mellon University
# See LICENSE for details

Class(VectorCodegen, DefaultCodegen, rec(

    Formula := meth(self, o, y, x, opts)
        local icode, datas, prog, params, sub, initsub, io, initcode;

        o := SumsUnification(o.child(1), opts);

        [x, y] := self.initXY(x, y, opts);

        o :=  Process_fPrecompute(o, opts);

        params := Set(Filtered(Collect(o, @(1, [param, var])), x -> ObjId(x)=param or IsParallelLoopIndex(x)));

        datas := Filtered(Collect(o, FDataOfs), x->IsBound(x.var.init));
        o := BlockSumsOpts(o, opts);
        icode := self(o, y, x, opts);
        if IsBound(opts.finalSReduce) and opts.finalSReduce then
            icode := SReduce(icode, opts);   #SReduce -> ESReduce sequence is faster than just ESReduce
            icode := ESReduce(icode, opts);
        fi;
        icode := RemoveAssignAcc(icode);
        icode := BlockUnroll(icode, opts);
        icode := DeclareHidden(icode);
        if IsBound(opts.isFixedPoint) and opts.isFixedPoint then
            icode := FixedPointCode(icode, opts.bits, opts.fracbits);
        fi;

        io := When(x=y, [x], [y, x]);
        sub := Cond(IsBound(opts.subName), opts.subName, "transform");
        initsub := Cond(IsBound(opts.subName), Concat("init_", opts.subName), "init");
        icode := func(TVoid, sub, Concatenation(io, params), icode);

        if IsBound(opts.generateInitFunc) and opts.generateInitFunc then
	    initcode := chain(List(datas, x -> SReduce(x.var.init, opts)));
            prog := program(
                decl(List(datas, x->x.var),
                    chain(
                        func(TVoid, initsub, params :: Set(Collect(initcode,param)), initcode),
                        icode
                    )));
        else
            prog := program( func(TVoid, initsub, params, chain()), icode);
        fi;

        # FF: I really don't know why suddenly AVX_8x32f requires me to do that !!
        #if IsBound(opts.vector.isas) then
        #    prog := FoldR(opts.isas, (r, e) -> e.fixProblems(r, opts), prog);
        #fi;
        #if IsBound(opts.vector.isa.fixProblems) then prog := opts.vector.isa.fixProblems(prog, opts); fi;

        prog.dimensions := o.dims();
        if IsBound(opts.finalSReduce) and opts.finalSReduce then
            icode := SReduce(icode, opts);   #SReduce -> ESReduce sequence is faster than just ESReduce
            icode := ESReduce(icode, opts);
        fi;
        return prog;
    end,

###########################################################################

    NoPull := (self, o, y, x, opts) >> self(o.child(1), y, x, opts),

    VContainer := (self, o, y, x, opts) >>
        self(o.child(1), y, x, CopyFields(opts, rec(
            vector := rec(
                isa  := o.isa,
                SIMD := LocalConfig.cpuinfo.SIMDname )))),

    # VirtualPad changes dimensions of the SPL object but does not
    # affect the code
    VirtualPad := (self, o, y, x, opts) >> self(o.child(1), y, x, opts),

    VPrm_x_I := (self, o, y, x, opts) >> self(VTensor(Prm(o.func), o.v), y, x, opts),

    VPerm := (self, o, y, x, opts) >> o.code(y, x), # these codes are generated

    #VTensor for multi inputs
    VTensor := (self, o, y, x, opts) >> let(
        CastToVect := p -> StripList(List(Flat([p]), e -> tcast(TPtr(TVect(opts.vector.isa.t.t, o.vlen)), e))),
        self(o.child(1), CastToVect(y), CastToVect(x), opts)),

    # ---------------
    # Gather
    # ---------------
    VGath := (self, o, y, x, opts) >> Cond(IsUnalignedPtrT(x.t),
        self(VGath_u(fTensor(o.func, fBase(o.v, 0)), o.v), y, x, opts),
        self(VTensor(Gath(o.func), o.v), y, x, opts)),

    VGath_u := (self, o, y, x, opts) >> let(
        j    := Ind(o.func.domain()),
        xofs := o.func.at(j),
        loop(j, j.range,
            opts.vector.isa.loadCont(o.v, y, j, x, xofs, imod(xofs, o.v), opts))),

    VGath_dup := (self, o, y, x, opts) >> let(
        v := o.v, func := o.func.lambda(), j := Ind(o.func.domain()),
        isa := opts.vector.isa,
        loop(j, j.range,
             isa.dupload(vtref(isa.t, y, j), nth(x, func.at(j))))),

    VReplicate := (self, o, y, x, opts) >> let(
	v := o.v, isa := opts.vector.isa,
        chain(List([0..v-1], i -> isa.duploadn(vtref(isa.t, y, i), vtref(isa.t, x, 0), i+1)))),

    _VHAdd := (self,xlist,opts) >> let(
       l := Length(xlist),
       Cond(l=2, opts.vector.isa.hadd(xlist[1], xlist[2]),
	    # else
	         opts.vector.isa.hadd(self._VHAdd(xlist{[1..l/2]}, opts),
		                      self._VHAdd(xlist{[l/2+1..l]}, opts)))),

    VHAdd := (self, o, y, x, opts) >> let(v := o.v, isa := opts.vector.isa,
        assign(vtref(isa.t, y, 0), self._VHAdd(List([0..v-1], i -> vtref(isa.t, x, i)), opts))),

    VGath_zero := (self, o, y, x, opts) >> self(VGath(fAdd(o.N, o.n, 0), o.v), y, x, opts),

    VScat_sv := meth(self, o, y, x, opts)
        local v, sv, func, nv1, rem, ii, id, svstore, isa;
        [v, sv, func] := [o.v, o.sv, o.func.lambda()];
        isa := opts.vector.isa;
        nv1 := idiv(func.domain()*sv, v);
        rem := o.getConstantRem();
        ii  := Ind(nv1);
        id  := 1+Log2Int(sv);
        svstore  := (n, id2, idx) -> isa.svstore[id][id2](
            List([0..n-1], i -> nth(y, sv*func.at(i + (v/sv)*idx))),
            vtref(isa.t, x, idx), opts);
        return chain(
            loop(ii, ii.range, svstore(v/sv, v/sv, ii)),
            When(rem=0, [],    svstore(rem, rem, nv1)));
    end,

    VScat_svAcc := meth(self, o, y, x, opts)
        local v, sv, func, nv1, rem, ii, id, svaccstore, tmp, tmp2, isa;
        [v, sv, func] := [o.v, o.sv, o.func.lambda()];
        nv1 := idiv(func.domain()*sv, v);
        #ESReduce should do the equivalent of an EvalScalar if possible
        #and maybe come up with smarter reductions if not possible
        # rem := ESReduce(imod(func.domain()*sv, v) / sv, opts);  <-- keep this??
        rem := o.getConstantRem();
        isa := opts.vector.isa;
        ii  := Ind(nv1);
        id  := 1+Log2Int(sv);
        tmp := TempVar(isa.t);
        tmp2:= TempVar(isa.t);
        svaccstore  := (n, id2, idx) -> chain(
            isa.svload[id][id2](
                tmp,
                List([0..n-1], i -> nth(y, sv*func.at(i + (v/sv)*idx))), opts),
            assign(tmp2, tmp + vtref(isa.t, x, idx)),
            isa.svstore[id][id2](
                List([0..n-1], i -> nth(y, sv*func.at(i + (v/sv)*idx))),
                tmp2, opts));
        return chain(
            loop(ii, ii.range, svaccstore(v/sv, v/sv, ii)),
            When(rem=0, [],    svaccstore(rem, rem, nv1)));
    end,

    VGath_sv := meth(self, o, y, x, opts)
        local v, sv, func, nv1, rem, ii, id, svload, isa;
        [v, sv, func] := [o.v, o.sv, o.func.lambda()];
        nv1 := idiv(func.domain()*sv, v);
        rem := o.getConstantRem();
        isa := opts.vector.isa;
        ii := Ind(nv1);
        id := 1+Log2Int(o.sv);
        svload  := (n, id2, idx) -> isa.svload[id][id2](
            vtref(isa.t, y, idx),
            List([0..n-1], i -> nth(x, sv*func.at(i + (v/sv)*idx))), opts);
        return chain(
            loop(ii, ii.range, svload(v/sv, v/sv, ii)),
            When(rem=0, [],    svload(rem, rem, nv1)));
    end,

    RCVGath_sv := meth(self, o, y, x, opts)
        local v, sv, func, nv1, res, ii, id, svload, n, isa;
        [v, sv, func] := [o.v, o.sv, fTensor(o.func, fId(2*o.sv)).lambda()];
        n := o.func.domain()*sv;
        nv1 := idiv(n, v);
        res := EvalScalar((n - v*nv1)/sv);
        ii  := Ind(2*nv1);
        id := Log2Int(2*sv)+1;
        isa := opts.vector.isa;
        svload := (n,id2, idx) -> isa.svload[id][id2](
            vtref(isa.t, y, idx),
            List([0..n-1], i -> nth(x, func.at(2*i*sv + v*idx))), opts);
        # FF: NOTE: This strength reduction call should not be necessary. However, looks like at this point SAR requires it
        return RulesMergedStrengthReduce(chain(
            loop(ii, ii.range, svload(v/sv, v/id, ii)),
            Cond(res=0,         [  ],
                 sv*res <= v/2, [ svload(res, res, 2*nv1),
                          assign(vtref(isa.t, y, (2*nv1+1)), isa.t.zero()) ],
                        [ svload(v/sv, v/id, 2*nv1),
                  svload(res-v/(2*sv), res-v/id, 2*nv1+1) ])));
    end,

    RCVScat_sv := meth(self, o, y, x, opts)
        local v, sv, func, nv1, res, ii, id, svstore, n, isa;
        [v, sv, func] := [o.v, o.sv, fTensor(o.func, fId(2*o.sv)).lambda()];
        n := o.func.domain()*sv;
        nv1 := idiv(n, v);
        res := EvalScalar((n - v*nv1)/sv);
        ii  := Ind(2*nv1);
        id := Log2Int(2*sv)+1;
        isa := opts.vector.isa;
        svstore := (n,id2, idx) -> isa.svstore[id][id2](
        List([0..n-1], i -> nth(y, func.at(2*i*sv + v*idx))),
        vtref(isa.t, x, idx), opts);
        return chain(
            loop(ii, ii.range, svstore(v/sv, v/id, ii)),
            Cond(res=0,         [  ],
                 sv*res <= v/2, [ svstore(res, res, 2*nv1) ],
                        [ svstore(v/sv, v/id, 2*nv1),
                  svstore(res-v/(2*sv), res-v/id, 2*nv1+1) ]));
    end,

   VStretchGath := (self, o, y, x, opts) >> let(
       v := o.v,
       func := o.func.lambda(),
       rat := func.domain() / o.part,
       nv1 := idiv(rat, v),
       res := EvalScalar(rat - v*nv1),
       ii := Ind(),
       it := Ind(),
       xbase := rat * it,
       ybase := (_roundup(rat, v) / v) * it,
       isa := opts.vector.isa,
       svload := isa.svload[1][v],

       footer := When(res=0, skip(),
           let(svloadR := isa.svload[1][res],
               svloadR(vtref(isa.t, y, nv1 + ybase), List([0..res-1],
                       i->nth(x, func.at(nv1*v + i + xbase))), opts))),
       loop(it, o.part,
           chain(
               loop(ii, nv1,
                   svload(vtref(isa.t, y, ii + ybase),
                       List([0..v-1], i->nth(x, func.at(v * ii + i + xbase))), opts)),
               footer))
    ),

   vRCStretchGath := (self, o, y, x, opts) >> let(
       v := o.v/2,
       func := o.func.lambda(),
       rat := func.domain() / o.part,
       nv1 := idiv(rat, v),
       res := EvalScalar(rat - v*nv1),
       ii := Ind(),
       it := Ind(),
       xbase := rat * it,
       ybase := (_roundup(rat, v) / v) * it,
       isa := opts.vector.isa,
       svload := isa.svload[2][v],
       footer := When(res=0, skip(),
           let(svloadR := isa.svload[2][res],
               svloadR(vtref(isa.t, y, nv1 + ybase), List([0..res-1], i -> nth(x, 2*func.at(nv1*v + i + xbase))), opts))),
       loop(it, o.part,
           chain(
               loop(ii, nv1,
                   svload(vtref(isa.t, y, ii + ybase), List([0..v-1], i -> nth(x, 2*func.at(v*ii + i + xbase))), opts)),
               footer))
    ),

   RCVStretchGath := (self, o, y, x, opts) >> let(
       v    := o.v,
       func := o.func.lambda(),
       rat  := o.func.domain()/o.part,
       nv1  := idiv(rat, v),
       res  := EvalScalar(rat-v*nv1),
       ii   := Ind(),
       it   := Ind(),
       isa  := opts.vector.isa,
       svload := isa.svload[2][v/2],
       ybase := (2 * _roundup(rat, v) / v) * it,
       xbase := rat * it,

       footer := Cond(
           res=0,
              skip(),

           res<=v/2, let(svloadR := isa.svload[2][res],
               chain(
                   svloadR(vtref(isa.t, y, 2*nv1   + ybase), List([0..res-1], i -> nth(x, 2*func.at(nv1*v + i + xbase))), opts),
                   assign (vtref(isa.t, y, 2*nv1+1 + ybase), isa.t.zero()))),

           let(svloadR := isa.svload[2][res-v/2],
               chain(
                   svload (vtref(isa.t, y, 2*nv1   + ybase), List([0..v/2-1],   i -> nth(x, 2*func.at(nv1*v + i + xbase))), opts),
                   svloadR(vtref(isa.t, y, 2*nv1+1 + ybase), List([v/2..res-1], i -> nth(x, 2*func.at(nv1*v + i + xbase))), opts)))
       ),

       loop(it, o.part,
           chain(
               loop(ii, 2*nv1,
                   svload(vtref(isa.t, y, ii + ybase), List([0..v/2-1], i->nth(x, 2*func.at(ii*(v/2) + i + xbase))), opts)),
           footer))
    ),

    ##
    _VScat_pc := (self, N, n, ofs, v, y, x, xofs, opts) >> Checked(IsPosInt0Sym(n), let(isa := opts.vector.isa,
        nv1 := idiv(n, v),
	res := imod(n, v),
	i   := Ind(nv1),
        chain(loop(i, nv1,        isa.storeCont(v,   y, v*i   + ofs, imod(ofs, v), x, xofs +   i, opts)),
              Cond(res=0, skip(), isa.storeCont(res, y, v*nv1 + ofs, imod(ofs, v), x, xofs + nv1, opts)))
    )),

    # NOTE: _pcAcc is a hack
    _VScat_pcAcc := (self, N, n, ofs, v, y, x, xofs, opts) >> Checked(IsPosInt0Sym(n), let(isa := opts.vector.isa,
        nv1 := idiv(n, v),
	res := imod(n, v),
	i   := Ind(nv1),
        chain(loop(i, nv1,        isa.storeContAcc(v,   y, v*i   + ofs, imod(ofs, v), x, xofs +   i, opts)),
              Cond(res=0, skip(), isa.storeContAcc(res, y, v*nv1 + ofs, imod(ofs, v), x, xofs + nv1, opts)))
    )),

    _VGath_pc := (self, N, n, ofs, v, y, yofs, x, opts) >> Checked(IsPosInt0Sym(n), let(isa := opts.vector.isa,
        nv1 := idiv(n, v),
	res := imod(n, v),
        i   := Ind(nv1),
        chain(loop(i, nv1,        isa.loadCont(v,   y, yofs +   i, x, v*i + ofs,   imod(ofs, v), opts)),
              When(res=0, skip(), isa.loadCont(res, y, yofs + nv1, x, v*nv1 + ofs, imod(ofs, v), opts)))
    )),

    VScat_pc    := (self, o, y, x, opts) >> self._VScat_pc   (o.N, o.n, o.ofs, o.v, y, x, 0, opts),
    VScat_pcAcc := (self, o, y, x, opts) >> self._VScat_pcAcc(o.N, o.n, o.ofs, o.v, y, x, 0, opts),
    VGath_pc    := (self, o, y, x, opts) >> self._VGath_pc   (o.N, o.n, o.ofs, o.v, y, 0, x, opts),

    ##
    IxVGath_pc := (self, o, y, x, opts) >> Checked(IsPosInt0(o.n), let(
	nn := _roundup(o.n, o.v)/o.v,
	jj := Ind(),
	chain(Cond(IsPosInt0(o.k) and IsPosInt0(o.ofs) and IsPosInt0(o.N),
	     # if all values are constant, we fully unroll to keep alignments constant
	     List([0..o.k-1], jj -> self._VGath_pc(o.N, o.n, o.ofs + o.N*jj, o.v, y, nn*jj, x, opts)),
	     # no need to fully unroll, alignment will still be unknown
	     loop(jj, o.k,  	    self._VGath_pc(o.N, o.n, o.ofs + o.N*jj, o.v, y, nn*jj, x, opts))))
    )),
    IxVScat_pc := (self, o, y, x, opts) >> Checked(IsPosInt0(o.n), let(
	nn := _roundup(o.n, o.v)/o.v,
	jj := Ind(),
	chain(Cond(IsPosInt0(o.k) and IsPosInt0(o.ofs) and IsPosInt0(o.N),
	     # if all values are constant, we fully unroll to keep alignments constant
	     List([0..o.k-1], jj -> self._VScat_pc(o.N, o.n, o.ofs + o.N*jj, o.v, y, x, nn*jj, opts)),
	     # no need to fully unroll, alignment will still be unknown
	     loop(jj, o.k,  	    self._VScat_pc(o.N, o.n, o.ofs + o.N*jj, o.v, y, x, nn*jj, opts))))
    )),
    ##
    _RCVGath_pc := (self, N, n, ofs, v, y, yofs, x, opts) >> let(
        nv1 := idiv(n, v), res := imod(n, v), isa := opts.vector.isa,
        chain(self._VGath_pc(2*N, 2*n, 2*ofs, v, y, 2*yofs, x, opts),
	      When(res > v/2, skip(),
		   assign(vtref(isa.t, y, 2*yofs + 2*nv1 + 1), isa.t.zero()))) # extra 0 pad is needed
    ),
    _RCVScat_pc := (self, N, n, ofs, v, y, x, xofs, opts) >> let(
        nv1 := idiv(n, v), res := imod(n, v),
        self._VScat_pc(2*N, 2*n, 2*ofs, v, y, x, 2*xofs, opts) # no extra 0 pads unlike in _RCVGath_pc case
    ),
    ##
    IxRCVGath_pc := (self, o, y, x, opts) >> Checked(IsPosInt0(o.n), let(
	nn := _roundup(o.n, o.v)/o.v,
	jj := Ind(),
	Cond(IsPosInt0(o.k) and IsPosInt0(o.ofs) and IsPosInt0(o.N),
	     # if all values are constant, we fully unroll to keep alignments constant
	     chain(List([0..o.k-1], jj -> self._RCVGath_pc(o.N, o.n, o.ofs + o.N*jj, o.v, y, nn*jj, x, opts))),
	     # no need to fully unroll, alignment will still be unknown
	     loop(jj, o.k,                self._RCVGath_pc(o.N, o.n, o.ofs + o.N*jj, o.v, y, nn*jj, x, opts)))
    )),
    IxRCVScat_pc := (self, o, y, x, opts) >> Checked(IsPosInt0(o.n), let(
	nn := _roundup(o.n, o.v)/o.v,
	jj := Ind(),
	Cond(IsPosInt0(o.k) and IsPosInt0(o.ofs) and IsPosInt0(o.N),
	     # if all values are constant, we fully unroll to keep alignments constant
	     chain(List([0..o.k-1], jj -> self._RCVScat_pc(o.N, o.n, o.ofs + o.N*jj, o.v, y, x, nn*jj, opts))),
	     # no need to fully unroll, alignment will still be unknown
	     loop(jj, o.k,                self._RCVScat_pc(o.N, o.n, o.ofs + o.N*jj, o.v, y, x, nn*jj, opts)))
    )),

    # ---------------
    # Scatter
    # ---------------
    VScat := (self, o, y, x, opts) >> Cond(IsUnalignedPtrT(y.t),
        self(VScat_u(fTensor(o.func, fBase(o.v, 0)), o.v), y, x, opts),
        self(VTensor(Scat(o.func), o.v), y, x, opts)),

    VScat_u := (self, o, y, x, opts) >> let(
        j    := Ind(o.func.domain()),
	yofs := o.func.at(j),
        loop(j, j.range,
            opts.vector.isa.storeCont(o.v, y, yofs, imod(yofs, o.v), x, j, opts))),

    VScatAcc := (self, o, y, x, opts) >>
	Cond(IsUnalignedPtrT(y.t),
             let(j      := Ind(o.func.domain()),
		 yofs   := o.func.at(j),
		 loop(j, j.range,
		     opts.vector.isa.storeContAcc(o.v, y, o.v*yofs, 0, x, j, opts))),
	     # else
	     self._acc(self(VScat(o.func, o.v),y,x,opts), y)),

    VScatAcc_u := (self, o, y, x, opts) >> let(
	j      := Ind(o.func.domain()),
	yofs   := o.func.at(j),
	nfunc  := fTensor(o.func, fBase(o.v, 0)),
	loop(j, j.range,
	    opts.vector.isa.storeContAcc(o.v, y, yofs, imod(yofs, o.v), x, j, opts))),

    VScat_zero := (self, o, y, x, opts) >> let(
	i := Ind(), j := Ind(), v := o.v, isa := opts.vector.isa,
        chain(
            loop(i, o.n,     assign(vtref(isa.t, y, i    ),  vtref(isa.t, x, i))),
            loop(j, o.N-o.n, assign(vtref(isa.t, y, o.n+j),  isa.t.zero())))),

    VStretchScat := (self, o, y, x, opts) >> let(
        v := o.v,
        func := o.func.lambda(),
        rat := func.domain() / o.part,
	nv1 := idiv(rat, v),
	res := EvalScalar(rat - v*nv1),
        ii := Ind(),
	it := Ind(),
	xbase := rat * it,
	ybase := it * ((_roundup(rat, v) / v)),
	isa := opts.vector.isa,
        svstore := isa.svstore[1][v],

        footer := Cond(
            res=0, skip(),
            let(svstoreR := isa.svstore[1][res],
                svstoreR(List([0..res-1], i->nth(y, func.at(nv1*v + i + xbase))), vtref(isa.t, x, nv1 + ybase), opts))
        ),
        loop(it, o.part,
            chain(
                loop(ii, nv1,
                    svstore(List([0..v-1], i->nth(y, func.at(v*ii + i + xbase))), vtref(isa.t, x, ii + ybase), opts)),
                footer)
        )
    ),

    vRCStretchScat := (self, o, y, x, opts) >> let(
        v := o.v/2,
        func := o.func.lambda(),
        rat := func.domain() / o.part,
	nv1 := idiv(rat, v),
	res := EvalScalar(rat-v*nv1),
        ii := Ind(),
	it := Ind(),
	ybase := it * (_roundup(rat, v) / v),
	xbase := rat * it,
	isa := opts.vector.isa,
        svstore := isa.svstore[2][v],

        footer := Cond(
            res=0, skip(),
            let(svstoreR := isa.svstore[2][res],
                svstoreR(List([0..res-1], i -> nth(y, 2 * func.at(nv1*v + i + xbase))), vtref(isa.t, x, nv1 + ybase), opts))
        ),
        loop(it, o.part,
            chain(
                loop(ii, nv1,
                    svstore(List([0..v-1], i -> nth(y, 2 * func.at(v*ii + i + xbase))), vtref(isa.t, x, ii + ybase), opts)),
                footer)
        )
    ),

    RCVStretchScat := (self, o, y, x, opts) >> let(
        v    := o.v,
        func := o.func.lambda(),
        rat  := func.domain()/o.part,
        nv1  := idiv(rat, v),
        res  := EvalScalar(rat-v*nv1),
        ii := Ind(),
        it := Ind(),
        ybase := 2 * (_roundup(rat, v) / v) * it,
	xbase := rat * it,
	isa := opts.vector.isa,
        svstore := isa.svstore[2][v/2],

        footer := Cond(
            res=0,
                skip(),

            res <= v/2, let(svstoreR := isa.svstore[2][res],
                svstoreR(List([0..res-1], i->nth(y, 2 * func.at(nv1*v + i + xbase))), vtref(isa.t, x, 2*nv1 + ybase), opts)),

            let(svstoreR := isa.svstore[2][res-v/2],
                chain(
                  svstore (List([0..v/2-1],   i->nth(y, 2 * func.at(nv1*v + i + xbase))), vtref(isa.t, x, 2*nv1   + ybase), opts),
                  svstoreR(List([v/2..res-1], i->nth(y, 2 * func.at(nv1*v + i + xbase))), vtref(isa.t, x, 2*nv1+1 + ybase), opts))
            )
        ),
        loop(it, o.part,
            chain(
                loop(ii, 2*nv1,
                    svstore(List([0..v/2-1], i->nth(y, 2 * func.at(v/2*ii + i + xbase))), vtref(isa.t, x, ii + ybase), opts)),
            footer)
        )
    ),

    # ---------------
    # Diagonal
    # ---------------
    VDiag := (self, o, y, x, opts) >>
        self(VTensor(Diag(VData(o.element, o.v)), o.v), y, x, opts),

    VDiag_x_I := (self,o,y,x,opts) >>
        self(VTensor(Diag(o.element), o.v), y, x, opts),

    # need to do VRef into the twiddles
    VRCDiag := (self, o, y, x, opts) >>
        self(VTensor(RCDiag(o.element), o.v), y, x, opts),

    VBlk := (self, o, y, x, opts) >> self(VTensor(Blk(o.velement()), o.v), y, x, opts),

    RCVBlk := (self, o, y, x, opts) >> let(
        #self(BlockMat(MapMat(o.velement(), el->RCVDiag(el, o.v))), y, x, opts),
        isa := opts.vector.isa,
        cx_mul := isa.mul_cx(opts),
        j   := Ind(),
        i   := Ind(),
        t   := TempVar(isa.t),
        u   := TempVar(isa.t),
        mat := o.velement(),
        d   := Dat(mat.t),
	data(d, mat,
            loop(j, Rows(o) / o.v,
		decl([t, u], chain( # FF: fixed for v>2
                    assign(t, 0),
                    loop(i, Cols(o) / o.v, chain(
			cx_mul(u, vtref(isa.t, x, i), nth(nth(d, j), i)),
			assign(t, add(t, u)))
		    ),
                    assign(vtref(isa.t, y, j), t)
		))
    ))),

    # dv := VData(o.element, o.v);
    RCVDiag := (self, o, y, x, opts) >> let(
        i     := Ind(),
        isa   := opts.vector.isa,
        cxmul := isa.mul_cx(opts),
        loop(i, Rows(o)/o.v,
             cxmul(vtref(isa.t, y, i), vtref(isa.t, x, i), o.element.at(i)))
    ),

    RCVOnlineDiag := (self, o, y, x, opts) >> let(
        isa        := opts.vector.isa,
        cxmul      := isa.mul_cx(opts),
        cxmul_conj := isa.mul_cx_conj(opts),
	cc         := o.element.computeWithOps(cxmul, cxmul_conj),
	decl(cc.values, chain(
	    cc.code,
	    List([1..Length(cc.values)], i -> cxmul(vtref(isa.t, y, i-1), cc.values[i], vtref(isa.t, x, i-1)))
	))
    ),

    RCVDiagSplit := (self, o, y, x, opts) >> let(
        isa := opts.vector.isa,
        i   := Ind(),
        yy  := vtref(isa.t, y, i),
        xx  := vtref(isa.t, x, i),
        t   := var.fresh_t("U", isa.t),
        t2  := var.fresh_t("U", isa.t),
        loop(i, Rows(o)/o.v,
	    decl([t, t2], chain(
                isa.swap_cx(t, xx, opts),
                assign(yy, add(mul(o.element.at(2*i), xx), mul(o.element.at(2*i+1), t))))))
    ),

    VS := meth(self, o, y, x, opts)
        local xv, yv, i, n, isa, u, w;
	isa := opts.vector.isa;
        xv := tcast(TPtr(TVect(x.t.t, o.v)), x);
        yv := tcast(TPtr(TVect(y.t.t, o.v)), y);
        n := o.n / o.v;
        i := Ind();
	u := var.fresh_t("U", TVect(x.t.t, o.v));
        if o.transposed then
	    return decl([u], chain(
		loop(i, n-1, chain(
		    isa.bin_shl2(u, [nth(xv,i), nth(xv, i+1)], opts),
                    assign(nth(yv, i+1), add(u, nth(xv, i+1))))
		),
		isa.bin_shl1(u, nth(xv, 0), opts),
                assign(nth(yv, 0), add(u, nth(xv, 0)))
	    ));
        else
	    return decl([u], chain(
                loop(i, n-1, chain(
                    isa.bin_shr2(u, [nth(xv, i), nth(xv, i+1)], opts),
                    assign(nth(yv, i), add(u, nth(xv, i))))
		),
                isa.bin_shr1(u, nth(xv, n-1), opts),
                assign(nth(yv, n-1), add(u, nth(xv, n-1)))));
        fi;
    end,

    VO1dsJ := meth(self, o, y, x, opts)
        local xv, yv, i, n, isa, t;
        isa := opts.vector.isa;
        t   := Checked( IsVecT(isa.t) and isa.t.size = o.v, TPtr(isa.t));
        xv  := tcast(t, x);
        yv  := tcast(t, y);
        n   := o.n / o.v;
	i   := Ind(n-1);
	return chain(
	    loop(i, n-1, isa.bin_shrev(nth(yv, i+1), [nth(xv, n-i-1), nth(xv, n-i-2)], opts)),
            isa.bin_shrev(nth(yv, 0), [isa.t.zero(), nth(xv, n-1)], opts));
    end,

    VScale := (self, o, y, x, opts) >>
        self(VDiag(fConst(TReal, Rows(o), o.s), o.v) * o.child(1), y, x, opts),

    VOLMultiplication := (self, o, y, x, opts) >>
        self(VTensor(OLMultiplication(o.rChildren()[1], o.rChildren()[2]),  o.rChildren()[3]), y, x, opts),

    VRCOLMultiplication := (self, o, y, x, opts) >>
        self(VTensor(RCOLMultiplication(o.rChildren()[1], o.rChildren()[2]), o.rChildren()[3]), y, x, opts),

    RCVOLMultiplication := (self, o, y, x, opts) >> let(
        n  := o.rChildren()[2],
        m  := o.rChildren()[1],
        v  := o.rChildren()[3],
        t  := TPtr(opts.vector.isa.t),
        xv := List(x, e -> tcast(t, e)),
        yv := tcast(t, StripList(y)),
        mul_cx := opts.vector.isa.mul_cx(opts),
        i  := Ind(),
        a  := var.fresh_t("a", opts.vector.isa.t),
        loop( i, n, decl([a], chain(
            assign(a, nth(xv[1], i)),
            chain( List( [2..m], j -> mul_cx(a, nth(xv[j], i), a) )),
            assign(nth(yv, i), a))))
    ),

    VOLConjMultiplication := (self, o, y, x, opts) >>
        self(VTensor(OLConjMultiplication(o.rChildren()[1], o.rChildren()[2]),  o.rChildren()[3]), y, x, opts),

    VRCOLConjMultiplication := (self, o, y, x, opts) >>
        self(VTensor(RCOLConjMultiplication(o.rChildren()[1], o.rChildren()[2]), o.rChildren()[3]), y, x, opts),

    RCVOLConjMultiplication := (self, o, y, x, opts) >> let(
        n  := o.rChildren()[2],
        m  := o.rChildren()[1],
        v  := o.rChildren()[3],
        t  := TPtr(opts.vector.isa.t),
        xv := List(x, e -> tcast(t, e)),
        yv := tcast(t, StripList(y)),
        mul_cx_conj := opts.vector.isa.mul_cx_conj(opts),
        i  := Ind(),
        a  := var.fresh_t("a", opts.vector.isa.t),
        loop( i, n, decl([a], chain(
            assign(a, nth(xv[1], i)),
            chain( List( [2..m], j -> mul_cx_conj(a, nth(xv[j], i), a) )),
            assign(nth(yv, i), a))))
    ),

    RCVIxJ2 := (self, o, y, x, opts) >> let(
        isa := opts.vector.isa,
        t   := Checked( IsVecT(isa.t) and isa.t.size = o.v, TPtr(isa.t)),
        xv  := tcast(t, x),
        yv  := tcast(t, y),
        opts.vector.isa.RCVIxJ2(nth(yv,0), nth(xv, 0), opts)),

    VIxJ2 := (self, o, y, x, opts) >> let(
        isa := opts.vector.isa,
        t := Checked(IsVecT(isa.t) and isa.t.size = o.v, TPtr(isa.t)),
        xv := tcast(t, x),
        yv := tcast(t, y),
        opts.vector.isa.swap_cx(nth(yv, 0), nth(xv, 0), opts) ),

    VJxI := (self, o, y, x, opts) >> let(
        isa := opts.vector.isa,
        t   := Checked( IsVecT(isa.t) and isa.t.size = o.v, TPtr(isa.t)),
        xv  := tcast(t, x),
        yv  := tcast(t, y),
        opts.vector.isa.VJxI(o.m, nth(yv,0), nth(xv, 0), opts)),

));


text:
# Copyright (c) 2018-2021, Carnegie Mellon University
# See LICENSE for details

# ==========================================================================
# Perm
# ==========================================================================
Class(Perm, BaseMat, rec(
    new := (self, P, size) >>
	Checked(IsPerm(P), IsSymbolic(size) or IsValue(size) or (IsInt(size) and SPLOps.IsDegree(P, size)),
	    When(P = (),
		    SPL(WithBases(self, rec(isIdentity:=True,
				            element:=P, size := size,
					    dimensions := [size,size]))),
		    SPL(WithBases(self, rec(element:=P, size := size,
					    dimensions := [size,size]))))),

    rChildren := self >> [self.element, self.size],
    rSetChild := rSetChildFields("element", "size"),
    #-----------------------------------------------------------------------
    dims := self >> [self.size, self.size],
    #-----------------------------------------------------------------------
    isPermutation := True,
    #-----------------------------------------------------------------------
    isReal := True,
    #-----------------------------------------------------------------------
    toAMat := self >> AMatPerm(self.element, EvalScalar(self.size)),
    #-----------------------------------------------------------------------
    transpose := self >>  # we use inherit to copy all fields of self
        Inherit(self, rec(element := self.element^-1)),
    #-----------------------------------------------------------------------
    print := meth(self, indent, indentStep)
        Print(self.name, "(",  self.element, ", ", self.size, ")");
    end,
    #-----------------------------------------------------------------------
    arithmeticCost := (self, costMul, costAddMul) >> costMul(0) - costMul(0)
));


text:
# Copyright (c) 2018-2021, Carnegie Mellon University
# See LICENSE for details

# Dynamic Programming Search for good trees
# =========================================
# BS, MP, from 08/17/00

#F TimeLimitExpired( <startTime>, <timeLimit> )
#F    calculates if the time limit has expired
#F

TimeLimitExpired := function( startTime, timeLimit )
   return ( TimeInSecs()-startTime > 60*timeLimit );
end;

#F HashTableDP()
#F   returns a hash table for use with dynamic programming
#F

DPMeasureRuleTree := CMeasureRuleTree;

HashTableDP := function()
   return HashTable( HashIndexSPL, IsHashIdenticalSPL, "HashTableDP()" );
end;

_dpMeasure := function(wrappedTree, fullTree, spl, opts, dpopts, indent, isBaseCase)
    local mtree, time, bf;
    # Time tree
    When(dpopts.verbosity>=4, Print(Blanks(indent), "Timing: ", PrettyPrintRuleTree(fullTree, indent+6), "\n"));

#    Print("** _dpMeasure: \n* ", wrappedTree, "\n* ", fullTree, "\n* ", spl, "\n");

    ##################################################
    #    tSPL hack: do not measure everything
    if dpopts.verbosity>=5 then
    Print("Now doing measurments:\n");
    Print("spl: ", spl, "\n");
    if IsBound(dpopts.wraps) then Print("dpopts.wraps: ", dpopts.wraps, "\n"); fi;
    if IsBound(spl.wrap) then Print("spl.wrap", spl.wrap, "\n"); fi;
    fi;

    When(dpopts.verbosity>=5, Print(Blanks(indent), "tSPL: Measuring: ", wrappedTree,"\n"));

    if (IsBound(spl.doNotMeasure) and (spl.doNotMeasure)) then
        When(dpopts.verbosity>=5, Print(Blanks(indent), "tSPL: Not measuring ", spl, "\n"));
        time := 0;
    else
        if not dpopts.timeBaseCases and isBaseCase then
            time := 0; # do not measure
        elif IsBound(dpopts.measureFunction) then
            time := dpopts.measureFunction( wrappedTree, opts );
        else
            time := DPMeasureRuleTree( wrappedTree, opts );
        fi;
        When(dpopts.verbosity>=4, PrintLine("Measurment done: ", time));
    fi;

    ResetCodegen();

    When(dpopts.verbosity>=4, Print(Blanks(indent), "   ! ", time, "\n" ));
    return time;
end;

_dpReuseHash := function(W, spl, opts, dpopts, rvars)
    local lkup, lkup2, i, wrappedspl;

    wrappedspl := spl;
    for i in Reversed(W) do
        wrappedspl := i.twrap(spl,opts);
    od;

    # First lookup in readonly base cases hashtable, if not found, use the DP hashTable
    lkup := MultiHashLookup(opts.baseHashes, spl); # NOTE: why not wrappedspl? because it does not work!
    if lkup <> false then
        # Save in DP hash table also
        if HashLookup(rvars.hashTable, spl) = false then
            HashAdd(rvars.hashTable, spl, lkup);
        fi;
    else
        lkup := HashLookup( rvars.hashTable, wrappedspl);
    fi;

    # Found something -- just return it
    if not lkup = false then
    When(dpopts.verbosity>=5, Print("reuse lkup:\nlkup: ", lkup, "\n"));
    lkup2 := Copy(lkup);
    for i in lkup2 do
            if IsBound(i.origtree) then
                # special case in real A_x_I wrapped guys -- NOTE!!!
        if W <> VWrapId then
            When(dpopts.verbosity>=5, Print("VWrapId: using ruletree instead of origtree:\n"));
            i.ruletree := i.origtree;
        fi;
        Unbind(i.origtree);
        fi;
    od;
    return lkup2;
    fi;
    return lkup;
end;

_dpMax := (a,b) -> a.measured > b.measured;
_dpMin := (a,b) -> a.measured < b.measured;

Declare(_DPSPLRec);

# DPSPLRec( <spl>, <search-options-rec>, <SPL-options-rec>, <recVars> )
#    does the actual dynamic programming recursivedly.
#    do not call directly -- call DPSPL.
#
# HELP -- no checks for infinite loops (YSV: infinite loops in what?)
#
DPSPLRec := function( spl, dpopts, opts, rvars )
    local hspl, res, i;
    opts := TypeOpts(spl, opts);
    hspl := HashAsSPL(spl);
    res  := _DPSPLRec(hspl, dpopts, opts, rvars);
    for i in res do
        i.ruletree := ApplyRuleTreeSPL(i.ruletree, spl, opts);
    od;
    return res;
end;

_DPSPLRec := function( spl, dpopts, opts, rvars )
   local hash, hash2, chash, i, bf, wrappedspl, tree, trees, mtree, W, w, children, childrenSets,
         index, time, bestTrees, bestTrees2, numTimed, result, sorter, dpopts2, IsTopLevel,
         fullTree, mopts;

    ################################################
    if dpopts.verbosity>=5 then
        Print("Recursive call, spl: ", spl, "\n");
        if IsBound(dpopts.wraps) then Print("dpopts.wraps: ", dpopts.wraps, "\n"); fi;
        if IsBound(spl.wrap) then Print("spl.wrap", spl.wrap, "\n"); fi;
    fi;

    dpopts2 := Copy(dpopts);

    if not IsBound(dpopts2.wraps) then
        dpopts2.wraps := [VWrapId];
        dpopts2.wrap_index := 1;
    fi;

    # replaceable wrapper
    if ObjId(spl)=DPWrapper then
        dpopts2.wraps := ListWithout(dpopts2.wraps, dpopts2.wrap_index) :: [spl.wrap];
        dpopts2.wrap_index := Length(dpopts2.wraps);
    fi;
    # stackable wrappers
    if ObjId(spl)=DPSWrapper then
        Add(dpopts2.wraps, spl.wrap);
    fi;

    W := dpopts2.wraps;

    #################################################

    ############################################################
    ## Temporary Hack because spl.doNotMeasure is not checked ##
    ############################################################
    if (ObjId(spl)=InfoNt) then
        W:=[VWrapId];
    fi;

    # Check Time Limit
    if rvars.stopNow or (IsInt(dpopts.timeLimit) and TimeLimitExpired(rvars.startTime, dpopts.timeLimit)) then
        rvars.stopNow := true;
        When(dpopts.verbosity > 1, Print("\nTime Limit Expired!\n\n"));

        return [];
    fi;

    # unify data types to have spl with correct data type attributes before searching in hash
    spl := SumsUnification(spl, opts);

    hash := _dpReuseHash(W, HashAsSPL(spl), opts, dpopts, rvars);
    if hash <> false then
        return hash;
    fi;

    # Set up some local variables and functions
    sorter := When(dpopts.optimize = "maximize", _dpMax, _dpMin);
    numTimed := 0;
    bestTrees := [];
    if dpopts.verbosity>=1 then
        Print(Blanks(rvars.indent), "DP called on ", spl.print(rvars.indent, 2), "\n" );
    fi;
    trees := ExpandSPL(spl, opts);
    When(dpopts.verbosity>=3, Print(Blanks(rvars.indent), Length(trees), " tree(s) to fully expand\n"));
    rvars.indent := rvars.indent + 2;

    # For each possible new one level tree
    for tree in trees do

      # Check Time Limit
      if IsInt(dpopts.timeLimit) and not rvars.stopNow and TimeLimitExpired(rvars.startTime, dpopts.timeLimit) then
        rvars.stopNow := true;
        When(dpopts.verbosity > 1, Print("\nTime Limit Expired!\n\n"));
      else
        # For each possible set of subtrees of <tree>'s children
        childrenSets := Cartesian(List(tree.children, c -> List(DPSPLRec(c,dpopts2,opts,rvars), n->n.ruletree)));

        for children in childrenSets do
          if dpopts.verbosity>=5 then ################################################
            PrintLine("Back again:", "\nspl: ", spl, "\nchildren: ", children);
            When(IsBound(dpopts.wraps), Print("dpopts.wraps: ", dpopts.wraps, "\n"));
            When(IsBound(spl.wrap),    Print("spl.wrap", spl.wrap, "\n"));
          fi;   ######################################################################

          # Construct full tree, wrap it, and measure
          fullTree := CopyRuleTree(tree);
          fullTree.children := ShallowCopy(children);
          mopts := ShallowCopy(opts);
          mtree := fullTree;
          for w in Reversed(W) do
            mtree := w.wrap(mtree, spl, mopts);
            mopts := w.opts(spl, mopts);
          od;
          time := _dpMeasure(mtree, fullTree, spl, mopts, dpopts, rvars.indent,
              Length(childrenSets)=1 and Length(trees)=1);

          rvars.numTimed := rvars.numTimed + 1;
          numTimed := numTimed + 1;

              # See if one of the best times
          Add(bestTrees, rec( ruletree := mtree, origtree:= fullTree, measured := time,
                          globalUnrolling := opts.globalUnrolling ));
          Sort(bestTrees, sorter);
          When(IsBound(bestTrees[dpopts.nBest+1]), Unbind(bestTrees[dpopts.nBest+1]));

          od;
      fi;
   od;
   rvars.indent := rvars.indent - 2;

   # Save final result
   if not(IsBound(spl.doNotSaveInHashtable)) or
       (IsBound(spl.doNotSaveInHashtable) and not spl.doNotSaveInHashtable) then
       wrappedspl := HashAsSPL(spl);
       for w in Reversed(W) do
           wrappedspl := w.twrap(wrappedspl,opts);
       od;
       HashAdd(rvars.hashTable, wrappedspl, bestTrees);

       if IsBound(opts.unsafeDpHashUnwrapped) and opts.unsafeDpHashUnwrapped then
	   if HashLookup(rvars.hashTable, HashAsSPL(spl))=false then
	       HashAdd(rvars.hashTable, HashAsSPL(spl), List(bestTrees, x->CopyFields(x, rec(ruletree:=x.origtree))));
	   fi;
       fi;
   fi;

   if dpopts.verbosity>=2 then
       When(dpopts.verbosity>=3, Print(Blanks(rvars.indent), numTimed, " tree(s) timed at this level\n"));
       Print(Blanks(rvars.indent), "Best Trees:\n" );
       for result in bestTrees do
           Print(Blanks(rvars.indent+3), PrettyPrintRuleTree(result.ruletree, rvars.indent+3), " ! ", result.measured, "\n");
       od;
   fi;

    # NOTE: Hack to avoid wrapped trees in bestfoundtable
    bestTrees2 := Copy(bestTrees);
    for i in bestTrees2 do
        if IsBound(i.origtree) then
            i.ruletree := i.origtree;
            Unbind(i.origtree);
        fi;
    od;

    return bestTrees2;
end;

# GlobalUnrollingDPSPL( <spl>, <search-options-rec>,
#                       <SPL-options-rec>, <rvars> )
#   performs search over global unrolling for DP
#

GlobalUnrollingDPSPL := function( spl, dpopts, opts, rvars )
   local result, bestResult, bestUnrolling, bestHashTable;

   bestResult := false;

   # Initialize to first globalUnrolling setting
   opts.globalUnrolling := dpopts.globalUnrollingMin;

   repeat

      if dpopts.verbosity > 0 then
         Print( "Global_Unrolling := ", opts.globalUnrolling, "\n" );
      fi;

      # Set up hashTable
      if IsBound( dpopts.hashTable ) then
         rvars.hashTable := Copy(dpopts.hashTable);
      else
     rvars.hashTable := HashTableDP();
      fi;

      # Do DP
      result := DPSPLRec( spl, dpopts, opts, rvars );

      # Keep track of best result found over all unrollings
      if bestResult = false or bestResult = [] then
         bestResult := result;
     bestUnrolling := opts.globalUnrolling;
     bestHashTable := rvars.hashTable;
      elif    (     bestResult[1].measured < result[1].measured
                and dpopts.optimize = "maximize" )
           or (     bestResult[1].measured > result[1].measured
                and dpopts.optimize = "minimize" ) then
         bestResult := result;
     bestUnrolling := opts.globalUnrolling;
     bestHashTable := rvars.hashTable;
      fi;

      # Increase globalUnrolling
      opts.globalUnrolling := opts.globalUnrolling * 2;

   until opts.globalUnrolling > dpopts.globalUnrollingMax or
         rvars.stopNow;

   if dpopts.verbosity > 0 then
      Print( "Optimal unrolling is ", bestUnrolling, "\n" );
   fi;

   if IsBound( dpopts.hashTable ) then
      RecCopy(dpopts.hashTable, bestHashTable);
   fi;

   return bestResult;
end;

#F DPSPL( <spl> [, <DP-options-record>, <SPL-options-record> ] )
#F   runs dynamic programing on the given spl.
#F   maintins the n best formulas for each spl.
#F   returns a list of records of the best trees and their times.
#F   also may pass a DPOptionsRecord and a SPLOptionsRecord.
#F   to specify one set of options but not the other, pass just a "rec()"
#F      in place of the options you do not wish to set
#F   call PrintSpecDPOptionsRecord() and PrintSpecSPLOptionsRecord() to get
#F      info on possible options
#F   Verbosity levels:
#F      0 = Print nothing
#F      1 = Show recursive calls to DP
#F      2 = Show best trees found found each recursive call to DP
#F      3 = Show how many trees must be fully expanded and how many were timed
#F      4 = Show formulas that are being timed.
#F

DPSPL := function( arg )
   local spl,
     dpopts, opts,
     rvars,
     result;

   # process arg
   if Length(arg) = 1 then
      spl := arg[1];
      dpopts := MergeDPOptionsRecord(rec());
      opts := MergeSPLOptionsRecord(rec());
   elif Length(arg) = 3 then
      spl := arg[1];
      dpopts := MergeDPOptionsRecord(arg[2]);
#opts := MergeSPLOptionsRecord(arg[3]);
      opts := (arg[3]);
   else
      Error( "usage: DPSPL( <spl>",
             " [, <DP-options-record>, <SPL-options-record> ] )\n" );
   fi;

   # check spl
   if not IsSPL(spl) then
      Error("<spl> must be provided and a valid spl");
   fi;
   # check dataType
   SearchCheckDataType( spl, opts );
   # setup variables used during recursive calls

   rvars := rec( indent := 0, numTimed := 0, stopNow := false);

   # check timeLimit
   if IsInt( dpopts.timeLimit ) then
      rvars.startTime := TimeInSecs();
   fi;

   # check globalUnrolling because it requires extra work
   if dpopts.globalUnrolling = true then
      result := GlobalUnrollingDPSPL( spl, dpopts, opts, rvars );
   else

      # setup hashTable
      if IsBound( dpopts.hashTable ) then
         rvars.hashTable := dpopts.hashTable;
      elif IsBound( opts.hashTable ) then
         rvars.hashTable := opts.hashTable;
      else
         rvars.hashTable := HashTableDP();
      fi;

      result := DPSPLRec( spl, dpopts, opts, rvars );

   fi;

   if dpopts.verbosity >= 3 then
      Print( rvars.numTimed, " total trees timed\n" );
   fi;

   return result;
end;

#F DP(...) alias for DPSPL(...)
#F

DP := DPSPL;


text:
#
# Pregroup of free groups is special (at the moment at least)
#
InstallGlobalFunction(PregroupOfFreeGroup,
function(n)
    local i, r, e, inv, enams;

    #T maybe for n <= 26 just use a,b,c,?
    enams := [1..2*n+1];
    for i in [1..n] do
        enams[2 * i] := Concatenation("x", String(i));
        enams[2 * i + 1] := Concatenation("X", String(i));
    od;

    inv := function(x)
        if x = 1 then
            return 1;
        elif IsEvenInt(x) then
            return x + 1;
        else
            return x - 1;
        fi;
    end;

    r := rec( rank := n );

    r.fam := NewFamily( "PregroupElementsFamily", IsElementOfPregroup );
    r.elt_t := NewType( r!.fam, IsElementOfPregroupOfFreeGroupRep );
    r.elts := List( [ 1 .. (2*n + 1) ], i -> Objectify(r.elt_t, rec(parent := r, elt := i)));
    r.invs := [];
    for e in [1..Length(r.elts)] do
        r.elts[e]!.inv := r.elts[inv(e)];
    od;
    Objectify(PregroupOfFreeGroupType, r);
    SetPregroupElementNames(r, enams);
    return r;
end);

InstallMethod(ViewString
             , "for a pregroup of a free group"
             , [IsPregroupOfFreeGroupRep],
             function(pg)
                 return STRINGIFY("<pregroup of free group of rank ", pg!.rank, ">");
             end);

InstallMethod(Size
             , "for a pregroup of a free group"
             , [IsPregroupOfFreeGroupRep],
             pg -> 2 * pg!.rank + 1);

InstallMethod(\[\]
             , "for a pregroup of a free group"
             , [IsPregroupOfFreeGroupRep, IsInt],
             function(f,a)
                 return f!.elts[a];
             end);

InstallMethod(Iterator
             , "for a pregroup of a free group"
             , [IsPregroupOfFreeGroupRep],
             function(pgp)
                 local r;

                 r := rec( pgp := pgp
                         , pos := 0
                         , length := Size(pgp)
                         , NextIterator := function(iter)
                             if iter!.pos < iter!.length then
                                 iter!.pos := iter!.pos + 1;
                                 return iter!.pgp[iter!.pos];
                             else
                                 return fail;
                             fi;
                         end
                         , IsDoneIterator := iter -> iter!.pos = iter!.length
                         , ShallowCopy := iter -> rec( pgp := iter!.pgp, pos := iter!.pos )
                         );

                 return IteratorByFunctions(r);
             end);

InstallMethod(PregroupElementNames
             , "for a pregroup"
             , [IsPregroupOfFreeGroupRep]
             , p -> p!.elementnames );

InstallMethod(SetPregroupElementNames
             , "for a pregroup"
             , [IsPregroupOfFreeGroupRep, IsList]
             , function(p, n)
                 p!.elementnames := n;
             end );

InstallMethod(IntermultPairs
             , "for a pregroup in table rep"
             , [IsPregroupOfFreeGroupRep],
             pg -> []);

InstallMethod(IntermultPairsIDs
             , "for a pregroup in table rep"
             , [IsPregroupOfFreeGroupRep],
             pg -> []);

InstallMethod(IntermultMapIDs
             , "for a pregroup in table rep"
             , [IsPregroupOfFreeGroupRep],
             pg -> ListWithIdenticalEntries(Size(pg), []));

InstallMethod(IntermultMap
             , "for a pregroup in table rep"
             , [IsPregroupOfFreeGroupRep],
             pg -> ListWithIdenticalEntries(Size(pg), []));

InstallMethod(One, "for a pregroup",
              [IsPregroupOfFreeGroupRep],
              pg -> pg!.elts[1]);

#
# PregroupOfFreeGroup elements
#
InstallMethod(IntermultMap
             , "for a pregroup element"
             , [IsElementOfPregroupOfFreeGroupRep],
             pge -> []);

InstallMethod(ViewString
             , "for a pregroup element"
             , [IsElementOfPregroupOfFreeGroupRep],
function(pge)
    if pge!.elt > 0 then
        return PregroupElementNames(pge!.parent)[pge!.elt];
    else
        return "undefined";
    fi;
end);

InstallMethod(String
             , "for a pregroup element"
             , [IsElementOfPregroupOfFreeGroupRep],
function(pge)
    if pge!.elt > 0 then
        return PregroupElementNames(pge!.parent)[pge!.elt];
    else
        return "undefined";
    fi;
end);

#XXX Is fail as a result for multiplication acceptable?
InstallMethod(\*
             , "for pregroup elements"
             , IsIdenticalObj
             , [IsElementOfPregroupOfFreeGroupRep, IsElementOfPregroupOfFreeGroupRep]
             , 0,
function(x,y)
    if x!.elt = 1 then
        return y;
    elif y!.elt = 1 then
        return x;
    elif x!.inv = y then
        return One(PregroupOf(x));
    else
        return fail;
    fi;
end);

InstallMethod(\=
             , "for pregroup elements"
             , IsIdenticalObj
             , [IsElementOfPregroupOfFreeGroupRep, IsElementOfPregroupOfFreeGroupRep]
             , 0,
function(x,y)
    return x!.elt = y!.elt;
end);

# Artificial ordering on pregroup to make sets work
InstallMethod(\<
             , "for pregroup elements"
             , IsIdenticalObj
             , [ IsElementOfPregroupOfFreeGroupRep, IsElementOfPregroupOfFreeGroupRep]
             , 0,
function(x,y)
    return x!.elt < y!.elt;
end);

InstallMethod(PregroupOf
             , "for pregroup elements"
             , [ IsElementOfPregroupOfFreeGroupRep ]
             , 0,
function(a)
    return a!.parent;
end);

InstallMethod(PregroupInverse
             , "for pregroup elements"
             , [ IsElementOfPregroupOfFreeGroupRep ]
             , 0,
             a -> a!.inv);

InstallMethod(PregroupElementId
             , "for pregroup elements"
             , [ IsElementOfPregroupOfFreeGroupRep ]
             , 0,
             a -> a!.elt);

InstallMethod(__ID
             , "for pregroup elements"
             , [ IsElementOfPregroupOfFreeGroupRep ]
             , 0,
             x -> x!.elt);

InstallMethod(IsDefinedMultiplication
             , "for pregroup elements"
             , IsIdenticalObj
             , [ IsElementOfPregroupOfFreeGroupRep, IsElementOfPregroupOfFreeGroupRep ]
             , 0,
function(a,b)
    return (a!.elt = 1) or (b!.elt = 1) or (a!.inv = b);
end);

# We could cache intermult pairs,
# or predetermine them, depending
# on the number of intermult lookups
# that could benefit runtime
InstallMethod(IsIntermultPair
             , "for pregroup elements"
             , IsIdenticalObj
             , [IsElementOfPregroupOfFreeGroupRep, IsElementOfPregroupOfFreeGroupRep]
             , 0,
function(a,b)
    return false;
end);

max_stars_repo_name: RussWoodroofe/walrus

max_issues_repo_name: RussWoodroofe/walrus

max_forks_repo_name: RussWoodroofe/walrus