예제 #1
0
def test_harmonic_oscillator_errors():
    """
    Make sure the errors produced by fitting ODE's are the same as when
    fitting an exact solution.
    """
    x, v, t = sf.variables('x, v, t')
    k = sf.Parameter(name='k', value=100)
    m = 1
    a = -k/m * x
    ode_model = sf.ODEModel({sf.D(v, t): a,
                             sf.D(x, t): v},
                            initial={t: 0, v: 0, x: 1})

    t_data = np.linspace(0, 10, 250)
    np.random.seed(2)
    noise = np.random.normal(1, 0.05, size=t_data.shape)
    x_data = ode_model(t=t_data, k=100).x * noise

    ode_fit = sf.Fit(ode_model, t=t_data, x=x_data, v=None)
    ode_result = ode_fit.execute()

    phi = 0
    A = 1
    model = sf.Model({x: A * sf.cos(sf.sqrt(k/m) * t + phi)})
    fit = sf.Fit(model, t=t_data, x=x_data)
    result = fit.execute()

    assert result.value(k) == pytest.approx(ode_result.value(k), 1e-4)
    assert result.stdev(k) == pytest.approx(ode_result.stdev(k), 1e-2)
    assert result.stdev(k) >= ode_result.stdev(k)
예제 #2
0
    def test_harmonic_oscillator_errors(self):
        """
        Make sure the errors produced by fitting ODE's are the same as when
        fitting an exact solution.
        """
        x, v, t = sf.variables('x, v, t')
        k = sf.Parameter(name='k', value=100)
        m = 1
        a = -k/m * x
        ode_model = sf.ODEModel({sf.D(v, t): a,
                                 sf.D(x, t): v},
                                initial={t: 0, v: 0, x: 1})

        t_data = np.linspace(0, 10, 250)
        np.random.seed(2)
        noise = np.random.normal(1, 0.05, size=t_data.shape)
        x_data = ode_model(t=t_data, k=100).x * noise

        ode_fit = sf.Fit(ode_model, t=t_data, x=x_data)
        ode_result = ode_fit.execute()

        phi = 0
        A = 1
        model = sf.Model({x: A * sf.cos(sf.sqrt(k/m) * t + phi)})
        fit = sf.Fit(model, t=t_data, x=x_data)
        result = fit.execute()

        self.assertAlmostEqual(result.value(k), ode_result.value(k), places=4)
        self.assertAlmostEqual(result.stdev(k) / ode_result.stdev(k), 1, 2)
        self.assertGreaterEqual(result.stdev(k), ode_result.stdev(k))
