def setUp(self):
     k = 3.0
     nspots = 8
     spot_max = 1500.0
     spotdensity = 7.0  # infinity is linear?
     spots = utils.sinh_space(k, spot_max, spotdensity, nspots)
     self.flip_idx = 4
     self.vec = spots
     self.C1 = FD.BO.for_vector(self.vec, scheme='center', derivative=1, order=2)
Exemple #2
0
 def setUp(self):
     spot_max = 1500.0
     var_max = 13.0
     nspots = 50
     nvols = 30
     spotdensity = 7.0  # infinity is linear?
     varexp = 4
     self.strike = spot_max / 4.0
     self.spots = utils.sinh_space(self.strike, spot_max, spotdensity, nspots)
     self.vars = utils.exponential_space(0.00, 0.04, var_max, varexp, nvols)
     self.Grid = Grid.Grid((self.spots, self.vars),
             initializer=lambda x0,x1: np.maximum(x0-self.strike,0))
    def setUp(self):
        k = 3.0
        nspots = 7
        spot_max = 1500.0
        spotdensity = 7.0  # infinity is linear?
        vec = utils.sinh_space(k, spot_max, spotdensity, nspots)
        self.vec = vec

        def coeff(high,low=None):
            if low is not None:
                high, low = low, high
            return np.linspace(0, 1, len(vec))[low:high]
        def fcoeff(i):
            return np.linspace(0, 1, len(vec))[i]
        def f0(x): return x*0.0
        def fx(x): return x+2.0

        data = np.ones((5,len(vec)))
        data[0][:2] = 0
        data[1][0] = 0
        data[3][-1] = 0
        data[4][-2:] = 0
        offsets = [2,1,0,-1,-2]
        res = np.ones_like(vec)
        oldB = FD.BandedOperator((data, offsets), res)
        self.oldB = oldB

        manualB = oldB.copy()
        # newB = oldB.copy()
        # vecB = oldB.copy()
        manualB.D.data[0][2:] *= coeff(len(vec)-2)
        manualB.D.data[1][1:] *= coeff(len(vec)-1)
        manualB.D.data[2] *= coeff(len(vec))
        manualB.D.data[3][:-1] *= coeff(1, len(vec))
        manualB.D.data[4][:-2] *= coeff(2, len(vec))
        manualB.R *= coeff(len(vec))

        self.manualB = manualB

        self.coeff = coeff
        self.fcoeff = fcoeff
        self.f0 = f0
        self.fx = fx
Exemple #4
0
    mean_variance=0.04,
    vol_of_variance=0.4,
    correlation=0.6,
)

dt = 1 / 100.0
spot_max = 1500.0
var_max = 10.0

nspots = 100
nvols = 100

spotdensity = 7.0  # infinity is linear?
varexp = 4

spots = utils.sinh_space(H.strike, spot_max, spotdensity, nspots)
vars = utils.exponential_space(0.00, H.variance.value, var_max, varexp, nvols)
# vars = [v0]
# spots = np.linspace(0.0, spot_max, nspots)
# vars = np.linspace(0.0, var_max, nvols)
# plot(spots); title("Spots"); show()
# plot(vars); title("Vars"); show()

# H.strike = spots[min(abs(spots - H.strike)) == abs(spots - H.strike)][0]
# H.spot = spots[min(abs(spots - H.spot)) == abs(spots - H.spot)][0]
def init(spots, vars):
    return np.maximum(0, spots - H.strike)


