ekmett / ad

Automatic Differentiation
http://hackage.haskell.org/package/ad
BSD 3-Clause "New" or "Revised" License
372 stars 73 forks source link

nesting: diff (\x -> diff (*x) 1) 1 #60

Open barak opened 8 years ago

barak commented 8 years ago

Was showing off nesting, simplest example I could think of, oops.

tldr: ad 4.3.2.1, ghc 8.0.1, diff (\x -> diff (*x) 1) 1 gets a type error.

$ cabal update
Downloading the latest package list from hackage.haskell.org
$ cabal install --user ad
Resolving dependencies...
Downloading base-orphans-0.5.4...
...
Installed free-4.12.4
Downloading ad-4.3.2.1...
Configuring ad-4.3.2.1...
Building ad-4.3.2.1...
Installed ad-4.3.2.1
$ ghci
GHCi, version 8.0.1: http://www.haskell.org/ghc/  :? for help
Prelude> :m + Numeric.AD
Prelude Numeric.AD> diff (*2) 1
2
Prelude Numeric.AD> diff sin 0
1.0
Prelude Numeric.AD> diff (\x -> diff (*x) 1) 1

<interactive>:6:20: error:
    • Occurs check: cannot construct the infinite type:
        a ~ AD s (Numeric.AD.Internal.Forward.Forward a)
      Expected type: AD
                       s1
                       (Numeric.AD.Internal.Forward.Forward
                          (AD s (Numeric.AD.Internal.Forward.Forward a)))
        Actual type: AD s (Numeric.AD.Internal.Forward.Forward a)
    • In the second argument of ‘(*)’, namely ‘x’
      In the first argument of ‘diff’, namely ‘(* x)’
      In the expression: diff (* x) 1
    • Relevant bindings include
        x :: AD s (Numeric.AD.Internal.Forward.Forward a)
          (bound at <interactive>:6:8)
        it :: a (bound at <interactive>:6:1)

This happens even without nesting.

> diff (pi*) 1
3.141592653589793
> (\x -> diff (x*) 1) pi
error: ...
> let x=pi in diff (x*) 1
3.141592653589793

and yes, I know auto makes it okay

Prelude Numeric.AD> diff (\x -> diff (auto x*) 2) 3
1
Prelude Numeric.AD> (\x -> diff (auto x*) 2) 3
3

But it's still a pretty big wart on an otherwise lovely countenance.

alang9 commented 7 years ago

I don't know if this is helpful, but this works fine if you use the diff from Numeric.AD.Rank1.Forward

barak commented 7 years ago

Not entirely.

Prelude Numeric.AD.Rank1.Forward> :t diff
diff :: Num a => (Forward a -> Forward a) -> a -> a

Prelude Numeric.AD.Rank1.Forward> diff (\x -> diff (x*) 2) 3
<interactive>:10:13: error:
    • Occurs check: cannot construct the infinite type: a ~ Forward a
    • In the expression: diff (x *) 2
      In the first argument of ‘diff’, namely ‘(\ x -> diff (x *) 2)’
      In the expression: diff (\ x -> diff (x *) 2) 3
    • Relevant bindings include
        x :: Forward a (bound at <interactive>:10:8)
        it :: a (bound at <interactive>:10:1)

Prelude Numeric.AD.Rank1.Forward> diff (\x -> diff (auto x*) 2) 3
1
ekmett commented 3 years ago

I don't see this issue ever going away with Haskell's notion of (*) :: Num a => a -> a -> a requiring both sides to have the same type. We can work around it by offering folks auto or (*^) and (^*), but without a custom numeric prelude that blurs the lines between scalars and vectors and then only infers forward not backwards, and is literally incompatible with the desugaring applied to integers, and so is incompatible with literally all other haskell numerics this seems fundamentally unsolvable.

cartazio commented 3 years ago

What would the types of the *^ be?

On Sun, Feb 14, 2021 at 11:47 PM Edward Kmett notifications@github.com wrote:

I don't see this issue ever going away with Haskell's notion of () :: Num a => a -> a -> a requiring both sides to have the same type. We can work around it by offering folks auto or (^) and (^*), but without a custom numeric prelude that blurs the lines between scalars and vectors and then only infers forward not backwards, and is literally incompatible with the desugaring applied to integers, and so is incompatible with literally all other haskell numerics this seems fundamentally unsolvable.

— You are receiving this because you are subscribed to this thread. Reply to this email directly, view it on GitHub https://github.com/ekmett/ad/issues/60#issuecomment-778934674, or unsubscribe https://github.com/notifications/unsubscribe-auth/AAABBQUZ33YVC775QMOIPIDS7CRORANCNFSM4CYOG26Q .

ekmett commented 3 years ago

(*^) multiplies whatever the 'scalar' type is for the mode, treating the ad type as an algebra over the basic scalar. It already exists inside Numeric.AD.Mode (or Jacobian). basically it is equivalent to x *^ y = auto x * y