예제 #3
0
    def test_interdependency_constrained(self):
        """
        Test a model with interdependent components, and with constraints which
        depend on the Model's output.
        This is done in the MatrixSymbol formalism, using a Tikhonov
        regularization as an example. In this, a matrix inverse has to be
        calculated and is used multiple times. Therefore we split that term of
        into a seperate component, so the inverse only has to be computed once
        per model call.

        See https://arxiv.org/abs/1901.05348 for a more detailed background.
        """
        N = Symbol('N', integer=True)
        M = MatrixSymbol('M', N, N)
        W = MatrixSymbol('W', N, N)
        I = MatrixSymbol('I', N, N)
        y = MatrixSymbol('y', N, 1)
        c = MatrixSymbol('c', N, 1)
        a, = parameters('a')
        z, = variables('z')
        i = Idx('i')

        model_dict = {
            W: Inverse(I + M / a ** 2),
            c: - W * y,
            z: sqrt(c.T * c)
        }
        # Sympy currently does not support derivatives of matrix expressions,
        # so we use CallableModel instead of Model.
        model = CallableModel(model_dict)

        # Generate data
        iden = np.eye(2)
        M_mat = np.array([[2, 1], [3, 4]])
        y_vec = np.array([[3], [5]])
        eval_model = model(I=iden, M=M_mat, y=y_vec, a=0.1)
        # Calculate the answers 'manually' so I know it was done properly
        W_manual = np.linalg.inv(iden + M_mat / 0.1 ** 2)
        c_manual = - np.atleast_2d(W_manual.dot(y_vec))
        z_manual = np.atleast_1d(np.sqrt(c_manual.T.dot(c_manual)))

        self.assertEqual(y_vec.shape, (2, 1))
        self.assertEqual(M_mat.shape, (2, 2))
        self.assertEqual(iden.shape, (2, 2))
        self.assertEqual(W_manual.shape, (2, 2))
        self.assertEqual(c_manual.shape, (2, 1))
        self.assertEqual(z_manual.shape, (1, 1))
        np.testing.assert_almost_equal(W_manual, eval_model.W)
        np.testing.assert_almost_equal(c_manual, eval_model.c)
        np.testing.assert_almost_equal(z_manual, eval_model.z)
        fit = Fit(model, z=z_manual, I=iden, M=M_mat, y=y_vec)
        fit_result = fit.execute()

        # See if a == 0.1 was reconstructed properly. Since only a**2 features
        # in the equations, we check for the absolute value. Setting a.min = 0.0
        # is not appreciated by the Minimizer, it seems.
        self.assertAlmostEqual(np.abs(fit_result.value(a)), 0.1)
예제 #4
0
def test_interdependency_constrained():
    """
    Test a model with interdependent components, and with constraints which
    depend on the Model's output.
    This is done in the MatrixSymbol formalism, using a Tikhonov
    regularization as an example. In this, a matrix inverse has to be
    calculated and is used multiple times. Therefore we split that term of
    into a seperate component, so the inverse only has to be computed once
    per model call.

    See https://arxiv.org/abs/1901.05348 for a more detailed background.
    """
    N = Symbol('N', integer=True)
    M = MatrixSymbol('M', N, N)
    W = MatrixSymbol('W', N, N)
    I = MatrixSymbol('I', N, N)
    y = MatrixSymbol('y', N, 1)
    c = MatrixSymbol('c', N, 1)
    a, = parameters('a')
    z, = variables('z')
    i = Idx('i')

    model_dict = {W: Inverse(I + M / a**2), c: -W * y, z: sqrt(c.T * c)}
    # Sympy currently does not support derivatives of matrix expressions,
    # so we use CallableModel instead of Model.
    model = CallableModel(model_dict)

    # Generate data
    iden = np.eye(2)
    M_mat = np.array([[2, 1], [3, 4]])
    y_vec = np.array([[3], [5]])
    eval_model = model(I=iden, M=M_mat, y=y_vec, a=0.1)
    # Calculate the answers 'manually' so I know it was done properly
    W_manual = np.linalg.inv(iden + M_mat / 0.1**2)
    c_manual = -np.atleast_2d(W_manual.dot(y_vec))
    z_manual = np.atleast_1d(np.sqrt(c_manual.T.dot(c_manual)))

    assert y_vec.shape == (2, 1)
    assert M_mat.shape == (2, 2)
    assert iden.shape == (2, 2)
    assert W_manual.shape == (2, 2)
    assert c_manual.shape == (2, 1)
    assert z_manual.shape == (1, 1)
    assert W_manual == pytest.approx(eval_model.W)
    assert c_manual == pytest.approx(eval_model.c)
    assert z_manual == pytest.approx(eval_model.z)
    fit = Fit(model, z=z_manual, I=iden, M=M_mat, y=y_vec)
    fit_result = fit.execute()

    # See if a == 0.1 was reconstructed properly. Since only a**2 features
    # in the equations, we check for the absolute value. Setting a.min = 0.0
    # is not appreciated by the Minimizer, it seems.
    assert np.abs(fit_result.value(a)) == pytest.approx(0.1)