Gi = Grid(mesh=(spots, vars), initializer=init)
G = Gi.copy()
Exemple #5
0
    def setUp(self):
        s1_enable = 1
        s2_enable = 1
        v1_enable = 1
        v2_enable = 1
        r_enable = 1
        dirichlet_s = 1
        dirichlet_v = 1
        kappa = 1
        r = 0.06
        theta = 0.04
        sigma = 0.4
        rho = 0.6
        spot_max = 1500.0
        var_max = 13.0
        nspots = 5
        nvols = 5
        spotdensity = 7.0  # infinity is linear?
        varexp = 5

        up_or_down_spot = 'up'
        up_or_down_var = 'down'
        flip_idx_spot = nspots // 2
        flip_idx_var = nvols // 2
        k = spot_max / 4.0
        # spots = np.linspace(0, spot_max, nspots)
        # vars = np.linspace(0, var_max, nvols)
        spots = utils.sinh_space(k, spot_max, spotdensity, nspots)
        vars = utils.exponential_space(0.00, 0.04, var_max, varexp, nvols)

        def mu_s(t, *dim):
            return r * dim[0] * s1_enable

        def gamma2_s(t, *dim):
            return 0.5 * dim[1] * dim[0]**2 * s2_enable

        def mu_v(t, *dim):
            return kappa * (theta - dim[1]) * v1_enable

        def gamma2_v(t, *dim):
            return 0.5 * sigma**2 * dim[1] * v2_enable

        coeffs = {
            (): lambda t: -r * r_enable,
            (0, ): mu_s,
            (0, 0): gamma2_s,
            (1, ): mu_v,
            (1, 1): gamma2_v,
            (0, 1): lambda t, *dim: dim[0] * dim[1] * rho * sigma
        }
        coeffs = {k: lambda *x: 1 for k in coeffs}
        bounds = {
            (0, ): ((0, lambda *args: 0), (1, lambda *args: 1)),
            (0, 0): ((0, lambda *args: 0), (None, lambda *args: 1)),
            (1, ): ((None, lambda *args: None), (None, lambda *args: None)),
            (1, 1): ((1, lambda *args: 0.0), (None, lambda *args: None)),
        }

        schemes = {}
        # G = Grid.Grid((spots, vars), initializer=lambda x0,x1: np.maximum(x0-k,0))
        self.G = Grid.Grid((spots, vars), initializer=lambda x0, x1: x0 * x1)
        # print G

        self.F = FD.FiniteDifferenceEngineADI(self.G,
                                              coefficients=coeffs,
                                              boundaries=bounds,
                                              schemes=schemes,
                                              force_bandwidth=None)
        self.F.init()
        # self.F.operators[1].diagonalize()
        self.FG = FDG.FiniteDifferenceEngineADI()
        self.FG.from_host_FiniteDifferenceEngine(self.F)
