def boxcox(cls, no_of_etas):
        assignments = ModelStatements()
        for i in range(1, no_of_etas + 1):
            symbol = S(f'etab{i}')
            expression = (exp(S(f'eta{i}')) ** S(f'theta{i}') - 1) / (S(f'theta{i}'))

            assignment = Assignment(symbol, expression)
            assignments.append(assignment)

        return cls('boxcox', assignments, 'lambda')
Example #2
0
def test_reassign():
    s1 = Assignment(S('G'), sympy.Integer(3))
    s2 = Assignment(S('M'), sympy.Integer(2))
    s3 = Assignment(S('Z'), sympy.Integer(23) + S('M'))
    s4 = Assignment(S('KA'), S('X') + S('Y'))
    s = ModelStatements([s1, s2, s3, s4])
    s.reassign(S('M'), S('x') + S('y'))
    assert s == ModelStatements([s1, Assignment('M', S('x') + S('y')), s3, s4])

    s5 = Assignment('KA', S('KA') + S('Q') + 1)
    s = ModelStatements([s1, s2, s3, s4, s5])
    s.reassign(S('KA'), S('F'))
    assert s == ModelStatements([s1, s2, s3, Assignment('KA', S('F'))])
    def john_draper(cls, no_of_etas):
        assignments = ModelStatements()
        for i in range(1, no_of_etas + 1):
            symbol = S(f'etad{i}')

            eta = S(f'eta{i}')
            theta = S(f'theta{i}')

            expression = sign(eta) * (((abs(eta) + 1) ** theta - 1) / theta)

            assignment = Assignment(symbol, expression)
            assignments.append(assignment)

        return cls('johndraper', assignments, 'lambda')
Example #4
0
def test_add_parameters_and_statements(pheno_path, param_new, statement_new, buf_new):
    model = Model(pheno_path)

    pset = model.parameters
    pset.append(param_new)
    model.parameters = pset

    sset = model.statements

    # Insert new statement before ODE system.
    new_sset = ModelStatements()
    for s in sset:
        if isinstance(s, ODESystem):
            new_sset.append(statement_new)
        new_sset.append(s)

    model.statements = new_sset
    model.update_source()

    rec = (
        f'$PK\n'
        f'IF(AMT.GT.0) BTIME=TIME\n'
        f'TAD=TIME-BTIME\n'
        f'TVCL=THETA(1)*WGT\n'
        f'TVV=THETA(2)*WGT\n'
        f'IF(APGR.LT.5) TVV=TVV*(1+THETA(3))\n'
        f'CL=TVCL*EXP(ETA(1))\n'
        f'V=TVV*EXP(ETA(2))\n'
        f'S1=V\n'
        f'{buf_new}\n\n'
    )

    assert str(model.get_pred_pk_record()) == rec
    def tdist(cls, no_of_etas):
        assignments = ModelStatements()
        for i in range(1, no_of_etas + 1):
            symbol = S(f'etat{i}')

            eta = S(f'eta{i}')
            theta = S(f'theta{i}')

            num_1 = eta ** 2 + 1
            denom_1 = 4 * theta

            num_2 = (5 * eta ** 4) + (16 * eta ** 2 + 3)
            denom_2 = 96 * theta ** 2

            num_3 = (3 * eta ** 6) + (19 * eta ** 4) + (17 * eta ** 2) - 15
            denom_3 = 384 * theta ** 3

            expression = eta * (1 + (num_1 / denom_1) + (num_2 / denom_2) + (num_3 / denom_3))

            assignment = Assignment(symbol, expression)
            assignments.append(assignment)

        return cls('tdist', assignments, 'df')
Example #6
0
def test_add_statements(pheno_path, statement_new, buf_new):
    model = Model(pheno_path)
    sset = model.statements
    assert len(sset) == 15

    # Insert new statement before ODE system.
    new_sset = ModelStatements()
    for s in sset:
        if isinstance(s, ODESystem):
            new_sset.append(statement_new)
        new_sset.append(s)

    model.statements = new_sset
    model.update_source()

    assert len(model.statements) == 16

    parser = NMTranParser()
    stream = parser.parse(str(model))

    assert str(model.control_stream) == str(stream)

    rec_ref = (
        f'$PK\n'
        f'IF(AMT.GT.0) BTIME=TIME\n'
        f'TAD=TIME-BTIME\n'
        f'TVCL=THETA(1)*WGT\n'
        f'TVV=THETA(2)*WGT\n'
        f'IF(APGR.LT.5) TVV=TVV*(1+THETA(3))\n'
        f'CL=TVCL*EXP(ETA(1))\n'
        f'V=TVV*EXP(ETA(2))\n'
        f'S1=V\n'
        f'{buf_new}\n\n'
    )

    rec_mod = str(model.control_stream.get_records('PK')[0])

    assert rec_ref == rec_mod