예제 #5
0
파일: test_model.py 프로젝트: tBuLi/symfit
    def test_MatrixSymbolModel(self):
        """
        Test a model which is defined by ModelSymbols, see #194
        """
        N = Symbol('N', integer=True)
        M = MatrixSymbol('M', N, N)
        W = MatrixSymbol('W', N, N)
        I = MatrixSymbol('I', N, N)
        y = MatrixSymbol('y', N, 1)
        c = MatrixSymbol('c', N, 1)
        a, b = parameters('a, b')
        z, x = variables('z, x')

        model_dict = {
            W: Inverse(I + M / a ** 2),
            c: - W * y,
            z: sqrt(c.T * c)
        }
        # TODO: This should be a Model in the future, but sympy is not yet
        # capable of computing Matrix derivatives at the time of writing.
        model = CallableModel(model_dict)

        self.assertEqual(model.params, [a])
        self.assertEqual(model.independent_vars, [I, M, y])
        self.assertEqual(model.dependent_vars, [z])
        self.assertEqual(model.interdependent_vars, [W, c])
        self.assertEqual(model.connectivity_mapping,
                         {W: {I, M, a}, c: {W, y}, z: {c}})
        # Generate data
        iden = np.eye(2)
        M_mat = np.array([[2, 1], [3, 4]])
        y_vec = np.array([3, 5])

        eval_model = model(I=iden, M=M_mat, y=y_vec, a=0.1)
        W_manual = np.linalg.inv(iden + M_mat / 0.1 ** 2)
        c_manual = - W_manual.dot(y_vec)
        z_manual = np.atleast_1d(np.sqrt(c_manual.T.dot(c_manual)))
        np.testing.assert_allclose(eval_model.W, W_manual)
        np.testing.assert_allclose(eval_model.c, c_manual)
        np.testing.assert_allclose(eval_model.z, z_manual)

        # Now try to retrieve the value of `a` from a fit
        a.value = 0.2
        fit = Fit(model, z=z_manual, I=iden, M=M_mat, y=y_vec)
        fit_result = fit.execute()
        eval_model = model(I=iden, M=M_mat, y=y_vec, **fit_result.params)
        self.assertAlmostEqual(0.1, np.abs(fit_result.value(a)))
        np.testing.assert_allclose(eval_model.W, W_manual, rtol=1e-5)
        np.testing.assert_allclose(eval_model.c, c_manual, rtol=1e-5)
        np.testing.assert_allclose(eval_model.z, z_manual, rtol=1e-5)
예제 #6
0
파일: test_model.py 프로젝트: elgalu/symfit
def test_MatrixSymbolModel():
    """
    Test a model which is defined by ModelSymbols, see #194
    """
    N = Symbol('N', integer=True)
    M = MatrixSymbol('M', N, N)
    W = MatrixSymbol('W', N, N)
    I = MatrixSymbol('I', N, N)
    y = MatrixSymbol('y', N, 1)
    c = MatrixSymbol('c', N, 1)
    a, b = parameters('a, b')
    z, x = variables('z, x')

    model_dict = {
        W: Inverse(I + M / a ** 2),
        c: - W * y,
        z: sqrt(c.T * c)
    }
    # TODO: This should be a Model in the future, but sympy is not yet
    # capable of computing Matrix derivatives at the time of writing.
    model = CallableModel(model_dict)

    assert model.params == [a]
    assert model.independent_vars == [I, M, y]
    assert model.dependent_vars == [z]
    assert model.interdependent_vars == [W, c]
    assert model.connectivity_mapping == {W: {I, M, a}, c: {W, y}, z: {c}}
    # Generate data
    iden = np.eye(2)
    M_mat = np.array([[2, 1], [3, 4]])
    y_vec = np.array([3, 5])

    eval_model = model(I=iden, M=M_mat, y=y_vec, a=0.1)
    W_manual = np.linalg.inv(iden + M_mat / 0.1 ** 2)
    c_manual = - W_manual.dot(y_vec)
    z_manual = np.atleast_1d(np.sqrt(c_manual.T.dot(c_manual)))
    assert eval_model.W == pytest.approx(W_manual)
    assert eval_model.c == pytest.approx(c_manual)
    assert eval_model.z == pytest.approx(z_manual)

    # Now try to retrieve the value of `a` from a fit
    a.value = 0.2
    fit = Fit(model, z=z_manual, I=iden, M=M_mat, y=y_vec)
    fit_result = fit.execute()
    eval_model = model(I=iden, M=M_mat, y=y_vec, **fit_result.params)
    assert 0.1 == pytest.approx(np.abs(fit_result.value(a)))
    assert eval_model.W == pytest.approx(W_manual)
    assert eval_model.c == pytest.approx(c_manual)
    assert eval_model.z == pytest.approx(z_manual)