Exemple #6
0
    def setUp(self):
        s1_enable = 1
        s2_enable = 1
        v1_enable = 1
        v2_enable = 1
        r_enable = 1
        dirichlet_s = 1
        dirichlet_v = 1
        kappa = 1
        r = 0.06
        theta = 0.04
        sigma = 0.4
        rho = 0.6
        spot_max = 1500.0
        var_max = 13.0
        nspots = 5
        nvols = 5
        spotdensity = 7.0  # infinity is linear?
        varexp = 5

        # TODO:!!!!XXX TODO XXX
        # var_max = nvols-1
        # spot_max = nspots-1

        up_or_down_spot = 'up'
        up_or_down_var = 'down'
        flip_idx_spot = nspots // 2
        flip_idx_var = nvols // 2
        k = spot_max / 4.0
        # spots = np.linspace(0, spot_max, nspots)
        # vars = np.linspace(0, var_max, nvols)
        spots = utils.sinh_space(k, spot_max, spotdensity, nspots)
        vars = utils.exponential_space(0.00, 0.04, var_max, varexp, nvols)

        def mu_s(t, *dim):
            return r * dim[0] * s1_enable

        def gamma2_s(t, *dim):
            return 0.5 * dim[1] * dim[0]**2 * s2_enable

        def mu_v(t, *dim):
            return kappa * (theta - dim[1]) * v1_enable

        def gamma2_v(t, *dim):
            return 0.5 * sigma**2 * dim[1] * v2_enable

        coeffs = {
            (): lambda t: -r * r_enable,
            (0, ): mu_s,
            (0, 0): gamma2_s,
            (1, ): mu_v,
            (1, 1): gamma2_v,
            (0, 1): lambda t, *dim: dim[0] * dim[1] * rho * sigma
        }
        bounds = {
            # D: U = 0              VN: dU/dS = 1
            (
                0, ): ((0 if dirichlet_s else 1, lambda *args: 0.0),
                       (1, lambda *args: 1.0)),
            # D: U = 0              Free boundary
            (0, 0): ((0 if dirichlet_s else 1, lambda *args: 0.0),
                     (None, lambda *x: 1.0)),
            # Free boundary at low variance
            (
                1, ): (
                (None, lambda *x: None),
                # (0.0, lambda t, *dim: 0),
                # D intrinsic value at high variance
                # (None, lambda *x: None)
                (0 if dirichlet_v else 1,
                 lambda t, *dim: np.maximum(0.0, dim[0] - k))),
            # # Free boundary
            (1, 1): (
                (1, lambda *x: 0),
                # D intrinsic value at high variance
                # (None, lambda *x: None)
                (0 if dirichlet_v else 1,
                 lambda t, *dim: np.maximum(0.0, dim[0] - k)))
        }

        schemes = {}
        schemes[(0, )] = ({
            "scheme": "center"
        }, {
            "scheme": up_or_down_spot,
            "from": flip_idx_spot
        })
        schemes[(1, )] = ({
            "scheme": "center"
        }, {
            "scheme": up_or_down_var,
            "from": flip_idx_var
        })

        dss = np.hstack((np.nan, np.diff(spots)))
        dvs = np.hstack((np.nan, np.diff(vars)))
        As_ = utils.nonuniform_complete_coefficients(
            dss, up_or_down=up_or_down_spot, flip_idx=flip_idx_spot)[0]
        Ass_ = utils.nonuniform_complete_coefficients(dss)[1]
        L1_ = []
        R1_ = []
        # As_, Ass_ = utils.nonuniform_forward_coefficients(dss)
        assert (not np.isnan(As_.data).any())
        assert (not np.isnan(Ass_.data).any())
        for j, v in enumerate(vars):
            # Be careful not to overwrite operators
            As, Ass = As_.copy(), Ass_.copy()
            m = 2

            mu_s = r * spots * s1_enable
            gamma2_s = 0.5 * v * spots**2 * s2_enable
            for i, z in enumerate(mu_s):
                # print z, coeffs[0,](0, spots[i])
                assert z == coeffs[0, ](0, spots[i])
            for i, z in enumerate(gamma2_s):
                # print z, coeffs[0,0](0, spots[i], v)
                assert z == coeffs[0, 0](0, spots[i], v)

            Rs = np.zeros(nspots)
            Rs[-1] = 1

            As.data[m - 2, 2:] *= mu_s[:-2]
            As.data[m - 1, 1:] *= mu_s[:-1]
            As.data[m, :] *= mu_s
            As.data[m + 1, :-1] *= mu_s[1:]
            As.data[m + 2, :-2] *= mu_s[2:]

            Rs *= mu_s

            Rss = np.zeros(nspots)
            Rss[-1] = 2 * dss[-1] / dss[-1]**2

            Ass.data[m + 1, -2] = 2 / dss[-1]**2
            Ass.data[m, -1] = -2 / dss[-1]**2

            Ass.data[m - 2, 2:] *= gamma2_s[:-2]
            Ass.data[m - 1, 1:] *= gamma2_s[:-1]
            Ass.data[m, :] *= gamma2_s
            Ass.data[m + 1, :-1] *= gamma2_s[1:]
            Ass.data[m + 2, :-2] *= gamma2_s[2:]

            Rss *= gamma2_s

            L1_.append(As.copy())
            L1_[j].data += Ass.data
            L1_[j].data[m, :] -= 0.5 * r * r_enable
            L1_[j].data[m, 0] = 1 * dirichlet_s

            R1_.append((Rs + Rss).copy())
            R1_[j][0] = 0

        L2_ = []
        R2_ = []
        Av_ = utils.nonuniform_complete_coefficients(dvs,
                                                     up_or_down=up_or_down_var,
                                                     flip_idx=flip_idx_var)[0]
        Avv_ = utils.nonuniform_complete_coefficients(dvs)[1]
        assert (not np.isnan(Av_.data).any())
        assert (not np.isnan(Avv_.data).any())
        for i, s in enumerate(spots):
            mu_v = kappa * (theta - vars) * v1_enable
            gamma2_v = 0.5 * sigma**2 * vars * v2_enable
            # for j, z in enumerate(mu_v):
            # assert z == coeffs[1,](0, 0, vars[j])
            # for j, z in enumerate(gamma2_v):
            # assert z == coeffs[1,1](0, 0, vars[j])

            # Be careful not to overwrite our operators
            Av, Avv = Av_.copy(), Avv_.copy()

            m = 2

            Av.data[m - 2, 2] = -dvs[1] / (dvs[2] * (dvs[1] + dvs[2]))
            Av.data[m - 1, 1] = (dvs[1] + dvs[2]) / (dvs[1] * dvs[2])
            Av.data[m,
                    0] = (-2 * dvs[1] - dvs[2]) / (dvs[1] * (dvs[1] + dvs[2]))

            Av.data[m - 2, 2:] *= mu_v[:-2]
            Av.data[m - 1, 1:] *= mu_v[:-1]
            Av.data[m, :] *= mu_v
            Av.data[m + 1, :-1] *= mu_v[1:]
            Av.data[m + 2, :-2] *= mu_v[2:]

            Rv = np.zeros(nvols)
            Rv *= mu_v

            Avv.data[m - 1, 1] = 2 / dvs[1]**2
            Avv.data[m, 0] = -2 / dvs[1]**2

            Avv.data[m - 2, 2:] *= gamma2_v[:-2]
            Avv.data[m - 1, 1:] *= gamma2_v[:-1]
            Avv.data[m, :] *= gamma2_v
            Avv.data[m + 1, :-1] *= gamma2_v[1:]
            Avv.data[m + 2, :-2] *= gamma2_v[2:]

            Rvv = np.zeros(nvols)
            Rvv[0] = 2 * dvs[1] / dvs[1]**2
            Rvv *= gamma2_v

            L2_.append(Av.copy())
            L2_[i].data += Avv.data
            L2_[i].data[m, :] -= 0.5 * r * r_enable
            L2_[i].data[
                m,
                -1] = 1 * dirichlet_v  # This is to cancel out the previous value so we can
            # set the dirichlet boundary condition using R.
            # Then we have U_i + -U_i + R

            R2_.append(Rv + Rvv)
            R2_[i][-1] = 0  # np.maximum(0, s - k)

        def flatten_tensor(mats):
            diags = np.hstack([x.data for x in mats])
            flatmat = scipy.sparse.dia_matrix(
                (diags, mats[0].offsets),
                shape=(diags.shape[1], diags.shape[1]))
            return flatmat

        L1 = flatten_tensor(L1_)
        L2 = flatten_tensor(L2_)
        R1 = np.array(R1_).T
        R2 = np.array(R2_)

        self.As_ = As_
        self.Ass_ = Ass_
        self.L1_ = L1
        self.R1_ = R1
        self.L2_ = L2
        self.R2_ = R2
        # G = Grid.Grid((spots, vars), initializer=lambda x0,x1: np.maximum(x0-k,0))
        self.G = Grid.Grid((spots, vars), initializer=lambda x0, x1: x0 * x1)
        # print G

        self.F = FD.FiniteDifferenceEngineADI(self.G,
                                              coefficients=coeffs,
                                              boundaries=bounds,
                                              schemes=schemes,
                                              force_bandwidth=None)
        self.F.init()
    def setUp(self):
        s1_enable = 1
        s2_enable = 1
        v1_enable = 1
        v2_enable = 1
        r_enable = 1
        dirichlet_s = 1
        dirichlet_v = 1
        kappa = 1
        r = 0.06
        theta = 0.04
        sigma = 0.4
        rho = 0.6
        spot_max = 1500.0
        var_max = 13.0
        nspots = 5
        nvols = 5
        spotdensity = 7.0  # infinity is linear?
        varexp = 5

        up_or_down_spot = 'up'
        up_or_down_var = 'down'
        flip_idx_spot = nspots//2
        flip_idx_var = nvols//2
        k = spot_max / 4.0
        # spots = np.linspace(0, spot_max, nspots)
        # vars = np.linspace(0, var_max, nvols)
        spots = utils.sinh_space(k, spot_max, spotdensity, nspots)
        vars = utils.exponential_space(0.00, 0.04, var_max, varexp, nvols)
        def mu_s(t, *dim): return r * dim[0] * s1_enable
        def gamma2_s(t, *dim): return 0.5 * dim[1] * dim[0]**2 * s2_enable

        def mu_v(t, *dim): return kappa * (theta - dim[1]) * v1_enable
        def gamma2_v(t, *dim): return 0.5 * sigma**2 * dim[1] * v2_enable

        coeffs = {()   : lambda t: -r * r_enable,
                  (0,) : mu_s,
                  (0,0): gamma2_s,
                  (1,) : mu_v,
                  (1,1): gamma2_v,
                  (0,1): lambda t, *dim: dim[0] * dim[1] * rho * sigma
                  }
        coeffs = {k: lambda *x: 1 for k in coeffs}
        bounds = {
                (0,)  : ((0,    lambda *args: 0),    (1,    lambda *args: 1)),
                (0,0) : ((0,    lambda *args: 0),    (None, lambda *args: 1)),
                (1,)  : ((None, lambda *args: None), (None, lambda *args: None)),
                (1,1) : ((1,    lambda *args: 0.0),  (None, lambda *args: None)),
                }

        schemes = {}
        # G = Grid.Grid((spots, vars), initializer=lambda x0,x1: np.maximum(x0-k,0))
        self.G = Grid.Grid((spots, vars), initializer=lambda x0,x1: x0*x1)
        # print G

        self.F = FD.FiniteDifferenceEngineADI(self.G, coefficients=coeffs,
                boundaries=bounds, schemes=schemes, force_bandwidth=None)
        self.F.init()
        # self.F.operators[1].diagonalize()
        self.FG = FDG.FiniteDifferenceEngineADI()
        self.FG.from_host_FiniteDifferenceEngine(self.F)
    def setUp(self):
        s1_enable = 1
        s2_enable = 1
        v1_enable = 1
        v2_enable = 1
        r_enable = 1
        dirichlet_s = 1
        dirichlet_v = 1
        kappa = 1
        r = 0.06
        theta = 0.04
        sigma = 0.4
        rho = 0.6
        spot_max = 1500.0
        var_max = 13.0
        nspots = 5
        nvols = 5
        spotdensity = 7.0  # infinity is linear?
        varexp = 5

        # TODO:!!!!XXX TODO XXX
        # var_max = nvols-1
        # spot_max = nspots-1

        up_or_down_spot = "up"
        up_or_down_var = "down"
        flip_idx_spot = nspots // 2
        flip_idx_var = nvols // 2
        k = spot_max / 4.0
        # spots = np.linspace(0, spot_max, nspots)
        # vars = np.linspace(0, var_max, nvols)
        spots = utils.sinh_space(k, spot_max, spotdensity, nspots)
        vars = utils.exponential_space(0.00, 0.04, var_max, varexp, nvols)

        def mu_s(t, *dim):
            return r * dim[0] * s1_enable

        def gamma2_s(t, *dim):
            return 0.5 * dim[1] * dim[0] ** 2 * s2_enable

        def mu_v(t, *dim):
            return kappa * (theta - dim[1]) * v1_enable

        def gamma2_v(t, *dim):
            return 0.5 * sigma ** 2 * dim[1] * v2_enable

        coeffs = {
            (): lambda t: -r * r_enable,
            (0,): mu_s,
            (0, 0): gamma2_s,
            (1,): mu_v,
            (1, 1): gamma2_v,
            (0, 1): lambda t, *dim: dim[0] * dim[1] * rho * sigma,
        }
        bounds = {
            # D: U = 0              VN: dU/dS = 1
            (0,): ((0 if dirichlet_s else 1, lambda *args: 0.0), (1, lambda *args: 1.0)),
            # D: U = 0              Free boundary
            (0, 0): ((0 if dirichlet_s else 1, lambda *args: 0.0), (None, lambda *x: 1.0)),
            # Free boundary at low variance
            (1,): (
                (None, lambda *x: None),
                # (0.0, lambda t, *dim: 0),
                # D intrinsic value at high variance
                # (None, lambda *x: None)
                (0 if dirichlet_v else 1, lambda t, *dim: np.maximum(0.0, dim[0] - k)),
            ),
            # # Free boundary
            (1, 1): (
                (1, lambda *x: 0),
                # D intrinsic value at high variance
                # (None, lambda *x: None)
                (0 if dirichlet_v else 1, lambda t, *dim: np.maximum(0.0, dim[0] - k)),
            ),
        }

        schemes = {}
        schemes[(0,)] = ({"scheme": "center"}, {"scheme": up_or_down_spot, "from": flip_idx_spot})
        schemes[(1,)] = ({"scheme": "center"}, {"scheme": up_or_down_var, "from": flip_idx_var})

        dss = np.hstack((np.nan, np.diff(spots)))
        dvs = np.hstack((np.nan, np.diff(vars)))
        As_ = utils.nonuniform_complete_coefficients(dss, up_or_down=up_or_down_spot, flip_idx=flip_idx_spot)[0]
        Ass_ = utils.nonuniform_complete_coefficients(dss)[1]
        L1_ = []
        R1_ = []
        # As_, Ass_ = utils.nonuniform_forward_coefficients(dss)
        assert not np.isnan(As_.data).any()
        assert not np.isnan(Ass_.data).any()
        for j, v in enumerate(vars):
            # Be careful not to overwrite operators
            As, Ass = As_.copy(), Ass_.copy()
            m = 2

            mu_s = r * spots * s1_enable
            gamma2_s = 0.5 * v * spots ** 2 * s2_enable
            for i, z in enumerate(mu_s):
                # print z, coeffs[0,](0, spots[i])
                assert z == coeffs[0,](0, spots[i])
            for i, z in enumerate(gamma2_s):
                # print z, coeffs[0,0](0, spots[i], v)
                assert z == coeffs[0, 0](0, spots[i], v)

            Rs = np.zeros(nspots)
            Rs[-1] = 1

            As.data[m - 2, 2:] *= mu_s[:-2]
            As.data[m - 1, 1:] *= mu_s[:-1]
            As.data[m, :] *= mu_s
            As.data[m + 1, :-1] *= mu_s[1:]
            As.data[m + 2, :-2] *= mu_s[2:]

            Rs *= mu_s

            Rss = np.zeros(nspots)
            Rss[-1] = 2 * dss[-1] / dss[-1] ** 2

            Ass.data[m + 1, -2] = 2 / dss[-1] ** 2
            Ass.data[m, -1] = -2 / dss[-1] ** 2

            Ass.data[m - 2, 2:] *= gamma2_s[:-2]
            Ass.data[m - 1, 1:] *= gamma2_s[:-1]
            Ass.data[m, :] *= gamma2_s
            Ass.data[m + 1, :-1] *= gamma2_s[1:]
            Ass.data[m + 2, :-2] *= gamma2_s[2:]

            Rss *= gamma2_s

            L1_.append(As.copy())
            L1_[j].data += Ass.data
            L1_[j].data[m, :] -= 0.5 * r * r_enable
            L1_[j].data[m, 0] = 1 * dirichlet_s

            R1_.append((Rs + Rss).copy())
            R1_[j][0] = 0

        L2_ = []
        R2_ = []
        Av_ = utils.nonuniform_complete_coefficients(dvs, up_or_down=up_or_down_var, flip_idx=flip_idx_var)[0]
        Avv_ = utils.nonuniform_complete_coefficients(dvs)[1]
        assert not np.isnan(Av_.data).any()
        assert not np.isnan(Avv_.data).any()
        for i, s in enumerate(spots):
            mu_v = kappa * (theta - vars) * v1_enable
            gamma2_v = 0.5 * sigma ** 2 * vars * v2_enable
            # for j, z in enumerate(mu_v):
            # assert z == coeffs[1,](0, 0, vars[j])
            # for j, z in enumerate(gamma2_v):
            # assert z == coeffs[1,1](0, 0, vars[j])

            # Be careful not to overwrite our operators
            Av, Avv = Av_.copy(), Avv_.copy()

            m = 2

            Av.data[m - 2, 2] = -dvs[1] / (dvs[2] * (dvs[1] + dvs[2]))
            Av.data[m - 1, 1] = (dvs[1] + dvs[2]) / (dvs[1] * dvs[2])
            Av.data[m, 0] = (-2 * dvs[1] - dvs[2]) / (dvs[1] * (dvs[1] + dvs[2]))

            Av.data[m - 2, 2:] *= mu_v[:-2]
            Av.data[m - 1, 1:] *= mu_v[:-1]
            Av.data[m, :] *= mu_v
            Av.data[m + 1, :-1] *= mu_v[1:]
            Av.data[m + 2, :-2] *= mu_v[2:]

            Rv = np.zeros(nvols)
            Rv *= mu_v

            Avv.data[m - 1, 1] = 2 / dvs[1] ** 2
            Avv.data[m, 0] = -2 / dvs[1] ** 2

            Avv.data[m - 2, 2:] *= gamma2_v[:-2]
            Avv.data[m - 1, 1:] *= gamma2_v[:-1]
            Avv.data[m, :] *= gamma2_v
            Avv.data[m + 1, :-1] *= gamma2_v[1:]
            Avv.data[m + 2, :-2] *= gamma2_v[2:]

            Rvv = np.zeros(nvols)
            Rvv[0] = 2 * dvs[1] / dvs[1] ** 2
            Rvv *= gamma2_v

            L2_.append(Av.copy())
            L2_[i].data += Avv.data
            L2_[i].data[m, :] -= 0.5 * r * r_enable
            L2_[i].data[m, -1] = 1 * dirichlet_v  # This is to cancel out the previous value so we can
            # set the dirichlet boundary condition using R.
            # Then we have U_i + -U_i + R

            R2_.append(Rv + Rvv)
            R2_[i][-1] = 0  # np.maximum(0, s - k)

        def flatten_tensor(mats):
            diags = np.hstack([x.data for x in mats])
            flatmat = scipy.sparse.dia_matrix((diags, mats[0].offsets), shape=(diags.shape[1], diags.shape[1]))
            return flatmat

        L1 = flatten_tensor(L1_)
        L2 = flatten_tensor(L2_)
        R1 = np.array(R1_).T
        R2 = np.array(R2_)

        self.As_ = As_
        self.Ass_ = Ass_
        self.L1_ = L1
        self.R1_ = R1
        self.L2_ = L2
        self.R2_ = R2
        # G = Grid.Grid((spots, vars), initializer=lambda x0,x1: np.maximum(x0-k,0))
        self.G = Grid.Grid((spots, vars), initializer=lambda x0, x1: x0 * x1)
        # print G

        self.F = FD.FiniteDifferenceEngineADI(
            self.G, coefficients=coeffs, boundaries=bounds, schemes=schemes, force_bandwidth=None
        )
        self.F.init()