Example #7
0
    def _assign_statements(self):
        s = []
        self.nodes = []
        for statement in self.root.all('statement'):
            for node in statement.children:
                if node.rule == 'assignment':
                    name = str(node.variable).upper()
                    expr = ExpressionInterpreter().visit(node.expression)
                    ass = Assignment(name, expr)
                    s.append(ass)
                    self.nodes.append(statement)
                elif node.rule == 'logical_if':
                    logic_expr = ExpressionInterpreter().visit(
                        node.logical_expression)
                    try:
                        assignment = node.assignment
                    except NoSuchRuleException:
                        pass
                    else:
                        name = str(assignment.variable).upper()
                        expr = ExpressionInterpreter().visit(
                            assignment.expression)
                        # Check if symbol was previously declared
                        else_val = sympy.Integer(0)
                        for prevass in s:
                            if prevass.symbol.name == name:
                                else_val = sympy.Symbol(name)
                                break
                        pw = sympy.Piecewise((expr, logic_expr),
                                             (else_val, True))
                        ass = Assignment(name, pw)
                        s.append(ass)
                    self.nodes.append(statement)
                elif node.rule == 'block_if':
                    interpreter = ExpressionInterpreter()
                    blocks = []  # [(logic, [(symb1, expr1), ...]), ...]
                    symbols = OrderedSet()

                    first_logic = interpreter.visit(
                        node.block_if_start.logical_expression)
                    first_block = node.block_if_start
                    first_symb_exprs = []
                    for ifstat in first_block.all('statement'):
                        for assign_node in ifstat.all('assignment'):
                            name = str(assign_node.variable).upper()
                            first_symb_exprs.append(
                                (name,
                                 interpreter.visit(assign_node.expression)))
                            symbols.add(name)
                    blocks.append((first_logic, first_symb_exprs))

                    else_if_blocks = node.all('block_if_elseif')
                    for elseif in else_if_blocks:
                        logic = interpreter.visit(elseif.logical_expression)
                        elseif_symb_exprs = []
                        for elseifstat in elseif.all('statement'):
                            for assign_node in elseifstat.all('assignment'):
                                name = str(assign_node.variable).upper()
                                elseif_symb_exprs.append(
                                    (name,
                                     interpreter.visit(
                                         assign_node.expression)))
                                symbols.add(name)
                        blocks.append((logic, elseif_symb_exprs))

                    else_block = node.find('block_if_else')
                    if else_block:
                        else_symb_exprs = []
                        for elsestat in else_block.all('statement'):
                            for assign_node in elsestat.all('assignment'):
                                name = str(assign_node.variable).upper()
                                else_symb_exprs.append(
                                    (name,
                                     interpreter.visit(
                                         assign_node.expression)))
                                symbols.add(name)
                        piecewise_logic = True
                        if len(blocks[0][1]) == 0 and not else_if_blocks:
                            # Special case for empty if
                            piecewise_logic = sympy.Not(blocks[0][0])
                        blocks.append((piecewise_logic, else_symb_exprs))

                    for symbol in symbols:
                        pairs = []
                        for block in blocks:
                            logic = block[0]
                            for cursymb, expr in block[1]:
                                if cursymb == symbol:
                                    pairs.append((expr, logic))
                        pw = sympy.Piecewise(*pairs)
                        ass = Assignment(symbol, pw)
                        s.append(ass)
                    self.nodes.append(statement)

        statements = ModelStatements(s)
        return statements
Example #8
0
def test_remove_symbol_definition():
    s1 = Assignment(S('KA'), S('X') + S('Y'))
    s2 = Assignment(S('Z'), sympy.Integer(23) + S('M'))
    s3 = Assignment(S('M'), sympy.Integer(2))
    s4 = Assignment(S('G'), sympy.Integer(3))
    s = ModelStatements([s4, s3, s2, s1])
    s.remove_symbol_definitions([S('Z')], s1)
    assert s == ModelStatements([s4, s1])

    s1 = Assignment(S('K'), sympy.Integer(16))
    s2 = Assignment(S('CL'), sympy.Integer(23))
    s3 = Assignment(S('CL'), S('CL') + S('K'))
    s4 = Assignment(S('G'), S('X') + S('K'))
    s = ModelStatements([s1, s2, s3, s4])
    s.remove_symbol_definitions([S('CL')], s4)
    assert s == ModelStatements([s1, s4])

    s1 = Assignment(S('K'), sympy.Integer(16))
    s2 = Assignment(S('CL'), sympy.Integer(23))
    s3 = Assignment(S('CL'), S('CL') + S('K'))
    s4 = Assignment(S('G'), S('X') + S('K'))
    s5 = Assignment(S('KR'), S('CL'))
    s = ModelStatements([s1, s2, s3, s4, s5])
    s.remove_symbol_definitions([S('CL')], s4)
    assert s == ModelStatements([s1, s2, s3, s4, s5])

    s1 = Assignment(S('K'), sympy.Integer(16))
    s2 = Assignment(S('CL'), sympy.Integer(23))
    s3 = Assignment(S('CL'), S('CL') + S('K'))
    s4 = Assignment(S('G'), S('X'))
    s = ModelStatements([s1, s2, s3, s4])
    s.remove_symbol_definitions([S('CL'), S('K')], s4)
    assert s == ModelStatements([s4])