예제 #7
0
        chi2_params = scipy.stats.chi2.fit(data)

        ###
        # k = Parameter("k", values=1.0, max=100, min=0.01)
        sigma2 = Parameter("sigma2", value=1, min=0.5, max=5.0)
        mu = Parameter("mu", value=max(np.max(data) - 1, 5.0), min=5.0, max=max(np.max(data), 5.0))
        V = Parameter("V", value=0.5, min=0.0001, max=1)
        A = Parameter("A", value=1.0, min=0.0001, max=10)
        B = Parameter("B", value=0.0, min=0.0, max=max(min(data) + 1, 1))

        x = Variable()

        model = Add(Mul(V, Piecewise(
            (Mul(exp(-Mul(Add(x, -B), 1 / A)), 1 / A), GreaterThan(Add(x, -B), 0)), (1e-09, True))),
                    Mul(Add(1, -V), Piecewise(((1 / (sqrt(2 * pi * np.abs(sigma2)))) * exp(
                        -(x - mu) ** 2 / (2 * np.abs(sigma2))), GreaterThan(Add(x, -B), 0)), (1e-09, True))))

        ###



        param_counter = 0
        opt_objective_value = np.inf
        optional_mixture_params = [{"v": 0.5}, {"v": 0.75}, {"v": 1.0}, {"v": 0.25}, {"v": 0.0001}]
        mixture_result = None
        opt_mixture_params = None
        manager = multiprocessing.Manager()
        return_list = manager.list()
        prcs = []
        for i, cur_params in enumerate(optional_mixture_params):
예제 #8
0
               lookup=lookup_table)
 plt.figure()
 plt.title('linewidth for 1mM TEMPOL')
 plot(d)
 d = d['$B_0$':(-9, 9)]
 plot(d, '--', alpha=0.5, linewidth=4)
 d.setaxis(
     '$B_0$', lambda x: x + 1
 )  # for a positive B_center, b/c the interactive guess doesn't deal well with negative parameters
 s_integral = d.C.run_nopop(np.cumsum, '$B_0$')
 #{{{fitting with voigt
 if not os.path.exists('dVoigt.pickle'):
     with open('dVoigt.pickle', 'wb') as fp:
         # cache the expression, which takes some time to generate
         print("no pickle file found -- generating")
         z = ((B - B_center) + s.I * R) / sigma / s.sqrt(2)
         faddeeva = s.simplify(s.exp(-z**2) * s.erfc(-s.I * z))
         voigt = A * s.re(faddeeva) / sigma / s.sqrt(2 * s.pi)
         voigt *= sigma * R  # so adjusting linewidth doesn't change amplitude
         voigt = voigt.simplify()
         # add real below b/c lambdify was giving complex answer
         dVoigt = s.re(s.re(voigt.diff(B)).simplify())
         pickle.dump(dVoigt, fp)
 else:
     with open('dVoigt.pickle', 'rb') as fp:
         print("reading expression from pickle")
         dVoigt = pickle.load(fp)
 plt.figure()
 plt.title('plot guess')
 logger.info(strm(A.value, "A value"))
 # {{{ need to re-do b/c defaults are stored in pickle
