google-research / torchsde

Differentiable SDE solvers with GPU support and efficient sensitivity analysis.
Apache License 2.0
1.56k stars 196 forks source link

>0.2.0 feature list #47

Open patrick-kidger opened 4 years ago

patrick-kidger commented 4 years ago

Creating a list of potential features that may be nice to have, but aren't necessarily a priority right now.

Tests:

Maybe?

jparkhill commented 3 years ago

My number one desired feature is antithetic sampling as an option for sdeint. It's pretty cumbersome to achieve this without editing the package by changing the BrownianInterval's W.

patrick-kidger commented 3 years ago

I've not filled in every detail, but I'd have thought something like this should work:

class AntitheticBrownian(BaseBrownian):
   def __init__(self, bm):
       self.bm = bm

    def __call__(self, ta, tb):
        return -self.bm(ta, tb)

bm = BrownianInterval(...)
ys = torchsde(bm=bm, ...)

abm = AntitheticBrownian(bm)
ays = torchsde(bm=abm, ...)

ys = torch.cat([ys, ays])

Does this approach fail / am I missing something / are you trying to achieve something beyond this?

jparkhill commented 3 years ago

Does work, but it's still much uglier than it needs to be vs sdeint(...,antithetic=True). For innumerable financial applications of this library, this type of option is... priceless ;p Here's a filled in version in case anyone else is following along:


ts = tch.linspace(0,1.,365)
ntraj = 1000
bm = torchsde.BrownianInterval(ts[0], ts[-1], size=(ntraj,sde.brownian_size), levy_area_approximation='space-time')
ys_ = torchsde.sdeint(sde,sde.y0(ntraj=ntraj), ts, bm=bm)
class AntitheticBrownian(torchsde.BrownianInterval):
    def __init__(self, t0, t1, size, bm):
        super(AntitheticBrownian, self).__init__(t0,t1,size, levy_area_approximation='space-time')
        self.bm = bm
    def __call__(self, ta, tb=None, return_U=False, return_A=False):
        Z = self.bm(ta, tb, return_U, return_A)
        if return_U:
            if return_A:
                return -Z[0], Z[1], Z[2]
            else:
                return -Z[0], Z[1]
        else:
            if return_A:
                return -Z[0], Z[1]
            else:
                return -Z
abm = AntitheticBrownian(ts[0], ts[-1], (ntraj,sde.brownian_size), bm)
ays = torchsde.sdeint(sde,sde.y0(ntraj=ntraj), ts, bm=abm)
ys = torch.cat([ys_, ays],1)```