def transformation(self, prob: Problem) -> Problem:

        states = sympy.Matrix(extract_syms(prob.states))
        dynamic_parameters = sympy.Matrix(extract_syms(prob.parameters))
        parameters = sympy.Matrix(
            extract_syms(prob.parameters) +
            extract_syms(prob.constraint_parameters))
        quads = sympy.Matrix(extract_syms(prob.quads))
        eom = sympy.Matrix(getattr_from_list(prob.states, 'eom'))
        phi_0 = sympy.Matrix(
            getattr_from_list(prob.constraints['initial'], 'expr'))
        phi_f = sympy.Matrix(
            getattr_from_list(prob.constraints['terminal'], 'expr'))

        prob.func_jac['df_dy'] = eom.jacobian(states)
        prob.bc_jac['initial']['dbc_dy'] = phi_0.jacobian(states)
        prob.bc_jac['terminal']['dbc_dy'] = phi_f.jacobian(states)

        if len(parameters) > 0:
            prob.func_jac.update({'df_dp': eom.jacobian(dynamic_parameters)})
            prob.bc_jac['initial']['dbc_dp'] = phi_0.jacobian(parameters)
            prob.bc_jac['terminal']['dbc_dp'] = phi_f.jacobian(parameters)

        if len(quads) > 0:
            prob.bc_jac['initial']['dbc_dq'] = phi_0.jacobian(quads)
            prob.bc_jac['terminal']['dbc_dq'] = phi_f.jacobian(quads)

        return prob
 def init(self, gamma, bvp):
     self.bvp = bvp
     # for var_name in self.var_iterator():
     #     if var_name not in [str(s['symbol']) for s in self.prob.get_constants()]:
     #         raise ValueError('Variable ' + var_name + ' not found in boundary value problem')
     gamma_in = copy.deepcopy(gamma)
     gamma_in.converged = False
     self.gammas = [gamma_in]
     self.constant_names = getattr_from_list(bvp.constants, 'name')
    def compile_deriv_func(self, use_control_arg=False):
        sym_eom = getattr_from_list(self.prob.states, 'eom')
        sym_eom_q = getattr_from_list(self.prob.quads, 'eom')

        if self.compute_u is None:
            if use_control_arg:
                _args = self._dynamic_args_w_controls
            else:
                _args = self._dynamic_args

            self.compute_y_dot = self.lambdify(_args, sym_eom)

            if len(sym_eom_q) > 0:
                self.compute_q_dot = self.lambdify(_args, sym_eom_q)

            self.deriv_func, self.quad_func = self.compute_y_dot, self.compute_q_dot

        else:
            self.compute_y_dot = self.lambdify(self._dynamic_args_w_controls,
                                               sym_eom)

            compute_u = self.compute_u
            compute_y_dot = self.compute_y_dot

            def deriv_func(_y, _p, _k):
                _u = compute_u(_y, _p, _k)
                return np.array(compute_y_dot(_y, _u, _p, _k))

            self.deriv_func = jit_compile_func(deriv_func, self._dynamic_args)

            if len(sym_eom_q) > 0:
                self.compute_q_dot = self.lambdify(
                    self._dynamic_args_w_controls, sym_eom_q)
                compute_q_dot = self.compute_q_dot

                def quad_func(_y, _p, _k):
                    _u = compute_u(_y, _p, _k)
                    return np.array(compute_q_dot(_y, _u, _p, _k))

                self.quad_func = jit_compile_func(quad_func,
                                                  self._dynamic_args)

        return self.deriv_func, self.quad_func
    def init(self, sol, bvp):
        super(SparseProductStrategy, self).init(sol, bvp)

        lower_bounds = []
        upper_bounds = []

        num_vars = len(self.vars)
        for var_name in self.vars.keys():
            jj = getattr_from_list(bvp.constants, 'name').index(var_name)
            self.vars[var_name].value = sol.const[jj]
            lower_bounds.append(sol.const[jj])
            upper_bounds.append(self.vars[var_name].target)

        major_num_steps = self._num_subdivisions[0]
        minor_num_steps = self._num_subdivisions[1]

        step_list = [lower_bounds]
        major_point_cloud = [lower_bounds]
        minor_point_cloud = []

        for n in range(num_vars):
            new_maj_pnts = []
            maj_step_series = np.linspace(lower_bounds[n], upper_bounds[n],
                                          major_num_steps[n])
            for maj_point in major_point_cloud:
                maj_pnt_line = []
                for maj_step in maj_step_series:
                    new_pnt = list(maj_point)
                    new_pnt[n] = maj_step
                    maj_pnt_line.append(tuple(new_pnt))

                for maj_pnt_0, maj_pnt_1 in zip(maj_pnt_line[:-1],
                                                maj_pnt_line[1:]):
                    min_step_series = np.linspace(maj_pnt_0[n],
                                                  maj_pnt_1[n],
                                                  minor_num_steps[n] + 1,
                                                  endpoint=False)[1:]
                    for min_step in min_step_series:
                        new_point = list(maj_pnt_0)
                        new_point[n] = min_step
                        step_list.append(tuple(new_point))
                        minor_point_cloud.append(tuple(new_point))

                    step_list.append(maj_pnt_1)

                new_maj_pnts += maj_pnt_line[1:]
            major_point_cloud += new_maj_pnts

        self.num_cases(len(step_list))

        for step in step_list:
            for n, var_name in enumerate(self.vars.keys()):
                self.vars[var_name].steps.append(step[n])
