|
| 1 | +@doc raw""" |
| 2 | + exchange_left!(W::WeylGroup, w::AbstractVector{UInt8}, i::UInt8) -> AbstractVector{UInt8} |
| 3 | +
|
| 4 | +Given a word `w` which is reduced w.r.t. `W`, modify `w` in-place into an equivalent word |
| 5 | +starting with `i` if the exchange condition can be applied, otherwise leave `w` unchanged. |
| 6 | +Finally, return `w`. |
| 7 | +
|
| 8 | +!!! warning |
| 9 | + If `w` is not a reduced expression, the behaviour is arbitrary. |
| 10 | +
|
| 11 | +See also [`exchange_right!(::WeylGroup, ::AbstractVector{UInt8}, ::UInt8)`](@ref). |
| 12 | +""" |
| 13 | +function exchange_left!(W::WeylGroup, w::AbstractVector{UInt8}, i::UInt8) |
| 14 | + if w[1] == i |
| 15 | + return w |
| 16 | + end |
| 17 | + |
| 18 | + root = i |
| 19 | + for s in 1:length(w) |
| 20 | + if w[s] == root |
| 21 | + for n in s:-1:2 |
| 22 | + w[n] = w[n - 1] |
| 23 | + end |
| 24 | + w[1] = i |
| 25 | + return w |
| 26 | + end |
| 27 | + root = W.refl[Int(w[s]), Int(root)] |
| 28 | + end |
| 29 | + |
| 30 | + return w |
| 31 | +end |
| 32 | + |
| 33 | +@doc raw""" |
| 34 | + exchange_right!(W::WeylGroup, w::AbstractVector{UInt8}, i::UInt8) -> AbstractVector{UInt8} |
| 35 | +
|
| 36 | +Given a word `w` which is reduced w.r.t. `W`, modify `w` in-place into an equivalent word |
| 37 | +ending with `i` if the exchange condition can be applied, otherwise leave `w` unchanged. |
| 38 | +Finally, return `w`. |
| 39 | +
|
| 40 | +!!! warning |
| 41 | + If `w` is not a reduced expression, the behaviour is arbitrary. |
| 42 | +
|
| 43 | +See also [`exchange_left!(::WeylGroup, ::AbstractVector{UInt8}, ::UInt8)`](@ref). |
| 44 | +""" |
| 45 | +function exchange_right!(W::WeylGroup, w::AbstractVector{UInt8}, i::UInt8) |
| 46 | + # The algorithm is almost the same as explain_rmul |
| 47 | + # But we don't need a normal form, so this is faster |
| 48 | + if w[end] == i |
| 49 | + return w |
| 50 | + end |
| 51 | + |
| 52 | + root = i |
| 53 | + for s in length(w):-1:1 |
| 54 | + if w[s] == root |
| 55 | + for n in s:(length(w) - 1) |
| 56 | + w[n] = w[s + 1] |
| 57 | + end |
| 58 | + w[end] = i |
| 59 | + return w |
| 60 | + end |
| 61 | + root = W.refl[Int(w[s]), Int(root)] |
| 62 | + end |
| 63 | + |
| 64 | + return w |
| 65 | +end |
| 66 | + |
| 67 | +@doc raw""" |
| 68 | + braid_moves(W::WeylGroup, w1::Vector{UInt8}, w2::Vector{UInt8}) -> Vector{Tuple{Int,Int,Int}} |
| 69 | +
|
| 70 | +Return the braid moves required to transform the reduced expression `w2` |
| 71 | +into the reduced expression `w1` with respect to the Weyl group `W`. |
| 72 | +A braid move `(n, len, dir)` should be understood as follows: |
| 73 | +- `n` is the position where the braid move starts |
| 74 | +- `len` is the length of the braid move |
| 75 | +- `dir` is the direction of the braid move. If `len=2` or `len=3`, `dir` is `0` or `-1`. |
| 76 | + If `len=4` or `len=6`, `dir` is `-2` or `-3` if the root at `n` is short, otherwise `dir` is `-1`. |
| 77 | + This information can be used, when computing the tropical Plücker relations. |
| 78 | +
|
| 79 | +!!! warning |
| 80 | + If `w1` and `w2` do not define the same element in `W`, the behaviour is arbitrary. |
| 81 | +
|
| 82 | +# Examples |
| 83 | +```jldoctest |
| 84 | +julia> W = weyl_group(:A, 3); |
| 85 | +
|
| 86 | +julia> braid_moves(W, UInt8[1,2,1,3,2,1], UInt8[1,3,2,1,3,2]) |
| 87 | +4-element Vector{Tuple{Int64, Int64, Int64}}: |
| 88 | + (4, 2, 0) |
| 89 | + (2, 3, -1) |
| 90 | + (4, 3, -1) |
| 91 | + (3, 2, 0) |
| 92 | +
|
| 93 | +julia> W = weyl_group(:B, 2); |
| 94 | +
|
| 95 | +julia> braid_moves(W, UInt8[2,1,2,1], UInt8[1,2,1,2]) |
| 96 | +1-element Vector{Tuple{Int64, Int64, Int64}}: |
| 97 | + (1, 4, -2) |
| 98 | +``` |
| 99 | +""" |
| 100 | +function braid_moves(W::WeylGroup, w1::Vector{UInt8}, w2::Vector{UInt8}) |
| 101 | + return _braid_moves(W, w1, w2, 0) |
| 102 | +end |
| 103 | + |
| 104 | +function _braid_moves( |
| 105 | + W::WeylGroup, w1::AbstractVector{UInt8}, w2::AbstractVector{UInt8}, offset::Int |
| 106 | +) |
| 107 | + mvs = Tuple{Int,Int,Int}[] |
| 108 | + if w1 == w2 |
| 109 | + return mvs |
| 110 | + end |
| 111 | + |
| 112 | + C = cartan_matrix(W) |
| 113 | + jo, jn = copy(w2), copy(w2) |
| 114 | + for i in 1:length(w1) |
| 115 | + if w1[i] == jo[i] |
| 116 | + continue |
| 117 | + end |
| 118 | + |
| 119 | + cij = Int(C[Int(w1[i]), Int(jo[i])]) |
| 120 | + cji = Int(C[Int(jo[i]), Int(w1[i])]) |
| 121 | + |
| 122 | + # in all cases we need to move w1[i] to the right of jn[i] |
| 123 | + # so that we can later apply the appropriate braid move |
| 124 | + @views exchange_left!(W, jn[(i + 1):end], w1[i]) |
| 125 | + |
| 126 | + if cij == 0 |
| 127 | + # compute how to get jn[i:end] into [jn[i], w1[i], ...] |
| 128 | + @views append!(mvs, _braid_moves(W, jn[(i + 1):end], jo[(i + 1):end], i + offset)) |
| 129 | + push!(mvs, (i + offset, 2, cij)) |
| 130 | + reverse!(jn, i, i + 1) |
| 131 | + elseif cij == -1 && cji == -1 |
| 132 | + @views exchange_left!(W, jn[(i + 2):end], jn[i]) # move jn[i] to the right of jn[i+1] |
| 133 | + |
| 134 | + # compute how to get jn[i:end] into [jn[i], w1[i], jn[i], ...] |
| 135 | + @views append!(mvs, _braid_moves(W, jn[(i + 1):end], jo[(i + 1):end], i + offset)) |
| 136 | + push!(mvs, (i + offset, 3, cij)) |
| 137 | + jn[i], jn[i + 1], jn[i + 2] = jn[i + 1], jn[i], jn[i + 1] |
| 138 | + elseif cij == -2 || cji == -2 |
| 139 | + @views exchange_left!(W, jn[(i + 2):end], jn[i]) # move jn[i] to the right of jn[i+1] |
| 140 | + @views exchange_left!(W, jn[(i + 3):end], w1[i]) # move w1[i] to the right of jn[i+2] |
| 141 | + |
| 142 | + # compute how to get jn[i:end] into [jn[i], w1[i], jn[i], w1[i], ...] |
| 143 | + @views append!(mvs, _braid_moves(W, jn[(i + 1):end], jo[(i + 1):end], i + offset)) |
| 144 | + push!(mvs, (i + offset, 4, cij)) |
| 145 | + reverse!(jn, i, i + 3) |
| 146 | + elseif cij == -3 || cji == -3 |
| 147 | + @views exchange_left!(W, jn[(i + 2):end], jn[i]) # move jn[i] to the right of jn[i+1] |
| 148 | + @views exchange_left!(W, jn[(i + 3):end], w1[i]) # move w1[i] to the right of jn[i+2] |
| 149 | + @views exchange_left!(W, jn[(i + 4):end], jn[i]) # move jn[i] to the right of jn[i+3] |
| 150 | + @views exchange_left!(W, jn[(i + 5):end], w1[i]) # move w1[i] to the right of jn[i+4] |
| 151 | + |
| 152 | + # compute how to get jn[i:end] into [jn[i], w1[i], jn[i], w1[i], jn[i], w1[i], ...] |
| 153 | + @views append!(mvs, _braid_moves(W, jn[(i + 1):end], jo[(i + 1):end], i + offset)) |
| 154 | + push!(mvs, (i + offset, 6, cij)) |
| 155 | + reverse!(jn, i, i + 5) |
| 156 | + end |
| 157 | + |
| 158 | + copyto!(jo, i, jn, i, length(jo) - i + 1) |
| 159 | + end |
| 160 | + |
| 161 | + return mvs |
| 162 | +end |
| 163 | + |
| 164 | +@doc raw""" |
| 165 | + apply_braid_move!(w::Vector{UInt8}, mv::Tuple{Int,Int,Int}) -> Vector{UInt8} |
| 166 | +
|
| 167 | +Apply the braid move `mv` to the word `w` and return the result. |
| 168 | +If `mv` is not a valid braid move for `w`, the behaviour is arbitrary. |
| 169 | +See also [`braid_moves`](@ref). |
| 170 | +""" |
| 171 | +function apply_braid_move!(w::Vector{UInt8}, mv::Tuple{Int,Int,Int}) |
| 172 | + i, len, _ = mv |
| 173 | + if len == 2 |
| 174 | + w[i], w[i + 1] = w[i + 1], w[i] |
| 175 | + elseif len == 3 |
| 176 | + w[i], w[i + 1], w[i + 2] = w[i + 1], w[i], w[i + 1] |
| 177 | + elseif len == 4 |
| 178 | + w[i], w[i + 1], w[i + 2], w[i + 3] = w[i + 1], w[i], w[i + 1], w[i] |
| 179 | + elseif len == 6 |
| 180 | + w[i], w[i + 1], w[i + 2], w[i + 3], w[i + 4], w[i + 5] = w[i + 1], |
| 181 | + w[i], w[i + 1], w[i], w[i + 1], |
| 182 | + w[i] |
| 183 | + end |
| 184 | + return w |
| 185 | +end |
| 186 | + |
1 | 187 | @doc raw"""
|
2 | 188 | FPGroup(W::WeylGroup) -> FPGroup
|
3 | 189 | fp_group(W::WeylGroup) -> FPGroup
|
|
0 commit comments