Example #9
0
def add_iov(model, occ, list_of_parameters=None, eta_names=None):
    """
    Adds IOVs to :class:`pharmpy.model`. Initial estimate of new IOVs are 10% of the IIV eta
    it is based on.

    Parameters
    ----------
    model : Model
        Pharmpy model to add new IOVs to.
    occ : str
        Name of occasion column.
    list_of_parameters : str, list
        List of names of parameters and random variables. Accepts random variable names, parameter
        names, or a mix of both.
    eta_names: str, list
        Custom names of new etas. Must be equal to the number of input etas times the number of
        categories for occasion.
    """
    rvs, pset, sset = model.random_variables, model.parameters, model.statements

    list_of_parameters = _format_input_list(list_of_parameters)
    etas = _get_etas(model, list_of_parameters, include_symbols=True)
    categories = _get_occ_levels(model.dataset, occ)

    if eta_names and len(eta_names) != len(etas) * len(categories):
        raise ValueError(
            f'Number of provided names incorrect, need {len(etas) * len(categories)} names.'
        )
    elif len(categories) == 1:
        raise ValueError(f'Only one value in {occ} column.')

    iovs, etais = ModelStatements(), ModelStatements()
    for i, eta in enumerate(etas, 1):
        omega_name = str(
            next(iter(eta.sympy_rv.pspace.distribution.free_symbols)))
        omega = S(f'OMEGA_IOV_{i}')  # TODO: better name
        pset.append(Parameter(str(omega), init=pset[omega_name].init * 0.1))

        iov = S(f'IOV_{i}')

        values, conditions = [], []

        for j, cat in enumerate(categories, 1):
            if eta_names:
                eta_name = eta_names[j - 1]
            else:
                eta_name = f'ETA_IOV_{i}{j}'

            eta_new = RandomVariable.normal(eta_name, 'iov', 0, omega)
            rvs.append(eta_new)

            values += [S(eta_new.name)]
            conditions += [Eq(cat, S(occ))]

        expression = Piecewise(*zip(values, conditions))

        iovs.append(Assignment(iov, sympy.sympify(0)))
        iovs.append(Assignment(iov, expression))
        etais.append(Assignment(S(f'ETAI{i}'), eta.symbol + iov))

        sset.subs({eta.name: S(f'ETAI{i}')})

    iovs.extend(etais)
    iovs.extend(sset)

    model.random_variables, model.parameters, model.statements = rvs, pset, iovs

    return model
Example #10
0
def update_statements(model, old, new, trans):
    trans['NaN'] = int(data.conf.na_rep)
    main_statements = ModelStatements()
    error_statements = ModelStatements()

    new_odes = new.ode_system
    if new_odes is not None:
        old_odes = old.ode_system
        if new_odes != old_odes:
            update_ode_system(model, old_odes, new_odes)

    after_odes = False
    for s in new:
        if isinstance(s, ODESystem):
            after_odes = True
        elif after_odes:
            error_statements.append(s)
        else:
            main_statements.append(s)

    main_statements.subs(trans)
    rec = model.get_pred_pk_record()
    rec.statements = main_statements
    error = model._get_error_record()
    if error:
        if len(error_statements) > 0:
            error_statements.pop(0)  # Remove the link statement
        error_statements.subs(trans)
        error.statements = error_statements
        error.is_updated = True

    rec.is_updated = True
Example #11
0
def test_repr_html():
    s1 = Assignment(S('KA'), S('X') + S('Y'))
    stats = ModelStatements([s1])
    html = stats._repr_html_()
    assert 'X + Y' in html