예제 #9
0
import numpy as np
from symfit import Variable, Parameter, Fit, Model, sqrt

t_data = np.array([1.4, 2.1, 2.6, 3.0, 3.3])
h_data = np.array([10, 20, 30, 40, 50])

# We now define our model
h = Variable('h')
t = Variable('t')
g = Parameter('g')

t_model = Model({t: sqrt(2 * h / g)})

fit = Fit(t_model, h=h_data, t=t_data)
fit_result = fit.execute()
print(fit_result)

# Make an array from 0 to 50 in 1000 steps
h_range = np.linspace(0, 50, 1000)
fit_data = t_model(h=h_range, g=fit_result.value(g))
t_fit = fit_data.t

#---------------------------------------------------

t_data = np.array([1.4, 2.1, 2.6, 3.0, 3.3])
h_data = np.array([10, 20, 30, 40, 50])
n = np.array([5, 3, 8, 15, 30])
sigma = 0.2
sigma_t = sigma / np.sqrt(n)

# We now define our model
예제 #10
0
    def test_constrained_dependent_on_model(self):
        """
        For a simple Gaussian distribution, we test if Models of various types
        can be used as constraints. Of particular interest are NumericalModels,
        which can be used to fix the integral of the model during the fit to 1,
        as it should be for a probability distribution.
        :return:
        """
        A, mu, sig = parameters('A, mu, sig')
        x, y, Y = variables('x, y, Y')
        i = Idx('i', (0, 1000))
        sig.min = 0.0

        model = Model({y: A * Gaussian(x, mu=mu, sig=sig)})

        # Generate data, 100 samples from a N(1.2, 2) distribution
        np.random.seed(2)
        xdata = np.random.normal(1.2, 2, 1000)
        ydata, xedges = np.histogram(xdata, bins=int(np.sqrt(len(xdata))), density=True)
        xcentres = (xedges[1:] + xedges[:-1]) / 2

        # Unconstrained fit
        fit = Fit(model, x=xcentres, y=ydata)
        unconstr_result = fit.execute()

        # Constraints must be scalar models.
        with self.assertRaises(ModelError):
            Model.as_constraint([A - 1, sig - 1], model, constraint_type=Eq)
        constraint_exact = Model.as_constraint(
            A * sqrt(2 * sympy.pi) * sig - 1, model, constraint_type=Eq
        )
        # Only when explicitly asked, do models behave as constraints.
        self.assertTrue(hasattr(constraint_exact, 'constraint_type'))
        self.assertEqual(constraint_exact.constraint_type, Eq)
        self.assertFalse(hasattr(model, 'constraint_type'))

        # Now lets make some valid constraints and see if they are respected!
        # TODO: These first two should be symbolical integrals over `y` instead,
        # but currently this is not converted into a numpy/scipy function. So instead the first two are not valid constraints.
        constraint_model = Model.as_constraint(A - 1, model, constraint_type=Eq)
        constraint_exact = Eq(A, 1)
        constraint_num = CallableNumericalModel.as_constraint(
            {Y: lambda x, y: simps(y, x) - 1},  # Integrate using simps
            model=model,
            connectivity_mapping={Y: {x, y}},
            constraint_type=Eq
        )

        # Test for all these different types of constraint.
        for constraint in [constraint_model, constraint_exact, constraint_num]:
            if not isinstance(constraint, Eq):
                self.assertEqual(constraint.constraint_type, Eq)

            xcentres = (xedges[1:] + xedges[:-1]) / 2
            fit = Fit(model, x=xcentres, y=ydata, constraints=[constraint])
            # Test if conversion into a constraint was done properly
            fit_constraint = fit.constraints[0]
            self.assertEqual(fit.model.params, fit_constraint.params)
            self.assertEqual(fit_constraint.constraint_type, Eq)

            con_map = fit_constraint.connectivity_mapping
            if isinstance(constraint, CallableNumericalModel):
                self.assertEqual(con_map, {Y: {x, y}, y: {x, mu, sig, A}})
                self.assertEqual(fit_constraint.independent_vars, [x])
                self.assertEqual(fit_constraint.dependent_vars, [Y])
                self.assertEqual(fit_constraint.interdependent_vars, [y])
                self.assertEqual(fit_constraint.params, [A, mu, sig])
            else:
                # ToDo: if these constraints can somehow be written as integrals
                # depending on y and x this if/else should be removed.
                self.assertEqual(con_map,
                                 {fit_constraint.dependent_vars[0]: {A}})
                self.assertEqual(fit_constraint.independent_vars, [])
                self.assertEqual(len(fit_constraint.dependent_vars), 1)
                self.assertEqual(fit_constraint.interdependent_vars, [])
                self.assertEqual(fit_constraint.params, [A, mu, sig])

            # Finally, test if the constraint worked
            fit_result = fit.execute(options={'eps': 1e-15, 'ftol': 1e-10})
            unconstr_value = fit.minimizer.wrapped_constraints[0]['fun'](**unconstr_result.params)
            constr_value = fit.minimizer.wrapped_constraints[0]['fun'](**fit_result.params)
            self.assertAlmostEqual(constr_value[0], 0.0, 10)
        # And if it was very poorly met before
        self.assertNotAlmostEqual(unconstr_value[0], 0.0, 2)
