x = var'x'
GOOD time: 0.060000ms
stack: size: 0


    y = func('y', {x}, x^2)
    GOOD time: 0.131000ms
    stack: size: 0
      TODO what to display...
      y = x
      y(x) = x
      y(x) := x

      print(y(x))
      $y\left( x\right)$ GOOD time: 0.114000ms
      stack: size: 0

        print(y(x)())
        ${x}^{2}$ GOOD time: 3.540000ms
        stack: size: 11
        • Init
        • y:Prune:apply
        • Prune
        • ^:Expand:integerPower
        • Expand
        • +:Prune:combineConstants
        • *:Prune:combinePows
        • Prune
        • Factor
        • Prune
        • Tidy

        printbr(y:defeq())
        ${y\left( x\right)} = {{x}^{2}}$
        GOOD
        time: 0.422000ms
        stack: size: 0

          assert(UserFunction.registeredFunctions.y == y)
          GOOD time: 0.035000ms
          stack: size: 0

            if UserFunction is not a Variable then this is invalid
            because you cannot have Functions as Variables in the arg list
            f = func('f', {x, y}, x*y)
            print(f:defeq())
            assert(UserFunction.registeredFunctions.f == f)

            instead, if UserFunction returns Functions, this is what you would see
            and with this the derivative evaluation is obvious

            f = func('f', {x}, x*y(x))
            GOOD time: 0.099000ms
            stack: size: 0

              print(f:defeq())
              ${f\left( x\right)} = {{{x}} {{y\left( x\right)}}}$ GOOD time: 0.564000ms
              stack: size: 0

                assert(UserFunction.registeredFunctions.f == f)
                GOOD time: 0.032000ms
                stack: size: 0

                  diff() is partial derivative
                  totalDiff() is total derivative

                  total derivative evaluation
                  substitute chain rule for all terms
                  df/dx, when simplified, does not go anywhere, because f is dependent on x
                  for that reason, I can just build the equality f:eq(f.def) and apply :diff() to the whole thing:

                  print(f:defeq():diff(x):prune())
                  ${{{3}} {{{x}^{2}}}} = {{{3}} {{{x}^{2}}}}$ GOOD time: 8.292000ms
                  stack: size: 12
                  • f:Prune:apply
                  • y:Prune:apply
                  • +:Prune:combineConstants
                  • *:Prune:combinePows
                  • y:Prune:apply
                  • +:Prune:combineConstants
                  • *:Prune:combinePows
                  • Derivative:Prune:self
                  • Derivative:Prune:eval
                  • Derivative:Prune:self
                  • Derivative:Prune:eval
                  • Derivative:Prune:eval
                  but TODO wrt total derivatives ... diff(y) ...
                  y(x) above is a UserFunction subclass
                  which means it isn't a Variable
                  which means you can't diff(y) ...
                  though you could diff(y(x)) ...
                  but that would be diff'ing wrt expressions, which I don't have support for

                  print(f:defeq():diff(y):prune())
                  ${0} = {0}$ GOOD time: 7.276000ms
                  stack: size: 14
                  • f:Prune:apply
                  • y:Prune:apply
                  • +:Prune:combineConstants
                  • *:Prune:combinePows
                  • y:Prune:apply
                  • +:Prune:combineConstants
                  • *:Prune:combinePows
                  • Derivative:Prune:other
                  • *:Prune:apply
                  • Derivative:Prune:eval
                  • Derivative:Prune:other
                  • *:Prune:apply
                  • Derivative:Prune:eval
                  • Derivative:Prune:eval

                  print(f:defeq():diff(y(x)):prune())
                  ${0} = {0}$ GOOD time: 4.928000ms
                  stack: size: 15
                  • f:Prune:apply
                  • y:Prune:apply
                  • +:Prune:combineConstants
                  • *:Prune:combinePows
                  • y:Prune:apply
                  • y:Prune:apply
                  • +:Prune:combineConstants
                  • *:Prune:combinePows
                  • Derivative:Prune:other
                  • *:Prune:apply
                  • Derivative:Prune:eval
                  • Derivative:Prune:other
                  • *:Prune:apply
                  • Derivative:Prune:eval
                  • Derivative:Prune:eval


                  s = var's'
                  GOOD time: 0.039000ms
                  stack: size: 0

                    t = var't'
                    GOOD time: 0.035000ms
                    stack: size: 0

                      x = func('x', {s,t})
                      GOOD time: 0.221000ms
                      stack: size: 0

                        y = func('y', {s,t})
                        GOOD time: 0.072000ms
                        stack: size: 0

                          f = func('f', {x,y})
                          BAD
                          /home/chris/Projects/lua/symmath/UserFunction.lua:141: args must be a table of Variables
                          stack traceback:
                          /home/chris/Projects/lua/symmath/tests/unit/unit.lua:246: in function
                          [C]: in function 'assert'
                          /home/chris/Projects/lua/symmath/UserFunction.lua:141: in function 'func'
                          [string "f = func('f', {x,y})"]:1: in main chunk
                          /home/chris/Projects/lua/symmath/tests/unit/unit.lua:238: in function
                          [C]: in function 'xpcall'
                          /home/chris/Projects/lua/symmath/tests/unit/unit.lua:237: in function 'exec'
                          func.lua:65: in function 'cb'
                          /home/chris/Projects/lua/ext/timer.lua:54: in function 'timer'
                          func.lua:6: in main chunk
                          [C]: at 0x55e2a76ae3e0
                          time: 0.167000ms
                          stack: size: 0
                            ∂f/∂x
                            print(f:diff(x):prune())
                            BAD
                            /home/chris/Projects/lua/symmath/Expression.lua:39: attempt to call a table value
                            stack traceback:
                            /home/chris/Projects/lua/symmath/tests/unit/unit.lua:246: in function
                            /home/chris/Projects/lua/symmath/Expression.lua:39: in function 'clone'
                            /home/chris/Projects/lua/symmath/Derivative.lua:325: in function 'func'
                            /home/chris/Projects/lua/symmath/visitor/Visitor.lua:224: in function 'prune'
                            [string "print(f:diff(x):prune())"]:1: in main chunk
                            /home/chris/Projects/lua/symmath/tests/unit/unit.lua:238: in function
                            [C]: in function 'xpcall'
                            /home/chris/Projects/lua/symmath/tests/unit/unit.lua:237: in function 'exec'
                            func.lua:65: in function 'cb'
                            /home/chris/Projects/lua/ext/timer.lua:54: in function 'timer'
                            func.lua:6: in main chunk
                            [C]: at 0x55e2a76ae3e0
                            time: 0.811000ms
                            stack: size: 0
                              ∂f/∂y
                              print(f:diff(y):prune())
                              BAD
                              /home/chris/Projects/lua/symmath/Expression.lua:39: attempt to call a table value
                              stack traceback:
                              /home/chris/Projects/lua/symmath/tests/unit/unit.lua:246: in function
                              /home/chris/Projects/lua/symmath/Expression.lua:39: in function 'clone'
                              /home/chris/Projects/lua/symmath/Derivative.lua:325: in function 'func'
                              /home/chris/Projects/lua/symmath/visitor/Visitor.lua:224: in function 'prune'
                              [string "print(f:diff(y):prune())"]:1: in main chunk
                              /home/chris/Projects/lua/symmath/tests/unit/unit.lua:238: in function
                              [C]: in function 'xpcall'
                              /home/chris/Projects/lua/symmath/tests/unit/unit.lua:237: in function 'exec'
                              func.lua:65: in function 'cb'
                              /home/chris/Projects/lua/ext/timer.lua:54: in function 'timer'
                              func.lua:6: in main chunk
                              [C]: at 0x55e2a76ae3e0
                              time: 0.553000ms
                              stack: size: 0
                                ∂f/∂x ∂x/∂s + ∂f/∂y ∂y/∂s
                                print(f:diff(s):prune())
                                BAD
                                /home/chris/Projects/lua/symmath/Expression.lua:39: attempt to call a table value
                                stack traceback:
                                /home/chris/Projects/lua/symmath/tests/unit/unit.lua:246: in function
                                /home/chris/Projects/lua/symmath/Expression.lua:39: in function 'clone'
                                /home/chris/Projects/lua/symmath/Derivative.lua:325: in function 'func'
                                /home/chris/Projects/lua/symmath/visitor/Visitor.lua:224: in function 'prune'
                                [string "print(f:diff(s):prune())"]:1: in main chunk
                                /home/chris/Projects/lua/symmath/tests/unit/unit.lua:238: in function
                                [C]: in function 'xpcall'
                                /home/chris/Projects/lua/symmath/tests/unit/unit.lua:237: in function 'exec'
                                func.lua:65: in function 'cb'
                                /home/chris/Projects/lua/ext/timer.lua:54: in function 'timer'
                                func.lua:6: in main chunk
                                [C]: at 0x55e2a76ae3e0
                                time: 0.419000ms
                                stack: size: 0
                                  ∂f/∂x ∂x/∂t + ∂f/∂y ∂y/∂t
                                  print(f:diff(t):prune())
                                  BAD
                                  /home/chris/Projects/lua/symmath/Expression.lua:39: attempt to call a table value
                                  stack traceback:
                                  /home/chris/Projects/lua/symmath/tests/unit/unit.lua:246: in function
                                  /home/chris/Projects/lua/symmath/Expression.lua:39: in function 'clone'
                                  /home/chris/Projects/lua/symmath/Derivative.lua:325: in function 'func'
                                  /home/chris/Projects/lua/symmath/visitor/Visitor.lua:224: in function 'prune'
                                  [string "print(f:diff(t):prune())"]:1: in main chunk
                                  /home/chris/Projects/lua/symmath/tests/unit/unit.lua:238: in function
                                  [C]: in function 'xpcall'
                                  /home/chris/Projects/lua/symmath/tests/unit/unit.lua:237: in function 'exec'
                                  func.lua:65: in function 'cb'
                                  /home/chris/Projects/lua/ext/timer.lua:54: in function 'timer'
                                  func.lua:6: in main chunk
                                  [C]: at 0x55e2a76ae3e0
                                  time: 0.498000ms
                                  stack: size: 0
                                    TODO I need something to represent ∂/∂x "the def of f", rather than ∂/∂x "f", which is zero.
                                    in contrast ∂/∂x "the def of f" would be a placeholder (in absense of f's provided definition)