Example #12
0
def add_covariate_effect(model, parameter, covariate, effect, operation='*'):
    """
    Adds covariate effect to :class:`pharmpy.model`. The following effects have templates:

    - Linear function for continuous covariates (*lin*)
        - Function:

        .. math::

            \\text{coveff} = 1 + \\text{theta} * (\\text{cov} - \\text{median})

        - Init:  0.001
        - Upper:
            - If median of covariate equals minimum: :math:`100,000`
            - Otherwise: :math:`\\frac{1}{\\text{median} - \\text{min}}`
        - Lower:
            - If median of covariate equals maximum: :math:`-100,000`
            - Otherwise: :math:`\\frac{1}{\\text{median} - \\text{max}}`
    - Linear function for categorical covariates (*cat*)
        - Function:

            - If covariate is most common category:

            .. math::

                \\text{coveff} = 1

            - For each additional category:

            .. math::

                \\text{coveff} = 1 + \\text{theta}

        - Init: :math:`0.001`
        - Upper: :math:`100,000`
        - Lower: :math:`-100,000`
    - Piecewise linear function/"hockey-stick", continuous covariates only (*piece_lin*)
        - Function:
            - If cov <= median:

            .. math::

                \\text{coveff} = 1 + \\text{theta1} * (\\text{cov} - \\text{median})

            - If cov > median:

            .. math::

                \\text{coveff} = 1 + \\text{theta2} * (\\text{cov} - \\text{median})


        - Init: :math:`0.001`
        - Upper:
            - For first state: :math:`\\frac{1}{\\text{median} - \\text{min}}`
            - Otherwise: :math:`100,000`
        - Lower:
            - For first state: :math:`-100,000`
            - Otherwise: :math:`\\frac{1}{\\text{median} - \\text{max}}`
    - Exponential function, continuous covariates only (*exp*)
        - Function:

        .. math::

            \\text{coveff} = \\exp(\\text{theta} * (\\text{cov} - \\text{median}))

        - Init:
            - If lower > 0.001 or upper < 0.001: :math:`\\frac{\\text{upper} - \\text{lower}}{2}`
            - If estimated init is 0: :math:`\\frac{\\text{upper}}{2}`
            - Otherwise: :math:`0.001`
        - Upper:
            - If min - median = 0 or max - median = 0: :math:`100`
            - Otherwise:

            .. math::

                \\min(\\frac{\\log(0.01)}{\\text{min} - \\text{median}},
                \\frac{\\log(100)}{\\text{max} - \\text{median}})
        - Lower:
            - If min - median = 0 or max - median = 0: :math:`0.01`
            - Otherwise:

            .. math::

                \\max(\\frac{\\log(0.01)}{\\text{max} - \\text{median}},
                \\frac{\\log(100)}{\\text{min} - \\text{median}})

    - Power function, continuous covariates only (*pow*)
        - Function:

        .. math::

            \\text{coveff} = (\\frac{\\text{cov}}{\\text{median}})^\\text{theta}

        - Init: :math:`0.001`
        - Upper: :math:`100,000`
        - Lower: :math:`-100`


    Parameters
    ----------
    model : Model
        Pharmpy model to add covariate effect to.
    parameter : str
        Name of parameter to add covariate effect to.
    covariate : str
        Name of covariate.
    effect : str
        Type of covariate effect. May be abbreviated covariate effect (see above) or custom.
    operation : str, optional
        Whether the covariate effect should be added or multiplied (default).
    """
    sset = model.statements

    if S(f'{parameter}{covariate}') in sset.free_symbols:
        warnings.warn('Covariate effect already exists')
        return model

    statistics = dict()
    statistics['mean'] = _calculate_mean(model.dataset, covariate)
    statistics['median'] = _calculate_median(model.dataset, covariate)
    statistics['std'] = _calculate_std(model.dataset, covariate)

    covariate_effect = _create_template(effect, model, covariate)
    thetas = _create_thetas(model, parameter, effect, covariate,
                            covariate_effect.template)

    param_statement = sset.find_assignment(parameter)

    index = sset.index(param_statement)

    covariate_effect.apply(parameter, covariate, thetas, statistics)
    effect_statement = covariate_effect.create_effect_statement(
        operation, param_statement)

    statements = ModelStatements()

    statements += [
        s for s in covariate_effect.statistic_statements if s not in sset
    ]
    statements.append(covariate_effect.template)
    statements.append(effect_statement)

    previous_effect = sset.find_assignment(parameter)
    cov_possible = [
        f'{parameter}{col_name}' for col_name in model.dataset.columns
    ]

    if previous_effect.expression.args and all(
            arg.name in cov_possible for arg in previous_effect.expression.args
            if str(arg) != parameter):
        effect_statement.expression = effect_statement.expression.subs(
            {parameter: previous_effect.expression})
        sset.remove(previous_effect)

    for i, statement in enumerate(statements, 1):
        sset.insert(index + i, statement)

    model.statements = sset
    return model