示例#5
0
def match_constants_to_states(prob: Problem, sol: Trajectory):
    state_names = getattr_from_list(prob.states + [prob.independent_variable], 'name')

    initial_states = np.hstack((sol.y[0, :], sol.t[0]))
    terminal_states = np.hstack((sol.y[-1, :], sol.t[-1]))

    initial_bc = dict(zip(state_names, initial_states))
    terminal_bc = dict(zip(state_names, terminal_states))

    constant_names = getattr_from_list(prob.constants, 'name')
    for ii, bc0 in enumerate(initial_bc):
        if bc0 + '_0' in constant_names:
            jj = getattr_from_list(prob.constants, 'name').index(bc0 + '_0')
            sol.const[jj] = initial_bc[bc0]

    for ii, bcf in enumerate(terminal_bc):
        if bcf + '_f' in constant_names:
            jj = getattr_from_list(prob.constants, 'name').index(bcf + '_f')
            sol.const[jj] = terminal_bc[bcf]

    return sol
    def init(self, sol, bvp):
        super(ProductStrategy, self).init(sol, bvp)

        num_vars = len(self.vars)
        self.num_cases(self.num_subdivisions()**num_vars)
        for var_name in self.vars.keys():
            jj = getattr_from_list(bvp.constants, 'name').index(var_name)
            self.vars[var_name].value = sol.const[jj]

        ls_set = [
            np.linspace(self.vars[var_name].value, self.vars[var_name].target,
                        self._num_subdivisions)
            for var_name in self.vars.keys()
        ]
        for val in itertools.product(*ls_set):
            ii = 0
            for var_name in self.vars.keys():
                self.vars[var_name].steps.append(val[ii])
                ii += 1
