upper by default
local x=a'i' print(x) assert(#x==2 and x[1]==a and x[2]==Tensor.Index{symbol='i', lower=false})
${ a} ^i$ GOOD time: 0.038000ms
stack: size: 0

    local x=a'^i' print(x) assert(#x==2 and x[1]==a and x[2]==Tensor.Index{symbol='i', lower=false})
    ${ a} ^i$ GOOD time: 0.021000ms
    stack: size: 0

      local x=a'_i' print(x) assert(#x==2 and x[1]==a and x[2]==Tensor.Index{symbol='i', lower=true})
      ${ a} _i$ GOOD time: 0.050000ms
      stack: size: 0

        local x=a'ij' print(x) assert(#x==3 and x[1]==a and x[2]==Tensor.Index{symbol='i', lower=false} and x[3]==Tensor.Index{symbol='j', lower=false})
        ${{ a} ^i} ^j$ GOOD time: 0.090000ms
        stack: size: 0

          local x=a'i_j' print(x) assert(#x==3 and x[1]==a and x[2]==Tensor.Index{symbol='i', lower=false} and x[3]==Tensor.Index{symbol='j', lower=true})
          ${{ a} ^i} _j$ GOOD time: 0.026000ms
          stack: size: 0

            local x=a'^ij' print(x) assert(#x==3 and x[1]==a and x[2]==Tensor.Index{symbol='i', lower=false} and x[3]==Tensor.Index{symbol='j', lower=false})
            ${{ a} ^i} ^j$ GOOD time: 0.023000ms
            stack: size: 0

              local x=a'^i_j' print(x) assert(#x==3 and x[1]==a and x[2]==Tensor.Index{symbol='i', lower=false} and x[3]==Tensor.Index{symbol='j', lower=true})
              ${{ a} ^i} _j$ GOOD time: 0.032000ms
              stack: size: 0

                local x=a'_i^j' print(x) assert(#x==3 and x[1]==a and x[2]==Tensor.Index{symbol='i', lower=true} and x[3]==Tensor.Index{symbol='j', lower=false})
                ${{ a} _i} ^j$ GOOD time: 0.044000ms
                stack: size: 0

                  local x=a'_ij' print(x) assert(#x==3 and x[1]==a and x[2]==Tensor.Index{symbol='i', lower=true} and x[3]==Tensor.Index{symbol='j', lower=true})
                  ${{ a} _i} _j$ GOOD time: 0.066000ms
                  stack: size: 0

                    multi-char
                    upper by default
                    local x=a' i' print(x) assert(#x==2 and x[1]==a and x[2]==Tensor.Index{symbol='i', lower=false})
                    ${ a} ^i$ GOOD time: 0.023000ms
                    stack: size: 0
                      upper by default
                      local x=a' \\mu' print(x) assert(#x==2 and x[1]==a and x[2]==Tensor.Index{symbol='\\mu', lower=false})
                      ${ a} ^{\mu}$ GOOD time: 0.027000ms
                      stack: size: 0

                        local x=a' ^\\mu' print(x) assert(#x==2 and x[1]==a and x[2]==Tensor.Index{symbol='\\mu', lower=false})
                        ${ a} ^{\mu}$ GOOD time: 0.057000ms
                        stack: size: 0

                          local x=a' _\\mu' print(x) assert(#x==2 and x[1]==a and x[2]==Tensor.Index{symbol='\\mu', lower=true})
                          ${ a} _{\mu}$ GOOD time: 0.149000ms
                          stack: size: 0

                            local x=a' \\mu \\nu' print(x) assert(#x==3 and x[1]==a and x[2]==Tensor.Index{symbol='\\mu', lower=false} and x[3]==Tensor.Index{symbol='\\nu', lower=false})
                            ${{ a} ^{\mu}} ^{\nu}$ GOOD time: 0.090000ms
                            stack: size: 0

                              commas are lower by default
                              local x=a',i' print(x) assert(#x==2 and x[1]==a and x[2]==Tensor.Index{symbol='i', lower=true, derivative=','})
                              ${ a} _{,i}$ GOOD time: 0.022000ms
                              stack: size: 0

                                local x=a',^i' print(x) assert(#x==2 and x[1]==a and x[2]==Tensor.Index{symbol='i', lower=false, derivative=','})
                                ${ a} ^{,i}$ GOOD time: 0.019000ms
                                stack: size: 0

                                  local x=a',_i' print(x) assert(#x==2 and x[1]==a and x[2]==Tensor.Index{symbol='i', lower=true, derivative=','})
                                  ${ a} _{,i}$ GOOD time: 0.017000ms
                                  stack: size: 0

                                    local x=a'^,i' print(x) assert(#x==2 and x[1]==a and x[2]==Tensor.Index{symbol='i', lower=false, derivative=','})
                                    ${ a} ^{,i}$ GOOD time: 0.017000ms
                                    stack: size: 0

                                      local x=a'_,i' print(x) assert(#x==2 and x[1]==a and x[2]==Tensor.Index{symbol='i', lower=true, derivative=','})
                                      ${ a} _{,i}$ GOOD time: 0.032000ms
                                      stack: size: 0

                                        TODO multiple indexes with commas mixed
                                        TODO multiple indexes with commas mixed with multiple chars


                                        simplifyAssertNe(a'^,i', a'_,i')
                                        ${{ a} ^{,i}} \ne {{ a} _{,i}}$
                                        GOOD
                                        time: 0.919000ms
                                        stack: size: 7
                                        • Init
                                        • Prune
                                        • Expand
                                        • Prune
                                        • Factor
                                        • Prune
                                        • Tidy