Coder Social home page Coder Social logo

du failing on simple function about ad HOT 13 OPEN

ekmett avatar ekmett commented on September 2, 2024
du failing on simple function

from ad.

Comments (13)

barak avatar barak commented on September 2, 2024

(I understand that duF can do it. But that is something of a wart! These things should be unified. Maybe the type system isn't up to it, but if so, we should whine about the deficient type system when explaining the plethora of suffixes for various shapes of input and output.)

from ad.

cartazio avatar cartazio commented on September 2, 2024
Prelude Numeric.AD> :t du
du
  :: (Num a, Functor f) =>
     (forall s.
      f (AD s (Numeric.AD.Internal.Forward.Forward a))
      -> AD s (Numeric.AD.Internal.Forward.Forward a))
     -> f (a, a) -> a

if your function had the type

foo :: Num a => [a]-> a
foo [x,y]= x*y

then everything works fine

Prelude Numeric.AD> let foo [x,y]= x*y
Prelude Numeric.AD> du foo [(1,0),(2,8)]
8

from ad.

cartazio avatar cartazio commented on September 2, 2024

Are you suggesting that perhaps every value thats not wrapped in a Functor should be considered to be implicitly lifted into the identity functor? Thats what it sounds like, But in that case du would be the wrong type, and duF would become the default, right?

from ad.

barak avatar barak commented on September 2, 2024

I guess that's one way to think about it.

In more mathematical terms, the "tangent space" is always a vector space. I directional derivative maps a point on the input tangent space to the output tangent space. Which is clean and unified. Having the tangent spaces come in different "shapes" with different derivative-taking operators to deal with them depending on shape is sort of annoying. And worse, we could have something like

f :: Num a => ([[[a]]],[[a]],[a]) -> (a,[a],[[[[a]]]])

which makes complete sense to take a directional derivative of, but which doesn't fit into any of our cases.

from ad.

cartazio avatar cartazio commented on September 2, 2024

false, it fits in that regime like so

Prelude Numeric.AD> :t duF
duF
  :: (Num a, Functor g, Functor f) =>
     (forall s.
      f (AD s (Numeric.AD.Internal.Forward.Forward a))
      -> g (AD s (Numeric.AD.Internal.Forward.Forward a)))
     -> f (a, a) -> g a

just writing down the defn for duF for now

newtype F a = F ([[[a]]],[[a]],[a])
   deriving Functor 
newtype G a = G  (a,[a],[[[[a]]]])
   deriving Functor 

f:: Num a => F a -> G a

this f using G and F is trivially a wrapping of your proposed problematic f,
BUT duF works just fine for that example

from ad.

cartazio avatar cartazio commented on September 2, 2024

Or maybe I'm not understanding what you mean by directional derivative!

from ad.

cartazio avatar cartazio commented on September 2, 2024

what would a direction derive look like in that context/example? I'm imagining it being semantically equivalent to a big flattened version of a list

from ad.

ekmett avatar ekmett commented on September 2, 2024

I frankly don't see a plausible way to do unify these things.

Yes, types get in the way some times, and in this case they force a distinction.

You could argue that duF should actually be du, and that everyone who wants the simpler case should have to pay for an Identity wrapper or some nonsense, but we do carefully distinguish between the cases that take and/or return vectors throughout the API, and I don't see that changing.

To go far enough to get you what you want we have to throw out the entire numeric tower, because Num mixes (+) in with (*), etc.

That isn't happening, not with keeping any users.

from ad.

ekmett avatar ekmett commented on September 2, 2024

The only way this is going to change is if we adopt something like #2, which would have pretty far reaching consequences on the API. I'll leave this issue open as a sort of adjunct / example for that one.

from ad.

barak avatar barak commented on September 2, 2024

We could use fancy types, let the type constraint Tang t tt mean that the tangent type of t is tt, have things like (Tang t tt, Tang u uu) => Tang (t,u) (tt,uu) and Tang t tt => Tang [t] [tt] and such. This works fine except when you get to numbers, where it gets tricky because if someone was silly and defined something like Num a => Num [a] then you'd lose, so the system lets you ground the definitions in concrete things like Double but not in Num.

(Naturally this would need an API, the obvious one would be zero :: Tang t tt => t -> tt to get a zero element of the tangent space, and addition and scalar product inside the vector space, and maybe something to "take a step in this direction" with type t -> s -> tt -> t, where s is a step size of the appropriate numeric type. Thinking about that makes one think the type constraint should have a third slot for the base numeric type. Or else something more complicated to allow a mixture of numeric types...)

from ad.

ekmett avatar ekmett commented on September 2, 2024

Losing access to AD over arbitrary Num types isn't really an option. A number of the users of this library use it at some pretty exotic types!

You can avoid the base case issue by doing what we do with the AD wrapper when we want to work abstractly over the choice of Mode, we can't make the instance to know m a is a Num for all modes m, but something like AD m a can have such an instance. Such a beast would also have the slot for the base numeric type.

The problem is I don't think the technique you propose and having the rank-2 guard against infinitesimal confusion can't work together. There isn't a regular 'place' in the type for the region/infinitesimal parameter, as it is changing position all over the place moving under more functors layers, etc.

from ad.

barak avatar barak commented on September 2, 2024

Wouldn't that "brand" type go in the constraint but not the instance, so it could be the same in the various constraints on the LHS of the instance declaration. (With the appropriate extension enabled.)

from ad.

ekmett avatar ekmett commented on September 2, 2024

The "brand" can't float in the constraint without actually showing up in a type somewhere. You could almost kind of fake it with implicit parameters, but then they'd yield totally bogus results when it comes to 'diff of diff', rather than just making you insert autos to get it to compile.

from ad.

Related Issues (20)

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.