예제 #11
0
def test_constrained_dependent_on_model():
    """
    For a simple Gaussian distribution, we test if Models of various types
    can be used as constraints. Of particular interest are NumericalModels,
    which can be used to fix the integral of the model during the fit to 1,
    as it should be for a probability distribution.
    :return:
    """
    A, mu, sig = parameters('A, mu, sig')
    x, y, Y = variables('x, y, Y')
    i = Idx('i', (0, 1000))
    sig.min = 0.0

    model = GradientModel({y: A * Gaussian(x, mu=mu, sig=sig)})

    # Generate data, 100 samples from a N(1.2, 2) distribution
    np.random.seed(2)
    xdata = np.random.normal(1.2, 2, 1000)
    ydata, xedges = np.histogram(xdata,
                                 bins=int(np.sqrt(len(xdata))),
                                 density=True)
    xcentres = (xedges[1:] + xedges[:-1]) / 2

    # Unconstrained fit
    fit = Fit(model, x=xcentres, y=ydata)
    unconstr_result = fit.execute()

    # Constraints must be scalar models.
    with pytest.raises(ModelError):
        Model.as_constraint([A - 1, sig - 1], model, constraint_type=Eq)

    constraint_exact = Model.as_constraint(A * sqrt(2 * sympy.pi) * sig - 1,
                                           model,
                                           constraint_type=Eq)
    # Only when explicitly asked, do models behave as constraints.
    assert hasattr(constraint_exact, 'constraint_type')
    assert constraint_exact.constraint_type == Eq
    assert not hasattr(model, 'constraint_type')

    # Now lets make some valid constraints and see if they are respected!
    # FIXME These first two should be symbolical integrals over `y` instead,
    # but currently this is not converted into a numpy/scipy function. So
    # instead the first two are not valid constraints.
    constraint_model = Model.as_constraint(A - 1, model, constraint_type=Eq)
    constraint_exact = Eq(A, 1)
    constraint_num = CallableNumericalModel.as_constraint(
        {
            Y: lambda x, y: simps(y, x) - 1
        },  # Integrate using simps
        model=model,
        connectivity_mapping={Y: {x, y}},
        constraint_type=Eq)

    # Test for all these different types of constraint.
    for constraint in [constraint_model, constraint_exact, constraint_num]:
        if not isinstance(constraint, Eq):
            assert constraint.constraint_type == Eq

        xcentres = (xedges[1:] + xedges[:-1]) / 2
        fit = Fit(model, x=xcentres, y=ydata, constraints=[constraint])
        # Test if conversion into a constraint was done properly
        fit_constraint = fit.constraints[0]
        assert fit.model.params == fit_constraint.params
        assert fit_constraint.constraint_type == Eq

        con_map = fit_constraint.connectivity_mapping
        if isinstance(constraint, CallableNumericalModel):
            assert con_map == {Y: {x, y}, y: {x, mu, sig, A}}
            assert fit_constraint.independent_vars == [x]
            assert fit_constraint.dependent_vars == [Y]
            assert fit_constraint.interdependent_vars == [y]
            assert fit_constraint.params == [A, mu, sig]
        else:
            # TODO if these constraints can somehow be written as integrals
            # depending on y and x this if/else should be removed.
            assert con_map == {fit_constraint.dependent_vars[0]: {A}}
            assert fit_constraint.independent_vars == []
            assert len(fit_constraint.dependent_vars) == 1
            assert fit_constraint.interdependent_vars == []
            assert fit_constraint.params == [A, mu, sig]

        # Finally, test if the constraint worked
        fit_result = fit.execute(options={'eps': 1e-15, 'ftol': 1e-10})
        unconstr_value = fit.minimizer.wrapped_constraints[0]['fun'](
            **unconstr_result.params)
        constr_value = fit.minimizer.wrapped_constraints[0]['fun'](
            **fit_result.params)

        # TODO because of a bug by pytest we have to solve it like this
        assert constr_value[0] == pytest.approx(0, abs=1e-10)
    # And if it was very poorly met before
    assert not unconstr_value[0] == pytest.approx(0.0, 1e-1)