示例#7
0
def solve(autoscale=True,
          bvp=None,
          bvp_algorithm=None,
          guess_generator=None,
          initial_helper=False,
          method='traditional',
          n_cpus=1,
          ocp=None,
          ocp_map=None,
          ocp_map_inverse=None,
          optim_options=None,
          steps=None,
          save_sols=True):
    """
    Solves the OCP using specified method

    +------------------------+-----------------+---------------------------------------+
    | Valid kwargs           | Default Value   | Valid Values                          |
    +========================+=================+=======================================+
    | autoscale              | True            | bool                                  |
    +------------------------+-----------------+---------------------------------------+
    | prob                   | None            | codegen'd BVPs                        |
    +------------------------+-----------------+---------------------------------------+
    | bvp_algorithm          | None            | prob algorithm                        |
    +------------------------+-----------------+---------------------------------------+
    | guess_generator        | None            | guess generator                       |
    +------------------------+-----------------+---------------------------------------+
    | initial_helper         | False           | bool                                  |
    +------------------------+-----------------+---------------------------------------+
    | method                 | 'traditional'   | string                                |
    +------------------------+-----------------+---------------------------------------+
    | n_cpus                 | 1               | integer                               |
    +------------------------+-----------------+---------------------------------------+
    | ocp                    | None            | :math:`\\Sigma`                       |
    +------------------------+-----------------+---------------------------------------+
    | ocp_map                | None            | :math:`\\gamma \rightarrow \\gamma`   |
    +------------------------+-----------------+---------------------------------------+
    | ocp_map_inverse        | None            | :math:`\\gamma \rightarrow \\gamma`   |
    +------------------------+-----------------+---------------------------------------+
    | optim_options          | None            | dict()                                |
    +------------------------+-----------------+---------------------------------------+
    | steps                  | None            | continuation_strategy                 |
    +------------------------+-----------------+---------------------------------------+
    | save                   | False           | bool, str                             |
    +------------------------+-----------------+---------------------------------------+

    """

    if optim_options is None:
        optim_options = {}

    # Display useful info about the environment to debug logger.
    logger.debug('\n' + __splash__ + '\n')
    from beluga import __version__ as beluga_version
    from llvmlite import __version__ as llvmlite_version
    from numba import __version__ as numba_version
    from numpy import __version__ as numpy_version
    from scipy import __version__ as scipy_version
    from sympy.release import __version__ as sympy_version

    logger.debug('beluga:\t\t' + str(beluga_version))
    logger.debug('llvmlite:\t' + str(llvmlite_version))
    logger.debug('numba:\t\t' + str(numba_version))
    logger.debug('numpy:\t\t' + str(numpy_version))
    logger.debug('python:\t\t' + str(sys.version_info[0]) + '.' +
                 str(sys.version_info[1]) + '.' + str(sys.version_info[2]))
    logger.debug('scipy:\t\t' + str(scipy_version))
    logger.debug('sympy:\t\t' + str(sympy_version) + '\n\n')
    """
    Error checking
    """
    if n_cpus < 1:
        raise ValueError('Number of cpus must be greater than 1.')
    if n_cpus > 1:
        pool = pathos.multiprocessing.Pool(processes=n_cpus)
    else:
        pool = None

    if ocp is None:
        raise NotImplementedError('\"ocp\" must be defined.')
    """
    Main code
    """

    # f_ocp = compile_direct(ocp)

    logger.debug('Using ' + str(n_cpus) + '/' +
                 str(pathos.multiprocessing.cpu_count()) + ' CPUs. ')

    if bvp is None:
        preprocessor = make_preprocessor()
        processed_ocp = preprocessor(copy.deepcopy(ocp))

        if method.lower() in ['indirect', 'traditional', 'brysonho']:
            method = 'traditional'

        if method.lower() in ['traditional', 'diffyg']:
            RFfunctor = make_indirect_method(copy.deepcopy(processed_ocp),
                                             method=method,
                                             **optim_options)
            prob = RFfunctor(copy.deepcopy(processed_ocp))
        elif method == 'direct':
            functor = make_direct_method(copy.deepcopy(processed_ocp),
                                         **optim_options)
            prob = functor(copy.deepcopy(processed_ocp))
        else:
            raise NotImplementedError

        postprocessor = make_postprocessor()
        bvp = postprocessor(copy.deepcopy(prob))

        logger.debug('Resulting BVP problem:')
        logger.debug(bvp.__repr__())

        ocp_map = bvp.map_sol
        ocp_map_inverse = bvp.inv_map_sol

    else:
        if ocp_map is None or ocp_map_inverse is None:
            raise ValueError(
                'BVP problem must have an associated \'ocp_map\' and \'ocp_map_inverse\''
            )

    solinit = Trajectory()
    solinit.const = np.array(getattr_from_list(bvp.constants, 'default_val'))
    solinit = guess_generator.generate(bvp.functional_problem, solinit,
                                       ocp_map, ocp_map_inverse)

    if initial_helper:
        sol_ocp = copy.deepcopy(solinit)
        sol_ocp = match_constants_to_states(ocp, ocp_map_inverse(sol_ocp))
        solinit.const = sol_ocp.const

    if bvp.functional_problem.compute_u is not None:
        u = np.array([
            bvp.functional_problem.compute_u(solinit.y[0],
                                             solinit.dynamical_parameters,
                                             solinit.const)
        ])
        for ii in range(len(solinit.t) - 1):
            u = np.vstack(
                (u,
                 bvp.functional_problem.compute_u(solinit.y[ii + 1],
                                                  solinit.dynamical_parameters,
                                                  solinit.const)))
        solinit.u = u
    """
    Main continuation process
    """
    time0 = time.time()
    continuation_set = run_continuation_set(bvp_algorithm, steps, solinit, bvp,
                                            pool, autoscale)
    total_time = time.time() - time0
    logger.info('Continuation process completed in %0.4f seconds.\n' %
                total_time)
    bvp_algorithm.close()
    """
    Post processing and output
    """
    out = postprocess_continuations(continuation_set, ocp_map_inverse)

    if pool is not None:
        pool.close()

    if save_sols or (isinstance(save_sols, str)):
        if isinstance(save_sols, str):
            filename = save_sols
        else:
            filename = 'data.beluga'

        save(out, ocp, bvp, filename=filename)

    return out
    def compile_scaling(self):

        lambdify = self.lambdify

        units = self.prob.units
        units_syms = getattr_from_list(units, 'sym')
        units_func = getattr_from_list(units, 'expr')

        compute_unit_factors = lambdify(self._units_args, units_func)

        scalable_components_list = [
            self.prob.independent_variable, self.prob.states, self.prob.quads,
            self.prob.controls, self.prob.parameters,
            self.prob.constraint_parameters, self.prob.constants
        ]

        compute_factors = [
            lambdify(units_syms, getattr_from_list(component, 'units'))
            for component in scalable_components_list
        ]

        def compute_scale_factors(sol: Trajectory):

            ref_vals = tuple([max_mag(_arr)
                              for _arr in [sol.t, sol.y, sol.q]] + [
                                  np.fabs(_arr) for _arr in [
                                      sol.dynamical_parameters,
                                      sol.nondynamical_parameters, sol.const
                                  ]
                              ])

            unit_factors = compute_unit_factors(*ref_vals)

            return tuple([
                compute_factor(*unit_factors)
                for compute_factor in compute_factors
            ])

        def scale_sol(sol: Trajectory, scale_factors, inv=False):

            sol = copy.deepcopy(sol)

            if inv:
                op = np.multiply
            else:
                op = np.divide

            sol.t = op(sol.t, scale_factors[0])
            sol.y = op(sol.y, scale_factors[1])
            sol.q = op(sol.q, scale_factors[2])
            if sol.u.size > 0:
                sol.u = op(sol.u, scale_factors[3])
            sol.dynamical_parameters = op(sol.dynamical_parameters,
                                          scale_factors[4])
            sol.nondynamical_parameters = op(sol.nondynamical_parameters,
                                             scale_factors[5])
            sol.const = op(sol.const, scale_factors[6])

            return sol

        self.compute_scale_factors = compute_scale_factors
        self.scale_sol = scale_sol

        return self
    def compile_bc(self, use_quad_arg=False):

        sym_initial_bc = getattr_from_list(self.prob.constraints['initial'],
                                           'expr')
        sym_terminal_bc = getattr_from_list(self.prob.constraints['terminal'],
                                            'expr')

        if use_quad_arg:
            if self.compute_u is None:
                _args = self._bc_args_w_quads

                compute_initial_bc = self.lambdify(_args, sym_initial_bc)
                compute_terminal_bc = self.lambdify(_args, sym_terminal_bc)

                def bc_func(_y0, _q0, _yf, _qf, _p, _p_con, _k):
                    bc_0 = np.array(
                        compute_initial_bc(_y0, _q0, _p, _p_con, _k))
                    bc_f = np.array(
                        compute_terminal_bc(_yf, _qf, _p, _p_con, _k))
                    return np.concatenate((bc_0, bc_f))
            else:
                _args = self._bc_args_w_quads_controls

                compute_initial_bc = self.lambdify(_args, sym_initial_bc)
                compute_terminal_bc = self.lambdify(_args, sym_terminal_bc)

                compute_u = self.compute_u

                def bc_func(_y0, _q0, _yf, _qf, _p, _p_con, _k):

                    _u0 = compute_u(_y0, _p, _k)
                    _uf = compute_u(_yf, _p, _k)

                    bc_0 = np.array(
                        compute_initial_bc(_y0, _q0, _u0, _p, _p_con, _k))
                    bc_f = np.array(
                        compute_terminal_bc(_yf, _qf, _uf, _p, _p_con, _k))
                    return np.concatenate((bc_0, bc_f))

            _combined_args = \
                ([self.prob.independent_variable.sym] + self._state_syms + self._quad_syms) * 2 \
                + self._parameter_syms + self._constraint_parameters_syms + self._constant_syms
            self.bc_func = jit_compile_func(bc_func, _combined_args)
            self.compute_initial_bc, self.compute_terminal_bc = compute_initial_bc, compute_terminal_bc

        else:
            if self.compute_u is None:
                _args = self._bc_args

                compute_initial_bc = self.lambdify(_args, sym_initial_bc)
                compute_terminal_bc = self.lambdify(_args, sym_terminal_bc)

                def bc_func(_y0, _yf, _p, _p_con, _k):
                    bc_0 = np.array(compute_initial_bc(_y0, _p, _p_con, _k))
                    bc_f = np.array(compute_terminal_bc(_yf, _p, _p_con, _k))
                    return np.concatenate((bc_0, bc_f))

            else:
                _args = self._bc_args_w_controls

                compute_initial_bc = self.lambdify(_args, sym_initial_bc)
                compute_terminal_bc = self.lambdify(_args, sym_terminal_bc)

                compute_u = self.compute_u

                def bc_func(_y0, _yf, _p, _p_con, _k):

                    _u0 = compute_u(_y0, _p, _k)
                    _uf = compute_u(_yf, _p, _k)

                    bc_0 = np.array(
                        compute_initial_bc(_y0, _u0, _p, _p_con, _k))
                    bc_f = np.array(
                        compute_terminal_bc(_yf, _uf, _p, _p_con, _k))
                    return np.concatenate((bc_0, bc_f))

            _combined_args = [self._state_syms] * 2 + [self._parameter_syms] + [self._constraint_parameters_syms] \
                             + [self._constant_syms]

            self.bc_func = jit_compile_func(bc_func, _combined_args)
            self.compute_initial_bc, self.compute_terminal_bc = compute_initial_bc, compute_terminal_bc

        return self.bc_func