예제 #12
0
    # model = Add(Mul(V, Piecewise((Mul((1 / (2 ** (k / float(2)) * gamma(k / 2)) * Pow(Mul(Add(x, -B), 1 / A),
    #                                                                                   (k / 2 - 1)) * exp(
    #     -Mul(Add(x, -B), 1 / A) / 2)), 1 / A), GreaterThan(Add(x, -B), 0)), (1e-09, True))),
    #             Mul(Add(1, -V), Piecewise(((1 / (sqrt(2 * pi * np.abs(sigma2)))) * exp(
    #                 -(x - mu) ** 2 / (2 * np.abs(sigma2))), GreaterThan(Add(x, -B), 0)), (1e-09, True))))
    # model = Add(Mul(V, Piecewise((Mul(Mul(1 / k , exp(-Mul(Mul(Add(x,-B),1/A) ,1/ k))),1/A), GreaterThan(Add(x,-B),0)),(1e-09  , True))),
    #         Mul(Add(1,-V), Piecewise(((1 / (sqrt(2 * pi * np.abs(sigma2)))) * exp(-(x - mu) ** 2 / (2 * np.abs(sigma2))),GreaterThan(Add(x,-B),0)), (1e-09  , True))))
    model = Add(
        Mul(
            V,
            Piecewise((Mul(exp(-Mul(Add(x, -B), 1 / A)),
                           1 / A), GreaterThan(Add(x, -B), 0)),
                      (1e-09, True))),
        Mul(
            Add(1, -V),
            Piecewise(((1 / (sqrt(2 * pi * np.abs(sigma2)))) *
                       exp(-(x - mu)**2 /
                           (2 * np.abs(sigma2))), GreaterThan(Add(x, -B), 0)),
                      (1e-09, True))))

    # Do the fitting!   ##
    fit = Fit(
        model,
        data,
        objective=LogLikelihood,
        constraints=[
            GreaterThan(A, 0.2),
            GreaterThan(10, A),
            GreaterThan(B, 0),
            GreaterThan(max(min(data) + 1, 1), B),
            GreaterThan(mu, 5),