<commit_before>//
// Copyright (c) 2019, University of Edinburgh
// All rights reserved.
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are met:
//
//  * Redistributions of source code must retain the above copyright notice,
//    this list of conditions and the following disclaimer.
//  * Redistributions in binary form must reproduce the above copyright
//    notice, this list of conditions and the following disclaimer in the
//    documentation and/or other materials provided with the distribution.
//  * Neither the name of  nor the names of its contributors may be used to
//    endorse or promote products derived from this software without specific
//    prior written permission.
//
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
// AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
// ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
// LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
// CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
// SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
// INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
// CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
// ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
// POSSIBILITY OF SUCH DAMAGE.
//

#include <exotica_ilqg_solver/ilqg_solver.h>

REGISTER_MOTIONSOLVER_TYPE("ILQGSolver", exotica::ILQGSolver)

namespace exotica
{
void ILQGSolver::SpecifyProblem(PlanningProblemPtr pointer)
{
    if (pointer->type() != "exotica::DynamicTimeIndexedShootingProblem")
    {
        ThrowNamed("This ILQGSolver can't solve problem of type '" << pointer->type() << "'!");
    }

    MotionSolver::SpecifyProblem(pointer);
    prob_ = std::static_pointer_cast<DynamicTimeIndexedShootingProblem>(pointer);
    dynamics_solver_ = prob_->GetScene()->GetDynamicsSolver();
    if (debug_) HIGHLIGHT_NAMED("ILQGSolver", "initialized");
}

void ILQGSolver::BackwardPass()
{
    constexpr double min_clamp_ = -1e10;
    constexpr double max_clamp_ = 1e10;
    const int T = prob_->get_T();
    const double dt = dynamics_solver_->get_dt();
    const int NU = prob_->get_num_controls();

    // Noise terms
    Eigen::VectorXd big_C_times_little_c = Eigen::VectorXd::Zero(NU, 1);
    Eigen::MatrixXd big_C_times_big_C = Eigen::MatrixXd::Zero(NU, NU);
    Eigen::MatrixXd little_c_times_little_c = Eigen::MatrixXd::Zero(1, 1);

    // Value function and derivatives at the final timestep
    double s0 = prob_->GetStateCost(T - 1);
    Eigen::MatrixXd s = prob_->GetStateCostJacobian(T - 1);
    Eigen::MatrixXd S = prob_->GetStateCostHessian(T - 1);

    for (int t = T - 2; t > 0; --t)
    {
        // eq. 3
        Eigen::VectorXd x = prob_->get_X(t), u = prob_->get_U(t);
        dynamics_solver_->ComputeDerivatives(x, u);
        Eigen::MatrixXd A = dynamics_solver_->get_fx(), B = dynamics_solver_->get_fu();

        A.noalias() = A * dt + Eigen::MatrixXd::Identity(A.rows(), A.cols());
        B.noalias() = B * dt;

        double q0 = dt * (prob_->GetStateCost(t) + prob_->GetControlCost(t));
        // Aliases from the paper used. These are used with different names in e.g. DDPSolver.
        Eigen::MatrixXd q = dt * prob_->GetStateCostJacobian(t);
        Eigen::MatrixXd Q = dt * prob_->GetStateCostHessian(t);
        Eigen::MatrixXd r = dt * prob_->GetControlCostJacobian(t);
        Eigen::MatrixXd R = dt * prob_->GetControlCostHessian(t);
        Eigen::MatrixXd P = dt * prob_->GetStateControlCostHessian();

        Eigen::MatrixXd g = r + B.transpose() * s;
        Eigen::MatrixXd G = P + B.transpose() * S * A;
        Eigen::MatrixXd H = R + B.transpose() * S * B;

        if (parameters_.IncludeNoiseTerms)
        {
            Eigen::MatrixXd F = prob_->get_F(t);
            for (int i = 0; i < NU; ++i)
            {
                Eigen::MatrixXd C = std::sqrt(dt) * prob_->GetControlNoiseJacobian(i);
                Eigen::VectorXd c = std::sqrt(dt) * F.col(i);

                big_C_times_little_c = big_C_times_little_c + C.transpose() * S * c;
                big_C_times_big_C = big_C_times_big_C + C.transpose() * S * C;
                little_c_times_little_c = little_c_times_little_c + c.transpose() * S * c;
            }

            g = g + big_C_times_little_c;
            H = H + big_C_times_big_C;
        }

        // optimal U
        Eigen::EigenSolver<Eigen::Matrix<double, Eigen::Dynamic, Eigen::Dynamic>> eig_solver(H);
        auto d = eig_solver.eigenvalues();
        auto V = eig_solver.eigenvectors();
        Eigen::MatrixXcd D = Eigen::MatrixXcd::Zero(d.size(), d.size());

        for (int i = 0; i < d.size(); ++i)
        {
            if (d[i].real() < 0)
                d[i] = 0;
            d[i] = 1. / (d[i] + parameters_.RegularizationRate);
            D(i, i) = d[i];
        }

        Eigen::MatrixXd H1 = (V * D * V.transpose()).real();

        l_gains_[t] = -H1 * g;
        L_gains_[t] = -H1 * G;

        // Recursive terms update
        S = Q + A.transpose() * S * A + L_gains_[t].transpose() * H * L_gains_[t] + L_gains_[t].transpose() * G + G.transpose() * L_gains_[t];
        s = q + A.transpose() * s + L_gains_[t].transpose() * H * l_gains_[t] +
            L_gains_[t].transpose() * g + G.transpose() * l_gains_[t];
        s0 = q0 + s0 + (l_gains_[t].transpose() * H * l_gains_[t] / 2.0 +
                        l_gains_[t].transpose() * g)(0);

        if (parameters_.IncludeNoiseTerms)
        {
            s0 = s0 + 0.5 * little_c_times_little_c(0);
        }

        // fix for large values
        S = S.unaryExpr([min_clamp_, max_clamp_](double x) -> double {
            return std::min(std::max(x, min_clamp_), max_clamp_);
        });
        s = s.unaryExpr([min_clamp_, max_clamp_](double x) -> double {
            return std::min(std::max(x, min_clamp_), max_clamp_);
        });
        s0 = std::min(std::max(s0, min_clamp_), max_clamp_);
    }
}

double ILQGSolver::ForwardPass(const double alpha, Eigen::MatrixXdRefConst ref_x, Eigen::MatrixXdRefConst ref_u)
{
    double cost = 0;
    const int T = prob_->get_T();
    const Eigen::MatrixXd control_limits = dynamics_solver_->get_control_limits();
    const double dt = dynamics_solver_->get_dt();

    // NOTE: Todorov uses the linearized system in forward simulation.
    //  We here use the full system dynamics. YMMV
    for (int t = 0; t < T - 1; ++t)
    {
        Eigen::VectorXd u = ref_u.col(t);
        // eq. 12
        Eigen::VectorXd delta_uk = l_gains_[t] +
                                   L_gains_[t] * dynamics_solver_->StateDelta(prob_->get_X(t), ref_x.col(t));

        u.noalias() += alpha * delta_uk;
        // clamp controls
        u = u.cwiseMax(control_limits.col(0)).cwiseMin(control_limits.col(1));

        prob_->Update(u, t);
        cost += dt * (prob_->GetControlCost(t) + prob_->GetStateCost(t));
    }

    // add terminal cost
    cost += prob_->GetStateCost(T - 1);
    return cost;
}

void ILQGSolver::Solve(Eigen::MatrixXd& solution)
{
    if (!prob_) ThrowNamed("Solver has not been initialized!");
    Timer planning_timer, backward_pass_timer, line_search_timer;
    // TODO: This is an interesting approach but might give us incorrect results.
    prob_->DisableStochasticUpdates();

    const int T = prob_->get_T();
    const int NU = prob_->get_num_controls();
    const int NX = prob_->get_num_positions() + prob_->get_num_velocities();
    const double dt = dynamics_solver_->get_dt();
    prob_->ResetCostEvolution(GetNumberOfMaxIterations() + 1);
    prob_->PreUpdate();

    double initial_cost = 0;
    for (int t = 0; t < T - 1; ++t)
        initial_cost += dt * (prob_->GetControlCost(t) + prob_->GetStateCost(t));

    // add terminal cost
    initial_cost += prob_->GetStateCost(T - 1);
    prob_->SetCostEvolution(0, initial_cost);

    // initialize Gain matrices
    l_gains_.assign(T, Eigen::MatrixXd::Zero(NU, 1));
    L_gains_.assign(T, Eigen::MatrixXd::Zero(NU, NX));

    // all of the below are not pointers, since we want to copy over
    //  solutions across iterations
    Eigen::MatrixXd new_U, global_best_U = prob_->get_U();
    solution.resize(T - 1, NU);

    if (debug_) HIGHLIGHT_NAMED("ILQGSolver", "Running ILQG solver for max " << parameters_.MaxIterations << " iterations");

    double last_cost = initial_cost, global_best_cost = initial_cost;
    int last_best_iteration = 0;

    for (int iteration = 1; iteration <= GetNumberOfMaxIterations(); ++iteration)
    {
        // Check whether user interrupted (Ctrl+C)
        if (Server::IsRos() && !ros::ok())
        {
            if (debug_) HIGHLIGHT("Solving cancelled by user");
            prob_->termination_criterion = TerminationCriterion::UserDefined;
            break;
        }

        // Backwards pass computes the gains
        backward_pass_timer.Reset();
        BackwardPass();
        if (debug_) HIGHLIGHT_NAMED("ILQGSolver", "Backward pass complete in " << backward_pass_timer.GetDuration());
        // if (debug_) HIGHLIGHT_NAMED("ILQGSolver", "Backward pass complete in " << backward_pass_timer.GetDuration());

        line_search_timer.Reset();
        // forward pass to compute new control trajectory
        // TODO: Configure line-search space from xml
        // TODO (Wolf): What you are doing is a forward line-search when we may try a
        //    backtracking line search for a performance improvement later - this just as an aside.
        const Eigen::VectorXd alpha_space = Eigen::VectorXd::LinSpaced(10, 0.1, 1.0);
        double current_cost = 0, best_alpha = 0;

        Eigen::MatrixXd ref_x = prob_->get_X(),
                        ref_u = prob_->get_U();
        // perform a linear search to find the best rate
        for (int ai = 0; ai < alpha_space.rows(); ++ai)
        {
            double alpha = alpha_space(ai);
            double cost = ForwardPass(alpha, ref_x, ref_u);

            if (ai == 0 || (cost < current_cost && !std::isnan(cost)))
            {
                current_cost = cost;
                new_U = prob_->get_U();
                best_alpha = alpha;
            }
            // else if (cost > current_cost)
            // break;
        }

        // finite checks
        if (!new_U.allFinite() || !std::isfinite(current_cost))
        {
            prob_->termination_criterion = TerminationCriterion::Divergence;
            WARNING_NAMED("ILQGSolver", "Diverged!");
            return;
        }

        if (debug_)
        {
            HIGHLIGHT_NAMED("ILQGSolver", "Forward pass complete in " << line_search_timer.GetDuration() << " with cost: " << current_cost << " and alpha " << best_alpha);
            HIGHLIGHT_NAMED("ILQGSolver", "Final state: " << prob_->get_X(T - 1).transpose());
        }

        // copy solutions for next iteration
        if (global_best_cost > current_cost)
        {
            global_best_cost = current_cost;
            last_best_iteration = iteration;
            global_best_U = new_U;
            best_ref_x_ = ref_x;
            best_ref_u_ = ref_u;
        }

        if (iteration - last_best_iteration > parameters_.FunctionTolerancePatience)
        {
            if (debug_) HIGHLIGHT_NAMED("ILQGSolver", "Early stopping criterion reached. Time: " << planning_timer.GetDuration());
            prob_->termination_criterion = TerminationCriterion::FunctionTolerance;
            break;
        }

        if (last_cost - current_cost < parameters_.FunctionTolerance && last_cost - current_cost > 0)
        {
            if (debug_) HIGHLIGHT_NAMED("ILQGSolver", "Function tolerance reached. Time: " << planning_timer.GetDuration());
            prob_->termination_criterion = TerminationCriterion::Divergence;
            break;
        }

        if (debug_ && iteration == parameters_.MaxIterations)
        {
            HIGHLIGHT_NAMED("ILQGSolver", "Max iterations reached. Time: " << planning_timer.GetDuration());
            prob_->termination_criterion = TerminationCriterion::IterationLimit;
        }

        last_cost = current_cost;
        for (int t = 0; t < T - 1; ++t)
            prob_->Update(new_U.col(t), t);
        prob_->SetCostEvolution(iteration, current_cost);
    }

    // store the best solution found over all iterations
    for (int t = 0; t < T - 1; ++t)
    {
        solution.row(t) = global_best_U.col(t).transpose();
        prob_->Update(global_best_U.col(t), t);
    }

    planning_time_ = planning_timer.GetDuration();

    // TODO: See note at disable.
    prob_->EnableStochasticUpdates();
}

Eigen::VectorXd ILQGSolver::GetFeedbackControl(Eigen::VectorXdRefConst x, int t) const
{
    const Eigen::MatrixXd control_limits = dynamics_solver_->get_control_limits();

    Eigen::VectorXd delta_uk = l_gains_[t] +
                               L_gains_[t] * dynamics_solver_->StateDelta(x, best_ref_x_.col(t));

    Eigen::VectorXd u = best_ref_u_.col(t) + delta_uk;
    return u.cwiseMax(control_limits.col(0)).cwiseMin(control_limits.col(1));
}

}  // namespace exotica
<commit_msg>[exotica_ilqg_solver] Upgrade get_num_positions etc.<commit_after>//
// Copyright (c) 2019, University of Edinburgh
// All rights reserved.
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are met:
//
//  * Redistributions of source code must retain the above copyright notice,
//    this list of conditions and the following disclaimer.
//  * Redistributions in binary form must reproduce the above copyright
//    notice, this list of conditions and the following disclaimer in the
//    documentation and/or other materials provided with the distribution.
//  * Neither the name of  nor the names of its contributors may be used to
//    endorse or promote products derived from this software without specific
//    prior written permission.
//
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
// AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
// ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
// LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
// CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
// SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
// INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
// CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
// ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
// POSSIBILITY OF SUCH DAMAGE.
//

#include <exotica_ilqg_solver/ilqg_solver.h>

REGISTER_MOTIONSOLVER_TYPE("ILQGSolver", exotica::ILQGSolver)

namespace exotica
{
void ILQGSolver::SpecifyProblem(PlanningProblemPtr pointer)
{
    if (pointer->type() != "exotica::DynamicTimeIndexedShootingProblem")
    {
        ThrowNamed("This ILQGSolver can't solve problem of type '" << pointer->type() << "'!");
    }

    MotionSolver::SpecifyProblem(pointer);
    prob_ = std::static_pointer_cast<DynamicTimeIndexedShootingProblem>(pointer);
    dynamics_solver_ = prob_->GetScene()->GetDynamicsSolver();
    if (debug_) HIGHLIGHT_NAMED("ILQGSolver", "initialized");
}

void ILQGSolver::BackwardPass()
{
    constexpr double min_clamp_ = -1e10;
    constexpr double max_clamp_ = 1e10;
    const int T = prob_->get_T();
    const double dt = dynamics_solver_->get_dt();
    const int NU = prob_->GetScene()->get_num_controls();

    // Noise terms
    Eigen::VectorXd big_C_times_little_c = Eigen::VectorXd::Zero(NU, 1);
    Eigen::MatrixXd big_C_times_big_C = Eigen::MatrixXd::Zero(NU, NU);
    Eigen::MatrixXd little_c_times_little_c = Eigen::MatrixXd::Zero(1, 1);

    // Value function and derivatives at the final timestep
    double s0 = prob_->GetStateCost(T - 1);
    Eigen::MatrixXd s = prob_->GetStateCostJacobian(T - 1);
    Eigen::MatrixXd S = prob_->GetStateCostHessian(T - 1);

    for (int t = T - 2; t > 0; --t)
    {
        // eq. 3
        Eigen::VectorXd x = prob_->get_X(t), u = prob_->get_U(t);
        dynamics_solver_->ComputeDerivatives(x, u);
        Eigen::MatrixXd A = dynamics_solver_->get_fx(), B = dynamics_solver_->get_fu();

        A.noalias() = A * dt + Eigen::MatrixXd::Identity(A.rows(), A.cols());
        B.noalias() = B * dt;

        double q0 = dt * (prob_->GetStateCost(t) + prob_->GetControlCost(t));
        // Aliases from the paper used. These are used with different names in e.g. DDPSolver.
        Eigen::MatrixXd q = dt * prob_->GetStateCostJacobian(t);
        Eigen::MatrixXd Q = dt * prob_->GetStateCostHessian(t);
        Eigen::MatrixXd r = dt * prob_->GetControlCostJacobian(t);
        Eigen::MatrixXd R = dt * prob_->GetControlCostHessian(t);
        Eigen::MatrixXd P = dt * prob_->GetStateControlCostHessian();

        Eigen::MatrixXd g = r + B.transpose() * s;
        Eigen::MatrixXd G = P + B.transpose() * S * A;
        Eigen::MatrixXd H = R + B.transpose() * S * B;

        if (parameters_.IncludeNoiseTerms)
        {
            Eigen::MatrixXd F = prob_->get_F(t);
            for (int i = 0; i < NU; ++i)
            {
                Eigen::MatrixXd C = std::sqrt(dt) * prob_->GetControlNoiseJacobian(i);
                Eigen::VectorXd c = std::sqrt(dt) * F.col(i);

                big_C_times_little_c = big_C_times_little_c + C.transpose() * S * c;
                big_C_times_big_C = big_C_times_big_C + C.transpose() * S * C;
                little_c_times_little_c = little_c_times_little_c + c.transpose() * S * c;
            }

            g = g + big_C_times_little_c;
            H = H + big_C_times_big_C;
        }

        // optimal U
        Eigen::EigenSolver<Eigen::Matrix<double, Eigen::Dynamic, Eigen::Dynamic>> eig_solver(H);
        auto d = eig_solver.eigenvalues();
        auto V = eig_solver.eigenvectors();
        Eigen::MatrixXcd D = Eigen::MatrixXcd::Zero(d.size(), d.size());

        for (int i = 0; i < d.size(); ++i)
        {
            if (d[i].real() < 0)
                d[i] = 0;
            d[i] = 1. / (d[i] + parameters_.RegularizationRate);
            D(i, i) = d[i];
        }

        Eigen::MatrixXd H1 = (V * D * V.transpose()).real();

        l_gains_[t] = -H1 * g;
        L_gains_[t] = -H1 * G;

        // Recursive terms update
        S = Q + A.transpose() * S * A + L_gains_[t].transpose() * H * L_gains_[t] + L_gains_[t].transpose() * G + G.transpose() * L_gains_[t];
        s = q + A.transpose() * s + L_gains_[t].transpose() * H * l_gains_[t] +
            L_gains_[t].transpose() * g + G.transpose() * l_gains_[t];
        s0 = q0 + s0 + (l_gains_[t].transpose() * H * l_gains_[t] / 2.0 +
                        l_gains_[t].transpose() * g)(0);

        if (parameters_.IncludeNoiseTerms)
        {
            s0 = s0 + 0.5 * little_c_times_little_c(0);
        }

        // fix for large values
        S = S.unaryExpr([min_clamp_, max_clamp_](double x) -> double {
            return std::min(std::max(x, min_clamp_), max_clamp_);
        });
        s = s.unaryExpr([min_clamp_, max_clamp_](double x) -> double {
            return std::min(std::max(x, min_clamp_), max_clamp_);
        });
        s0 = std::min(std::max(s0, min_clamp_), max_clamp_);
    }
}

double ILQGSolver::ForwardPass(const double alpha, Eigen::MatrixXdRefConst ref_x, Eigen::MatrixXdRefConst ref_u)
{
    double cost = 0;
    const int T = prob_->get_T();
    const Eigen::MatrixXd control_limits = dynamics_solver_->get_control_limits();
    const double dt = dynamics_solver_->get_dt();

    // NOTE: Todorov uses the linearized system in forward simulation.
    //  We here use the full system dynamics. YMMV
    for (int t = 0; t < T - 1; ++t)
    {
        Eigen::VectorXd u = ref_u.col(t);
        // eq. 12
        Eigen::VectorXd delta_uk = l_gains_[t] +
                                   L_gains_[t] * dynamics_solver_->StateDelta(prob_->get_X(t), ref_x.col(t));

        u.noalias() += alpha * delta_uk;
        // clamp controls
        u = u.cwiseMax(control_limits.col(0)).cwiseMin(control_limits.col(1));

        prob_->Update(u, t);
        cost += dt * (prob_->GetControlCost(t) + prob_->GetStateCost(t));
    }

    // add terminal cost
    cost += prob_->GetStateCost(T - 1);
    return cost;
}

void ILQGSolver::Solve(Eigen::MatrixXd& solution)
{
    if (!prob_) ThrowNamed("Solver has not been initialized!");
    Timer planning_timer, backward_pass_timer, line_search_timer;
    // TODO: This is an interesting approach but might give us incorrect results.
    prob_->DisableStochasticUpdates();

    const int T = prob_->get_T();
    const int NU = prob_->GetScene()->get_num_controls();
    const int NX = prob_->GetScene()->get_num_state();
    const double dt = dynamics_solver_->get_dt();
    prob_->ResetCostEvolution(GetNumberOfMaxIterations() + 1);
    prob_->PreUpdate();

    double initial_cost = 0;
    for (int t = 0; t < T - 1; ++t)
        initial_cost += dt * (prob_->GetControlCost(t) + prob_->GetStateCost(t));

    // add terminal cost
    initial_cost += prob_->GetStateCost(T - 1);
    prob_->SetCostEvolution(0, initial_cost);

    // initialize Gain matrices
    l_gains_.assign(T, Eigen::MatrixXd::Zero(NU, 1));
    L_gains_.assign(T, Eigen::MatrixXd::Zero(NU, NX));

    // all of the below are not pointers, since we want to copy over
    //  solutions across iterations
    Eigen::MatrixXd new_U, global_best_U = prob_->get_U();
    solution.resize(T - 1, NU);

    if (debug_) HIGHLIGHT_NAMED("ILQGSolver", "Running ILQG solver for max " << parameters_.MaxIterations << " iterations");

    double last_cost = initial_cost, global_best_cost = initial_cost;
    int last_best_iteration = 0;

    for (int iteration = 1; iteration <= GetNumberOfMaxIterations(); ++iteration)
    {
        // Check whether user interrupted (Ctrl+C)
        if (Server::IsRos() && !ros::ok())
        {
            if (debug_) HIGHLIGHT("Solving cancelled by user");
            prob_->termination_criterion = TerminationCriterion::UserDefined;
            break;
        }

        // Backwards pass computes the gains
        backward_pass_timer.Reset();
        BackwardPass();
        if (debug_) HIGHLIGHT_NAMED("ILQGSolver", "Backward pass complete in " << backward_pass_timer.GetDuration());
        // if (debug_) HIGHLIGHT_NAMED("ILQGSolver", "Backward pass complete in " << backward_pass_timer.GetDuration());

        line_search_timer.Reset();
        // forward pass to compute new control trajectory
        // TODO: Configure line-search space from xml
        // TODO (Wolf): What you are doing is a forward line-search when we may try a
        //    backtracking line search for a performance improvement later - this just as an aside.
        const Eigen::VectorXd alpha_space = Eigen::VectorXd::LinSpaced(10, 0.1, 1.0);
        double current_cost = 0, best_alpha = 0;

        Eigen::MatrixXd ref_x = prob_->get_X(),
                        ref_u = prob_->get_U();
        // perform a linear search to find the best rate
        for (int ai = 0; ai < alpha_space.rows(); ++ai)
        {
            double alpha = alpha_space(ai);
            double cost = ForwardPass(alpha, ref_x, ref_u);

            if (ai == 0 || (cost < current_cost && !std::isnan(cost)))
            {
                current_cost = cost;
                new_U = prob_->get_U();
                best_alpha = alpha;
            }
            // else if (cost > current_cost)
            // break;
        }

        // finite checks
        if (!new_U.allFinite() || !std::isfinite(current_cost))
        {
            prob_->termination_criterion = TerminationCriterion::Divergence;
            WARNING_NAMED("ILQGSolver", "Diverged!");
            return;
        }

        if (debug_)
        {
            HIGHLIGHT_NAMED("ILQGSolver", "Forward pass complete in " << line_search_timer.GetDuration() << " with cost: " << current_cost << " and alpha " << best_alpha);
            HIGHLIGHT_NAMED("ILQGSolver", "Final state: " << prob_->get_X(T - 1).transpose());
        }

        // copy solutions for next iteration
        if (global_best_cost > current_cost)
        {
            global_best_cost = current_cost;
            last_best_iteration = iteration;
            global_best_U = new_U;
            best_ref_x_ = ref_x;
            best_ref_u_ = ref_u;
        }

        if (iteration - last_best_iteration > parameters_.FunctionTolerancePatience)
        {
            if (debug_) HIGHLIGHT_NAMED("ILQGSolver", "Early stopping criterion reached. Time: " << planning_timer.GetDuration());
            prob_->termination_criterion = TerminationCriterion::FunctionTolerance;
            break;
        }

        if (last_cost - current_cost < parameters_.FunctionTolerance && last_cost - current_cost > 0)
        {
            if (debug_) HIGHLIGHT_NAMED("ILQGSolver", "Function tolerance reached. Time: " << planning_timer.GetDuration());
            prob_->termination_criterion = TerminationCriterion::Divergence;
            break;
        }

        if (debug_ && iteration == parameters_.MaxIterations)
        {
            HIGHLIGHT_NAMED("ILQGSolver", "Max iterations reached. Time: " << planning_timer.GetDuration());
            prob_->termination_criterion = TerminationCriterion::IterationLimit;
        }

        last_cost = current_cost;
        for (int t = 0; t < T - 1; ++t)
            prob_->Update(new_U.col(t), t);
        prob_->SetCostEvolution(iteration, current_cost);
    }

    // store the best solution found over all iterations
    for (int t = 0; t < T - 1; ++t)
    {
        solution.row(t) = global_best_U.col(t).transpose();
        prob_->Update(global_best_U.col(t), t);
    }

    planning_time_ = planning_timer.GetDuration();

    // TODO: See note at disable.
    prob_->EnableStochasticUpdates();
}

Eigen::VectorXd ILQGSolver::GetFeedbackControl(Eigen::VectorXdRefConst x, int t) const
{
    const Eigen::MatrixXd control_limits = dynamics_solver_->get_control_limits();

    Eigen::VectorXd delta_uk = l_gains_[t] +
                               L_gains_[t] * dynamics_solver_->StateDelta(x, best_ref_x_.col(t));

    Eigen::VectorXd u = best_ref_u_.col(t) + delta_uk;
    return u.cwiseMax(control_limits.col(0)).cwiseMin(control_limits.col(1));
}

}  // namespace exotica
<|endoftext|>


<commit_before>/*****************************************************************************
 * Media Library
 *****************************************************************************
 * Copyright (C) 2015 Hugo Beauzée-Luyssen, Videolabs
 *
 * Authors: Hugo Beauzée-Luyssen<hugo@beauzee.fr>
 *
 * This program is free software; you can redistribute it and/or modify it
 * under the terms of the GNU Lesser General Public License as published by
 * the Free Software Foundation; either version 2.1 of the License, or
 * (at your option) any later version.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
 * GNU Lesser General Public License for more details.
 *
 * You should have received a copy of the GNU Lesser General Public License
 * along with this program; if not, write to the Free Software Foundation,
 * Inc., 51 Franklin Street, Fifth Floor, Boston MA 02110-1301, USA.
 *****************************************************************************/

#include "Album.h"
#include "AlbumTrack.h"
#include "Artist.h"
#include "Media.h"

#include "database/SqliteTools.h"

const std::string policy::AlbumTable::Name = "Album";
const std::string policy::AlbumTable::CacheColumn = "id_album";
unsigned int Album::* const policy::AlbumTable::PrimaryKey = &Album::m_id;

Album::Album(DBConnection dbConnection, sqlite::Row& row)
    : m_dbConnection( dbConnection )
{
    row >> m_id
        >> m_title
        >> m_releaseDate
        >> m_shortSummary
        >> m_artworkUrl
        >> m_lastSyncDate;
}

Album::Album(const std::string& title )
    : m_id( 0 )
    , m_title( title )
    , m_releaseDate( 0 )
    , m_lastSyncDate( 0 )
{
}

unsigned int Album::id() const
{
    return m_id;
}

const std::string& Album::title() const
{
    return m_title;
}

time_t Album::releaseDate() const
{
    return m_releaseDate;
}

bool Album::setReleaseDate( time_t date )
{
    static const std::string& req = "UPDATE " + policy::AlbumTable::Name
            + " SET release_date = ? WHERE id_album = ?";
    if ( sqlite::Tools::executeUpdate( m_dbConnection, req, date, m_id ) == false )
        return false;
    m_releaseDate = date;
    return true;
}

const std::string& Album::shortSummary() const
{
    return m_shortSummary;
}

bool Album::setShortSummary( const std::string& summary )
{
    static const std::string& req = "UPDATE " + policy::AlbumTable::Name
            + " SET short_summary = ? WHERE id_album = ?";
    if ( sqlite::Tools::executeUpdate( m_dbConnection, req, summary, m_id ) == false )
        return false;
    m_shortSummary = summary;
    return true;
}

const std::string& Album::artworkUrl() const
{
    return m_artworkUrl;
}

bool Album::setArtworkUrl( const std::string& artworkUrl )
{
    static const std::string& req = "UPDATE " + policy::AlbumTable::Name
            + " SET artwork_url = ? WHERE id_album = ?";
    if ( sqlite::Tools::executeUpdate( m_dbConnection, req, artworkUrl, m_id ) == false )
        return false;
    m_artworkUrl = artworkUrl;
    return true;
}

time_t Album::lastSyncDate() const
{
    return m_lastSyncDate;
}

std::vector<MediaPtr> Album::tracks() const
{
    static const std::string req = "SELECT med.* FROM " + policy::MediaTable::Name + " med "
            " LEFT JOIN " + policy::AlbumTrackTable::Name + " att ON att.media_id = med.id_media "
            " WHERE att.album_id = ?";
    return Media::fetchAll( m_dbConnection, req, m_id );
}

std::shared_ptr<AlbumTrack> Album::addTrack(std::shared_ptr<Media> media, unsigned int trackNb )
{
    auto track = AlbumTrack::create( m_dbConnection, m_id, media.get(), trackNb );
    media->setAlbumTrack( track );
    return track;
}

std::vector<ArtistPtr> Album::artists() const
{
    static const std::string req = "SELECT art.* FROM " + policy::ArtistTable::Name + " art "
            "LEFT JOIN AlbumArtistRelation aar ON aar.id_artist = art.id_artist "
            "WHERE aar.id_album = ?";
    return Artist::fetchAll( m_dbConnection, req, m_id );
}

bool Album::addArtist( std::shared_ptr<Artist> artist )
{
    static const std::string req = "INSERT INTO AlbumArtistRelation VALUES(?, ?)";
    if ( m_id == 0 || artist->id() == 0 )
    {
        LOG_ERROR("Both artist * album need to be inserted in database before being linked together" );
        return false;
    }
    return sqlite::Tools::executeRequest( m_dbConnection, req, m_id, artist->id() );
}

bool Album::createTable(DBConnection dbConnection )
{
    static const std::string req = "CREATE TABLE IF NOT EXISTS " +
            policy::AlbumTable::Name +
            "("
                "id_album INTEGER PRIMARY KEY AUTOINCREMENT,"
                "title TEXT UNIQUE ON CONFLICT FAIL,"
                "release_date UNSIGNED INTEGER,"
                "short_summary TEXT,"
                "artwork_url TEXT,"
                "UNSIGNED INTEGER last_sync_date"
            ")";
    static const std::string reqRel = "CREATE TABLE IF NOT EXISTS AlbumArtistRelation("
                "id_album INTEGER,"
                "id_artist INTEGER,"
                "PRIMARY KEY (id_album, id_artist),"
                "FOREIGN KEY(id_album) REFERENCES " + policy::AlbumTable::Name + "("
                    + policy::AlbumTable::CacheColumn + ") ON DELETE CASCADE,"
                "FOREIGN KEY(id_artist) REFERENCES " + policy::ArtistTable::Name + "("
                    + policy::ArtistTable::CacheColumn + ") ON DELETE CASCADE"
            ")";
    return sqlite::Tools::executeRequest( dbConnection, req ) &&
            sqlite::Tools::executeRequest( dbConnection, reqRel );
}

std::shared_ptr<Album> Album::create(DBConnection dbConnection, const std::string& title )
{
    auto album = std::make_shared<Album>( title );
    static const std::string req = "INSERT INTO " + policy::AlbumTable::Name +
            "(id_album, title) VALUES(NULL, ?)";
    if ( _Cache::insert( dbConnection, album, req, title ) == false )
        return nullptr;
    album->m_dbConnection = dbConnection;
    return album;
}
<commit_msg>Album: Sort tracks by track number<commit_after>/*****************************************************************************
 * Media Library
 *****************************************************************************
 * Copyright (C) 2015 Hugo Beauzée-Luyssen, Videolabs
 *
 * Authors: Hugo Beauzée-Luyssen<hugo@beauzee.fr>
 *
 * This program is free software; you can redistribute it and/or modify it
 * under the terms of the GNU Lesser General Public License as published by
 * the Free Software Foundation; either version 2.1 of the License, or
 * (at your option) any later version.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
 * GNU Lesser General Public License for more details.
 *
 * You should have received a copy of the GNU Lesser General Public License
 * along with this program; if not, write to the Free Software Foundation,
 * Inc., 51 Franklin Street, Fifth Floor, Boston MA 02110-1301, USA.
 *****************************************************************************/

#include "Album.h"
#include "AlbumTrack.h"
#include "Artist.h"
#include "Media.h"

#include "database/SqliteTools.h"

const std::string policy::AlbumTable::Name = "Album";
const std::string policy::AlbumTable::CacheColumn = "id_album";
unsigned int Album::* const policy::AlbumTable::PrimaryKey = &Album::m_id;

Album::Album(DBConnection dbConnection, sqlite::Row& row)
    : m_dbConnection( dbConnection )
{
    row >> m_id
        >> m_title
        >> m_releaseDate
        >> m_shortSummary
        >> m_artworkUrl
        >> m_lastSyncDate;
}

Album::Album(const std::string& title )
    : m_id( 0 )
    , m_title( title )
    , m_releaseDate( 0 )
    , m_lastSyncDate( 0 )
{
}

unsigned int Album::id() const
{
    return m_id;
}

const std::string& Album::title() const
{
    return m_title;
}

time_t Album::releaseDate() const
{
    return m_releaseDate;
}

bool Album::setReleaseDate( time_t date )
{
    static const std::string& req = "UPDATE " + policy::AlbumTable::Name
            + " SET release_date = ? WHERE id_album = ?";
    if ( sqlite::Tools::executeUpdate( m_dbConnection, req, date, m_id ) == false )
        return false;
    m_releaseDate = date;
    return true;
}

const std::string& Album::shortSummary() const
{
    return m_shortSummary;
}

bool Album::setShortSummary( const std::string& summary )
{
    static const std::string& req = "UPDATE " + policy::AlbumTable::Name
            + " SET short_summary = ? WHERE id_album = ?";
    if ( sqlite::Tools::executeUpdate( m_dbConnection, req, summary, m_id ) == false )
        return false;
    m_shortSummary = summary;
    return true;
}

const std::string& Album::artworkUrl() const
{
    return m_artworkUrl;
}

bool Album::setArtworkUrl( const std::string& artworkUrl )
{
    static const std::string& req = "UPDATE " + policy::AlbumTable::Name
            + " SET artwork_url = ? WHERE id_album = ?";
    if ( sqlite::Tools::executeUpdate( m_dbConnection, req, artworkUrl, m_id ) == false )
        return false;
    m_artworkUrl = artworkUrl;
    return true;
}

time_t Album::lastSyncDate() const
{
    return m_lastSyncDate;
}

std::vector<MediaPtr> Album::tracks() const
{
    static const std::string req = "SELECT med.* FROM " + policy::MediaTable::Name + " med "
            " LEFT JOIN " + policy::AlbumTrackTable::Name + " att ON att.media_id = med.id_media "
            " WHERE att.album_id = ? ORDER BY att.track_number";
    return Media::fetchAll( m_dbConnection, req, m_id );
}

std::shared_ptr<AlbumTrack> Album::addTrack(std::shared_ptr<Media> media, unsigned int trackNb )
{
    auto track = AlbumTrack::create( m_dbConnection, m_id, media.get(), trackNb );
    media->setAlbumTrack( track );
    return track;
}

std::vector<ArtistPtr> Album::artists() const
{
    static const std::string req = "SELECT art.* FROM " + policy::ArtistTable::Name + " art "
            "LEFT JOIN AlbumArtistRelation aar ON aar.id_artist = art.id_artist "
            "WHERE aar.id_album = ?";
    return Artist::fetchAll( m_dbConnection, req, m_id );
}

bool Album::addArtist( std::shared_ptr<Artist> artist )
{
    static const std::string req = "INSERT INTO AlbumArtistRelation VALUES(?, ?)";
    if ( m_id == 0 || artist->id() == 0 )
    {
        LOG_ERROR("Both artist * album need to be inserted in database before being linked together" );
        return false;
    }
    return sqlite::Tools::executeRequest( m_dbConnection, req, m_id, artist->id() );
}

bool Album::createTable(DBConnection dbConnection )
{
    static const std::string req = "CREATE TABLE IF NOT EXISTS " +
            policy::AlbumTable::Name +
            "("
                "id_album INTEGER PRIMARY KEY AUTOINCREMENT,"
                "title TEXT UNIQUE ON CONFLICT FAIL,"
                "release_date UNSIGNED INTEGER,"
                "short_summary TEXT,"
                "artwork_url TEXT,"
                "UNSIGNED INTEGER last_sync_date"
            ")";
    static const std::string reqRel = "CREATE TABLE IF NOT EXISTS AlbumArtistRelation("
                "id_album INTEGER,"
                "id_artist INTEGER,"
                "PRIMARY KEY (id_album, id_artist),"
                "FOREIGN KEY(id_album) REFERENCES " + policy::AlbumTable::Name + "("
                    + policy::AlbumTable::CacheColumn + ") ON DELETE CASCADE,"
                "FOREIGN KEY(id_artist) REFERENCES " + policy::ArtistTable::Name + "("
                    + policy::ArtistTable::CacheColumn + ") ON DELETE CASCADE"
            ")";
    return sqlite::Tools::executeRequest( dbConnection, req ) &&
            sqlite::Tools::executeRequest( dbConnection, reqRel );
}

std::shared_ptr<Album> Album::create(DBConnection dbConnection, const std::string& title )
{
    auto album = std::make_shared<Album>( title );
    static const std::string req = "INSERT INTO " + policy::AlbumTable::Name +
            "(id_album, title) VALUES(NULL, ?)";
    if ( _Cache::insert( dbConnection, album, req, title ) == false )
        return nullptr;
    album->m_dbConnection = dbConnection;
    return album;
}
<|endoftext|>


<commit_before>/*
Dudu Faz Serviço
https://www.urionlinejudge.com.br/judge/pt/problems/view/1610
*/

#include <iostream>
#include <vector>
#include <list>

using namespace std;

bool checarCiclos(vector<list<int>> &adj);
bool checarCiclos(int origem, vector<list<int>> &adj, vector<bool> &visitado, vector<bool> &visitadoNoCaminho);

int main(void) {
    ios::sync_with_stdio(false);

    int T;

    cin >> T;
    while(T-- > 0) {
        int N, M;

        cin >> N >> M;

        vector<list<int>> adj(N);

        for (int i = 0; i < M; i++) {
            int A, B;

            cin >> A >> B;

            adj[A - 1].push_back(B - 1);
        }

        if (checarCiclos(adj)) {
            cout << "SIM\n";
        }
        else {
            cout << "NAO\n";
        }
    }

    return 0;
}

bool checarCiclos(vector<list<int>> &adj) {
    int N = adj.size();
    vector<bool> visitado(N);
    vector<bool> visitadoNoCaminho(N);

    for (int i = 0; i < N; i++) {
        if (checarCiclos(i, adj, visitado, visitadoNoCaminho)) return true;
    }

    return false;
}

bool checarCiclos(int origem, vector<list<int>> &adj, vector<bool> &visitado, vector<bool> &visitadoNoCaminho) {
    if (!visitado[origem]) {
        visitado[origem] = true;
        visitadoNoCaminho[origem] = true;

        for (auto destino : adj[origem]) {
            if (!visitado[destino] && checarCiclos(destino, adj, visitado, visitadoNoCaminho)) return true;
            else if (visitadoNoCaminho[destino]) return true;
        }

        visitadoNoCaminho[origem] = false;
    }

    return false;
}<commit_msg>URI Online Judge - 1610 - Dudu faz serviço<commit_after>/*
Dudu Faz Serviço
https://www.urionlinejudge.com.br/judge/pt/problems/view/1610
*/

#include <iostream>
#include <vector>
#include <list>

using namespace std;

bool checarCiclos(vector<list<int>> &adj);
bool checarCiclos(int origem, vector<list<int>> &adj, vector<bool> &visitado, vector<bool> &local);

int main(void) {
    ios::sync_with_stdio(false);

    int T;

    cin >> T;
    while(T-- > 0) {
        int N, M;

        cin >> N >> M;

        vector<list<int>> adj(N);

        for (int i = 0; i < M; i++) {
            int A, B;

            cin >> A >> B;

            adj[A - 1].push_back(B - 1);
        }

        if (checarCiclos(adj)) {
            cout << "SIM\n";
        }
        else {
            cout << "NAO\n";
        }
    }

    return 0;
}

bool checarCiclos(vector<list<int>> &adj) {
    int N = adj.size();
    vector<bool> visitado(N, false);
    vector<bool> local(N, false);

    for (int i = 0; i < N; i++) {
        if (checarCiclos(i, adj, visitado, local)) return true;
    }

    return false;
}

bool checarCiclos(int origem, vector<list<int>> &adj, vector<bool> &visitado, vector<bool> &local) {
    if (local[origem]) return true;
    if (visitado[origem]) return false;

    visitado[origem] = true;
    local[origem] = true;

    for (auto destinoIt = adj[origem].begin(); destinoIt != adj[origem].end(); ++destinoIt) {
        if (checarCiclos(*destinoIt, adj, visitado, local)) return true;
    }

    local[origem] = false;

    return false;
}<|endoftext|>


<commit_before>#include "acmacs-base/time-series.hh"
#include "acmacs-base/rjson-v3-helper.hh"
#include "acmacs-base/string-compare.hh"
#include "acmacs-map-draw/mapi-settings.hh"
#include "acmacs-map-draw/draw.hh"

// ----------------------------------------------------------------------

//  "?start": "2019-01", "?end": "2019-11",
//  "interval": {"month": 1}, "?": "month, week, year, day (interval: month also supported)",
//  "output": "/path/name-{ts-name}.pdf",
// "shown-on-all": <Select Antigens>, -- reference antigens and sera are shown on all maps, select here other antigens to show on all the maps
//  "report": true

bool acmacs::mapi::v1::Settings::apply_time_series()
{
    using namespace std::string_view_literals;

    auto ts_params = getenv("interval"sv).visit([]<typename Val>(const Val& val) -> acmacs::time_series::parameters {
        if constexpr (std::is_same_v<Val, rjson::v3::detail::object>) {
            for (const auto& interval_n : {"year"sv, "month"sv, "week"sv, "day"sv}) {
                if (const auto& num = val[interval_n]; !num.is_null())
                    return {interval_n, num.template to<date::period_diff_t>()};
            }
            AD_WARNING("unrecognized interval specification: {}, month assumed", val);
            return {"month"sv};
        }
        else if constexpr (std::is_same_v<Val, rjson::v3::detail::string>) {
            return {val.template to<std::string_view>()};
        }
        else {
            AD_WARNING("unrecognized interval specification: {}, month assumed", val);
            return {"month"sv};
        }
    });

    if (const auto& start = getenv("start"sv); !start.is_null())
        ts_params.first = date::from_string(start.to<std::string_view>(), date::allow_incomplete::yes, date::throw_on_error::yes);
    if (const auto& end = getenv("end"sv); !end.is_null())
        ts_params.after_last = date::from_string(end.to<std::string_view>(), date::allow_incomplete::yes, date::throw_on_error::yes);

    // const auto ts_stat = acmacs::time_series::stat(ts_params, tal().tree().all_dates());
    auto series = acmacs::time_series::make(ts_params);

    // rjson::v3::copy_if_not_null(getenv("report"sv), param.report);

    const auto& chart_access = chart_draw().chart(0); // can draw just the chart 0 // get_chart(getenv("chart"sv), 0);
    if (const auto filename_pattern = rjson::v3::read_string(getenv("output"sv, toplevel_only::no, throw_if_partial_substitution::no)); filename_pattern.has_value()) {
        auto filename{substitute_chart_metadata(*filename_pattern, chart_access)};
        if (!acmacs::string::endswith_ignore_case(filename, ".pdf"sv))
            filename = fmt::format("{}.pdf", filename);
        chart_draw().calculate_viewport();
        chart_draw().draw(filename, rjson::v3::read_number(getenv("width"sv), 800.0), report_time::no);
    }
    else
        AD_WARNING("Cannot make time series: no \"output\" in {}", getenv_toplevel());
    return true;

} // acmacs::mapi::v1::Settings::apply_time_series

// ----------------------------------------------------------------------

// ----------------------------------------------------------------------
/// Local Variables:
/// eval: (if (fboundp 'eu-rename-buffer) (eu-rename-buffer))
/// End:
<commit_msg>mapi: time series<commit_after>#include "acmacs-base/time-series.hh"
#include "acmacs-base/rjson-v3-helper.hh"
#include "acmacs-base/string-compare.hh"
#include "acmacs-map-draw/mapi-settings.hh"
#include "acmacs-map-draw/draw.hh"

// ----------------------------------------------------------------------

//  "?start": "2019-01", "?end": "2019-11",
//  "interval": {"month": 1}, "?": "month, week, year, day (interval: month also supported)",
//  "output": "/path/name-{ts-name}.pdf",
// "shown-on-all": <Select Antigens>, -- reference antigens and sera are shown on all maps, select here other antigens to show on all the maps
//  "report": true

bool acmacs::mapi::v1::Settings::apply_time_series()
{
    using namespace std::string_view_literals;

    auto ts_params = getenv("interval"sv).visit([]<typename Val>(const Val& val) -> acmacs::time_series::parameters {
        if constexpr (std::is_same_v<Val, rjson::v3::detail::object>) {
            for (const auto& interval_n : {"year"sv, "month"sv, "week"sv, "day"sv}) {
                if (const auto& num = val[interval_n]; !num.is_null())
                    return {interval_n, num.template to<date::period_diff_t>()};
            }
            AD_WARNING("unrecognized interval specification: {}, month assumed", val);
            return {"month"sv};
        }
        else if constexpr (std::is_same_v<Val, rjson::v3::detail::string>) {
            return {val.template to<std::string_view>()};
        }
        else {
            AD_WARNING("unrecognized interval specification: {}, month assumed", val);
            return {"month"sv};
        }
    });

    if (const auto& start = getenv("start"sv); !start.is_null())
        ts_params.first = date::from_string(start.to<std::string_view>(), date::allow_incomplete::yes, date::throw_on_error::yes);
    if (const auto& end = getenv("end"sv); !end.is_null())
        ts_params.after_last = date::from_string(end.to<std::string_view>(), date::allow_incomplete::yes, date::throw_on_error::yes);

    // const auto ts_stat = acmacs::time_series::stat(ts_params, tal().tree().all_dates());
    // const auto [first, after_last] = acmacs::time_series::suggest_start_end(ts_params, ts_stat);
    auto series = acmacs::time_series::make(ts_params);

    // if (!ts_stat.counter().empty())
    //     AD_INFO("time series full range {} .. {}", ts_stat.counter().begin()->first, ts_stat.counter().rbegin()->first);
    // AD_INFO("time series suggested  {} .. {}", first, after_last);
    AD_INFO("time series used       {} .. {}", ts_params.first, ts_params.after_last);
    if (rjson::v3::read_bool(getenv("report"sv), false)) {
        // AD_INFO("time series report:\n{}", ts_stat.report("    {value}  {counter:6d}\n"));
    }

    const auto& chart_access = chart_draw().chart(0); // can draw just the chart 0 // get_chart(getenv("chart"sv), 0);
    if (const auto filename_pattern = rjson::v3::read_string(getenv("output"sv, toplevel_only::no, throw_if_partial_substitution::no)); filename_pattern.has_value()) {
        auto filename{substitute_chart_metadata(*filename_pattern, chart_access)};
        if (!acmacs::string::endswith_ignore_case(filename, ".pdf"sv))
            filename = fmt::format("{}.pdf", filename);
        chart_draw().calculate_viewport();
        chart_draw().draw(filename, rjson::v3::read_number(getenv("width"sv), 800.0), report_time::no);
    }
    else
        AD_WARNING("Cannot make time series: no \"output\" in {}", getenv_toplevel());
    return true;

} // acmacs::mapi::v1::Settings::apply_time_series

// ----------------------------------------------------------------------

// ----------------------------------------------------------------------
/// Local Variables:
/// eval: (if (fboundp 'eu-rename-buffer) (eu-rename-buffer))
/// End:
<|endoftext|>


<commit_before>#pragma once

#include <agency/detail/config.hpp>
#include <agency/detail/unique_ptr.hpp>
#include <memory>

namespace agency
{
namespace detail
{

template<class T, class Alloc = std::allocator<T>>
class boxed_value
{
  public:
    using allocator_type = typename std::allocator_traits<Alloc>::template rebind_alloc<T>;
    using value_type = typename allocator_type::value_type;

    __AGENCY_ANNOTATION
    boxed_value()
      : boxed_value(value_type{})
    {}

    __AGENCY_ANNOTATION
    boxed_value(const boxed_value& other)
      : boxed_value(other.value())
    {}

    __AGENCY_ANNOTATION
    boxed_value(boxed_value&& other)
      : boxed_value(std::move(other.value()))
    {}

    template<class... Args,
             class = typename std::enable_if<
               std::is_constructible<T,Args&&...>::value
             >::type>
    __AGENCY_ANNOTATION
    explicit boxed_value(Args... args)
      : data_(agency::detail::allocate_unique<T>(allocator_type(), std::forward<Args>(args)...))
    {}

    __AGENCY_ANNOTATION
    value_type& value() &
    {
      return *data_;
    }

    __AGENCY_ANNOTATION
    const value_type& value() const &
    {
      return *data_;
    }

    __AGENCY_ANNOTATION
    value_type&& value() &&
    {
      return std::move(*data_);
    }

    __AGENCY_ANNOTATION
    const value_type&& value() const &&
    {
      return std::move(*data_);
    }

    template<class U,
             class = typename std::enable_if<
               std::is_assignable<value_type,U&&>::value
             >::type>
    __AGENCY_ANNOTATION
    boxed_value& operator=(U&& other)
    {
      value() = std::forward<U>(other);
      return *this;
    }

  private:
    agency::detail::unique_ptr<T,agency::detail::deleter<allocator_type>> data_;
};

// when the allocator is std::allocator<T>, we can just put this on the stack
template<class T, class OtherT>
class boxed_value<T,std::allocator<OtherT>>
{
  public:
    using allocator_type = std::allocator<T>;
    using value_type = typename allocator_type::value_type;

    __AGENCY_ANNOTATION
    boxed_value()
      : boxed_value(value_type{})
    {}

    __AGENCY_ANNOTATION
    boxed_value(const boxed_value& other)
      : boxed_value(other.value())
    {}

    __AGENCY_ANNOTATION
    boxed_value(boxed_value&& other)
      : boxed_value(std::move(other.value_))
    {}

    template<class... Args,
             class = typename std::enable_if<
               std::is_constructible<T,Args&&...>::value
             >::type>
    __AGENCY_ANNOTATION
    explicit boxed_value(Args&&... args)
      : value_(std::forward<Args>(args)...)
    {}

    __AGENCY_ANNOTATION
    value_type& value()
    {
      return value_;
    }

    __AGENCY_ANNOTATION
    const value_type& value() const
    {
      return value_;
    }

    template<class U,
             class = typename std::enable_if<
               std::is_assignable<value_type,U&&>::value
             >::type>
    __AGENCY_ANNOTATION
    boxed_value& operator=(U&& other)
    {
      value() = std::forward<U>(other);
      return *this;
    }

  private:
    value_type value_;
};

template<class T, class Alloc, class... Args>
__AGENCY_ANNOTATION
boxed_value<T,Alloc> allocate_boxed(const Alloc&, Args&&... args)
{
  return boxed_value<T,Alloc>(std::forward<Args>(args)...);
}

} // end detail
} // end agency

<commit_msg>Add assignment operators to boxed_value<commit_after>#pragma once

#include <agency/detail/config.hpp>
#include <agency/detail/unique_ptr.hpp>
#include <memory>

namespace agency
{
namespace detail
{

template<class T, class Alloc = std::allocator<T>>
class boxed_value
{
  public:
    using allocator_type = typename std::allocator_traits<Alloc>::template rebind_alloc<T>;
    using value_type = typename allocator_type::value_type;

    __AGENCY_ANNOTATION
    boxed_value()
      : boxed_value(value_type{})
    {}

    __AGENCY_ANNOTATION
    boxed_value(const boxed_value& other)
      : boxed_value(other.value())
    {}

    __AGENCY_ANNOTATION
    boxed_value(boxed_value&& other)
      : boxed_value(std::move(other.value()))
    {}

    template<class... Args,
             class = typename std::enable_if<
               std::is_constructible<T,Args&&...>::value
             >::type>
    __AGENCY_ANNOTATION
    explicit boxed_value(Args... args)
      : data_(agency::detail::allocate_unique<T>(allocator_type(), std::forward<Args>(args)...))
    {}

    __AGENCY_ANNOTATION
    boxed_value& operator=(const boxed_value& other)
    {
      value() = other.value();
      return *this;
    }

    __AGENCY_ANNOTATION
    boxed_value& operator=(boxed_value&& other)
    {
      value() = std::move(other.value());
      return *this;
    }

    __AGENCY_ANNOTATION
    value_type& value() &
    {
      return *data_;
    }

    __AGENCY_ANNOTATION
    const value_type& value() const &
    {
      return *data_;
    }

    __AGENCY_ANNOTATION
    value_type&& value() &&
    {
      return std::move(*data_);
    }

    __AGENCY_ANNOTATION
    const value_type&& value() const &&
    {
      return std::move(*data_);
    }

    template<class U,
             class = typename std::enable_if<
               std::is_assignable<value_type,U&&>::value
             >::type>
    __AGENCY_ANNOTATION
    boxed_value& operator=(U&& other)
    {
      value() = std::forward<U>(other);
      return *this;
    }

  private:
    agency::detail::unique_ptr<T,agency::detail::deleter<allocator_type>> data_;
};

// when the allocator is std::allocator<T>, we can just put this on the stack
template<class T, class OtherT>
class boxed_value<T,std::allocator<OtherT>>
{
  public:
    using allocator_type = std::allocator<T>;
    using value_type = typename allocator_type::value_type;

    __AGENCY_ANNOTATION
    boxed_value()
      : boxed_value(value_type{})
    {}

    __AGENCY_ANNOTATION
    boxed_value(const boxed_value& other)
      : boxed_value(other.value())
    {}

    __AGENCY_ANNOTATION
    boxed_value(boxed_value&& other)
      : boxed_value(std::move(other.value_))
    {}

    template<class... Args,
             class = typename std::enable_if<
               std::is_constructible<T,Args&&...>::value
             >::type>
    __AGENCY_ANNOTATION
    explicit boxed_value(Args&&... args)
      : value_(std::forward<Args>(args)...)
    {}

    __AGENCY_ANNOTATION
    value_type& value()
    {
      return value_;
    }

    __AGENCY_ANNOTATION
    const value_type& value() const
    {
      return value_;
    }

    template<class U,
             class = typename std::enable_if<
               std::is_assignable<value_type,U&&>::value
             >::type>
    __AGENCY_ANNOTATION
    boxed_value& operator=(U&& other)
    {
      value() = std::forward<U>(other);
      return *this;
    }

  private:
    value_type value_;
};

template<class T, class Alloc, class... Args>
__AGENCY_ANNOTATION
boxed_value<T,Alloc> allocate_boxed(const Alloc&, Args&&... args)
{
  return boxed_value<T,Alloc>(std::forward<Args>(args)...);
}

} // end detail
} // end agency

<|endoftext|>


<commit_before>/*=========================================================================

  Program:   Visualization Toolkit
  Module:    vtkJPEGWriter.cxx

  Copyright (c) Ken Martin, Will Schroeder, Bill Lorensen
  All rights reserved.
  See Copyright.txt or http://www.kitware.com/Copyright.htm for details.

     This software is distributed WITHOUT ANY WARRANTY; without even
     the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
     PURPOSE.  See the above copyright notice for more information.

=========================================================================*/
#include "vtkJPEGWriter.h"

#include "vtkErrorCode.h"
#include "vtkImageData.h"
#include "vtkObjectFactory.h"
#include "vtkUnsignedCharArray.h"

extern "C" {
#include <jpeglib.h>
#include <setjmp.h>
}

vtkCxxRevisionMacro(vtkJPEGWriter, "1.21");
vtkStandardNewMacro(vtkJPEGWriter);

vtkCxxSetObjectMacro(vtkJPEGWriter,Result,vtkUnsignedCharArray);

vtkJPEGWriter::vtkJPEGWriter()
{
  this->FileLowerLeft = 1;
  this->FileDimensionality = 2;

  this->Quality = 95;
  this->Progressive = 1;
  this->WriteToMemory = 0;
  this->Result = 0;
}

vtkJPEGWriter::~vtkJPEGWriter()
{
  if (this->Result)
    {
    this->Result->Delete();
    this->Result = 0;
    }
}

//----------------------------------------------------------------------------
// Writes all the data from the input.
void vtkJPEGWriter::Write()
{
  this->SetErrorCode(vtkErrorCode::NoError);

  // Error checking
  if ( this->GetInput() == NULL )
    {
    vtkErrorMacro(<<"Write:Please specify an input!");
    return;
    }
  if (!this->WriteToMemory && ! this->FileName && !this->FilePattern)
    {
    vtkErrorMacro(<<"Write:Please specify either a FileName or a file prefix and pattern");
    this->SetErrorCode(vtkErrorCode::NoFileNameError);
    return;
    }

  // Make sure the file name is allocated
  this->InternalFileName =
    new char[(this->FileName ? strlen(this->FileName) : 1) +
            (this->FilePrefix ? strlen(this->FilePrefix) : 1) +
            (this->FilePattern ? strlen(this->FilePattern) : 1) + 10];

  // Fill in image information.
  this->GetInput()->UpdateInformation();
  int *wExtent;
  wExtent = this->GetInput()->GetWholeExtent();
  this->FileNumber = this->GetInput()->GetWholeExtent()[4];
  this->MinimumFileNumber = this->MaximumFileNumber = this->FileNumber;
  this->FilesDeleted = 0;
  this->UpdateProgress(0.0);
  // loop over the z axis and write the slices
  for (this->FileNumber = wExtent[4]; this->FileNumber <= wExtent[5];
       ++this->FileNumber)
    {
    this->MaximumFileNumber = this->FileNumber;
    this->GetInput()->SetUpdateExtent(wExtent[0], wExtent[1],
                                      wExtent[2], wExtent[3],
                                      this->FileNumber,
                                      this->FileNumber);
    // determine the name
    if (this->FileName)
      {
      sprintf(this->InternalFileName,"%s",this->FileName);
      }
    else
      {
      if (this->FilePrefix)
        {
        sprintf(this->InternalFileName, this->FilePattern,
                this->FilePrefix, this->FileNumber);
        }
      else
        {
        sprintf(this->InternalFileName, this->FilePattern,this->FileNumber);
        }
      }
    this->GetInput()->UpdateData();
    this->WriteSlice(this->GetInput());
    if (this->ErrorCode == vtkErrorCode::OutOfDiskSpaceError)
      {
      vtkErrorMacro("Ran out of disk space; deleting file(s) already written");
      this->DeleteFiles();
      return;
      }
    this->UpdateProgress((this->FileNumber - wExtent[4])/
                         (wExtent[5] - wExtent[4] + 1.0));
    }
  delete [] this->InternalFileName;
  this->InternalFileName = NULL;
}

// these three routines are for wqriting into memory
extern "C"
{
  void vtkJPEGWriteToMemoryInit(j_compress_ptr cinfo)
  {
    vtkJPEGWriter *self = vtkJPEGWriter::SafeDownCast(
      static_cast<vtkObject *>(cinfo->client_data));
    if (self)
      {
      vtkUnsignedCharArray *uc = self->GetResult();
      if (!uc || uc->GetReferenceCount() > 1)
        {
        uc = vtkUnsignedCharArray::New();
        self->SetResult(uc);
        uc->Delete();
        // start out with 10K as a guess for the image size
        uc->Allocate(10000);
        }
      cinfo->dest->next_output_byte = uc->GetPointer(0);
      cinfo->dest->free_in_buffer = uc->GetSize();
      }
  }
}

extern "C"
{
  boolean vtkJPEGWriteToMemoryEmpty(j_compress_ptr cinfo)
  {
    vtkJPEGWriter *self = vtkJPEGWriter::SafeDownCast(
      static_cast<vtkObject *>(cinfo->client_data));
    if (self)
      {
      vtkUnsignedCharArray *uc = self->GetResult();
      // we must grow the array, we grow by 50% each time
      int oldSize = uc->GetSize();
      uc->Resize(oldSize + oldSize/2);
      cinfo->dest->next_output_byte = uc->GetPointer(oldSize);
      cinfo->dest->free_in_buffer = oldSize/2;
      }
    return TRUE;
  }
}

extern "C"
{
  void vtkJPEGWriteToMemoryTerm(j_compress_ptr cinfo)
  {
    vtkJPEGWriter *self = vtkJPEGWriter::SafeDownCast(
      static_cast<vtkObject *>(cinfo->client_data));
    if (self)
      {
      vtkUnsignedCharArray *uc = self->GetResult();
      // we must close the array
      vtkIdType oldSize = uc->GetSize();
      uc->SetNumberOfTuples(oldSize - static_cast<vtkIdType>(cinfo->dest->free_in_buffer));
      }
  }
}

struct VTK_JPEG_ERROR_MANAGER
{
  struct jpeg_error_mgr pub;
  jmp_buf setjmp_buffer;
};

typedef struct VTK_JPEG_ERROR_MANAGER* VTK_JPEG_ERROR_PTR;

extern "C"
{
  void
  VTK_JPEG_ERROR_EXIT (j_common_ptr cinfo)
{
  VTK_JPEG_ERROR_PTR jpegErr = (VTK_JPEG_ERROR_PTR) cinfo->err;
  longjmp(jpegErr->setjmp_buffer, 1);
}
}

// we disable this warning because even though this is a C++ file, between
// the setjmp and resulting longjmp there should not be any C++ constructors
// or destructors.
#if defined(_MSC_VER) && !defined(VTK_DISPLAY_WIN32_WARNINGS)
#pragma warning ( disable : 4611 )
#endif
void vtkJPEGWriter::WriteSlice(vtkImageData *data)
{
  // Call the correct templated function for the output
  void *outPtr;
  unsigned int ui;

  int* uext = data->GetUpdateExtent();

  // Call the correct templated function for the input
  outPtr = data->GetScalarPointer(uext[0], uext[2], uext[4]);
  if (data->GetScalarType() != VTK_UNSIGNED_CHAR)
    {
    vtkWarningMacro("JPEGWriter only supports unsigned char input");
    return;
    }

  if (data->GetNumberOfScalarComponents() > MAX_COMPONENTS)
    {
    vtkErrorMacro("Exceed JPEG limits for number of components (" << data->GetNumberOfScalarComponents() << " > " << MAX_COMPONENTS << ")" );
    return;
    }

  // overriding jpeg_error_mgr so we don't exit when an error happens

  // Create the jpeg compression object and error handler
  struct jpeg_compress_struct cinfo;
  struct VTK_JPEG_ERROR_MANAGER jerr;
  FILE *fp = 0;

  cinfo.err = jpeg_std_error(&jerr.pub);
  jerr.pub.error_exit = VTK_JPEG_ERROR_EXIT;
  if (setjmp(jerr.setjmp_buffer))
    {
    jpeg_destroy_compress(&cinfo);
    if (!this->WriteToMemory)
      {
      fclose(fp);
      }
    this->SetErrorCode(vtkErrorCode::OutOfDiskSpaceError);
    return;
    }

  jpeg_create_compress(&cinfo);

  // set the destination file
  struct jpeg_destination_mgr compressionDestination;
  if (this->WriteToMemory)
    {
    // setup the compress structure to write to memory
    compressionDestination.init_destination = vtkJPEGWriteToMemoryInit;
    compressionDestination.empty_output_buffer = vtkJPEGWriteToMemoryEmpty;
    compressionDestination.term_destination = vtkJPEGWriteToMemoryTerm;
    cinfo.dest = &compressionDestination;
    cinfo.client_data = static_cast<void *>(this);
    }
  else
    {
    fp = fopen(this->InternalFileName, "wb");
    if (!fp)
      {
      vtkErrorMacro("Unable to open file " << this->InternalFileName);
      this->SetErrorCode(vtkErrorCode::CannotOpenFileError);
      return;
      }
    jpeg_stdio_dest(&cinfo, fp);
    }

  // set the information about image
  int *uExtent = data->GetUpdateExtent();
  unsigned int width, height;
  width = uExtent[1] - uExtent[0] + 1;
  height = uExtent[3] - uExtent[2] + 1;

  cinfo.image_width = width;    /* image width and height, in pixels */
  cinfo.image_height = height;

  cinfo.input_components = data->GetNumberOfScalarComponents();
  switch (cinfo.input_components)
    {
    case 1: cinfo.in_color_space = JCS_GRAYSCALE;
      break;
    case 3: cinfo.in_color_space = JCS_RGB;
      break;
    default: cinfo.in_color_space = JCS_UNKNOWN;
      break;
    }

  // set the compression parameters
  jpeg_set_defaults(&cinfo);         // start with reasonable defaults
  jpeg_set_quality(&cinfo, this->Quality, TRUE);
  if (this->Progressive)
    {
    jpeg_simple_progression(&cinfo);
    }

  // start compression
  jpeg_start_compress(&cinfo, TRUE);

  // write the data. in jpeg, the first row is the top row of the image
  JSAMPROW *row_pointers = new JSAMPROW [height];
  int *outInc = data->GetIncrements();
  int rowInc = outInc[1];
  for (ui = 0; ui < height; ui++)
    {
    row_pointers[height - ui - 1] = (JSAMPROW) outPtr;
    outPtr = (unsigned char *)outPtr + rowInc;
    }
  jpeg_write_scanlines(&cinfo, row_pointers, height);

  if (!this->WriteToMemory)
    {
    if (fflush(fp) == EOF)
      {
      this->ErrorCode = vtkErrorCode::OutOfDiskSpaceError;
      fclose(fp);
      return;
      }
    }

  // finish the compression
  jpeg_finish_compress(&cinfo);

  // clean up and close the file
  delete [] row_pointers;
  jpeg_destroy_compress(&cinfo);

  if (!this->WriteToMemory)
    {
    fclose(fp);
    }
}

void vtkJPEGWriter::PrintSelf(ostream& os, vtkIndent indent)
{
  this->Superclass::PrintSelf(os,indent);

  os << indent << "Quality: " << this->Quality << "\n";
  os << indent << "Progressive: " << (this->Progressive ? "On" : "Off") << "\n";
  os << indent << "Result: " << this->Result << "\n";
  os << indent << "WriteToMemory: " << (this->WriteToMemory ? "On" : "Off") << "\n";
}
<commit_msg>fix for warnings and other bad things<commit_after>/*=========================================================================

  Program:   Visualization Toolkit
  Module:    vtkJPEGWriter.cxx

  Copyright (c) Ken Martin, Will Schroeder, Bill Lorensen
  All rights reserved.
  See Copyright.txt or http://www.kitware.com/Copyright.htm for details.

     This software is distributed WITHOUT ANY WARRANTY; without even
     the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
     PURPOSE.  See the above copyright notice for more information.

=========================================================================*/
#include "vtkJPEGWriter.h"

#include "vtkErrorCode.h"
#include "vtkImageData.h"
#include "vtkObjectFactory.h"
#include "vtkUnsignedCharArray.h"

extern "C" {
#include <jpeglib.h>
#include <setjmp.h>
}

vtkCxxRevisionMacro(vtkJPEGWriter, "1.22");
vtkStandardNewMacro(vtkJPEGWriter);

vtkCxxSetObjectMacro(vtkJPEGWriter,Result,vtkUnsignedCharArray);

vtkJPEGWriter::vtkJPEGWriter()
{
  this->FileLowerLeft = 1;
  this->FileDimensionality = 2;

  this->Quality = 95;
  this->Progressive = 1;
  this->WriteToMemory = 0;
  this->Result = 0;
}

vtkJPEGWriter::~vtkJPEGWriter()
{
  if (this->Result)
    {
    this->Result->Delete();
    this->Result = 0;
    }
}

//----------------------------------------------------------------------------
// Writes all the data from the input.
void vtkJPEGWriter::Write()
{
  this->SetErrorCode(vtkErrorCode::NoError);

  // Error checking
  if ( this->GetInput() == NULL )
    {
    vtkErrorMacro(<<"Write:Please specify an input!");
    return;
    }
  if (!this->WriteToMemory && ! this->FileName && !this->FilePattern)
    {
    vtkErrorMacro(<<"Write:Please specify either a FileName or a file prefix and pattern");
    this->SetErrorCode(vtkErrorCode::NoFileNameError);
    return;
    }

  // Make sure the file name is allocated
  this->InternalFileName =
    new char[(this->FileName ? strlen(this->FileName) : 1) +
            (this->FilePrefix ? strlen(this->FilePrefix) : 1) +
            (this->FilePattern ? strlen(this->FilePattern) : 1) + 10];

  // Fill in image information.
  this->GetInput()->UpdateInformation();
  int *wExtent;
  wExtent = this->GetInput()->GetWholeExtent();
  this->FileNumber = this->GetInput()->GetWholeExtent()[4];
  this->MinimumFileNumber = this->MaximumFileNumber = this->FileNumber;
  this->FilesDeleted = 0;
  this->UpdateProgress(0.0);
  // loop over the z axis and write the slices
  for (this->FileNumber = wExtent[4]; this->FileNumber <= wExtent[5];
       ++this->FileNumber)
    {
    this->MaximumFileNumber = this->FileNumber;
    this->GetInput()->SetUpdateExtent(wExtent[0], wExtent[1],
                                      wExtent[2], wExtent[3],
                                      this->FileNumber,
                                      this->FileNumber);
    // determine the name
    if (this->FileName)
      {
      sprintf(this->InternalFileName,"%s",this->FileName);
      }
    else
      {
      if (this->FilePrefix)
        {
        sprintf(this->InternalFileName, this->FilePattern,
                this->FilePrefix, this->FileNumber);
        }
      else
        {
        sprintf(this->InternalFileName, this->FilePattern,this->FileNumber);
        }
      }
    this->GetInput()->UpdateData();
    this->WriteSlice(this->GetInput());
    if (this->ErrorCode == vtkErrorCode::OutOfDiskSpaceError)
      {
      vtkErrorMacro("Ran out of disk space; deleting file(s) already written");
      this->DeleteFiles();
      return;
      }
    this->UpdateProgress((this->FileNumber - wExtent[4])/
                         (wExtent[5] - wExtent[4] + 1.0));
    }
  delete [] this->InternalFileName;
  this->InternalFileName = NULL;
}

// these three routines are for wqriting into memory
extern "C"
{
  void vtkJPEGWriteToMemoryInit(j_compress_ptr cinfo)
  {
    vtkJPEGWriter *self = vtkJPEGWriter::SafeDownCast(
      static_cast<vtkObject *>(cinfo->client_data));
    if (self)
      {
      vtkUnsignedCharArray *uc = self->GetResult();
      if (!uc || uc->GetReferenceCount() > 1)
        {
        uc = vtkUnsignedCharArray::New();
        self->SetResult(uc);
        uc->Delete();
        // start out with 10K as a guess for the image size
        uc->Allocate(10000);
        }
      cinfo->dest->next_output_byte = uc->GetPointer(0);
      cinfo->dest->free_in_buffer = uc->GetSize();
      }
  }
}

extern "C"
{
  boolean vtkJPEGWriteToMemoryEmpty(j_compress_ptr cinfo)
  {
    vtkJPEGWriter *self = vtkJPEGWriter::SafeDownCast(
      static_cast<vtkObject *>(cinfo->client_data));
    if (self)
      {
      vtkUnsignedCharArray *uc = self->GetResult();
      // we must grow the array, we grow by 50% each time
      int oldSize = uc->GetSize();
      uc->Resize(oldSize + oldSize/2);
      cinfo->dest->next_output_byte = uc->GetPointer(oldSize);
      cinfo->dest->free_in_buffer = oldSize/2;
      }
    return TRUE;
  }
}

extern "C"
{
  void vtkJPEGWriteToMemoryTerm(j_compress_ptr cinfo)
  {
    vtkJPEGWriter *self = vtkJPEGWriter::SafeDownCast(
      static_cast<vtkObject *>(cinfo->client_data));
    if (self)
      {
      vtkUnsignedCharArray *uc = self->GetResult();
      // we must close the array
      vtkIdType oldSize = uc->GetSize();
      uc->SetNumberOfTuples(oldSize - static_cast<vtkIdType>(cinfo->dest->free_in_buffer));
      }
  }
}

struct VTK_JPEG_ERROR_MANAGER
{
  struct jpeg_error_mgr pub;
  jmp_buf setjmp_buffer;
};

typedef struct VTK_JPEG_ERROR_MANAGER* VTK_JPEG_ERROR_PTR;

extern "C"
{
  void
  VTK_JPEG_ERROR_EXIT (j_common_ptr cinfo)
{
  VTK_JPEG_ERROR_PTR jpegErr = (VTK_JPEG_ERROR_PTR) cinfo->err;
  longjmp(jpegErr->setjmp_buffer, 1);
}
}

// we disable this warning because even though this is a C++ file, between
// the setjmp and resulting longjmp there should not be any C++ constructors
// or destructors.
#if defined(_MSC_VER) && !defined(VTK_DISPLAY_WIN32_WARNINGS)
#pragma warning ( disable : 4611 )
#endif
void vtkJPEGWriter::WriteSlice(vtkImageData *data)
{
  // Call the correct templated function for the output
  unsigned int ui;

  // Call the correct templated function for the input
  if (data->GetScalarType() != VTK_UNSIGNED_CHAR)
    {
    vtkWarningMacro("JPEGWriter only supports unsigned char input");
    return;
    }

  if (data->GetNumberOfScalarComponents() > MAX_COMPONENTS)
    {
    vtkErrorMacro("Exceed JPEG limits for number of components (" << data->GetNumberOfScalarComponents() << " > " << MAX_COMPONENTS << ")" );
    return;
    }

  // overriding jpeg_error_mgr so we don't exit when an error happens

  // Create the jpeg compression object and error handler
  struct jpeg_compress_struct cinfo;
  struct VTK_JPEG_ERROR_MANAGER jerr;
  FILE *fp = 0;
  if (!this->WriteToMemory)
    {
    fp = fopen(this->InternalFileName, "wb");
    if (!fp)
      {
      vtkErrorMacro("Unable to open file " << this->InternalFileName);
      this->SetErrorCode(vtkErrorCode::CannotOpenFileError);
      return;
      }
    }

  cinfo.err = jpeg_std_error(&jerr.pub);
  jerr.pub.error_exit = VTK_JPEG_ERROR_EXIT;
  if (setjmp(jerr.setjmp_buffer))
    {
    jpeg_destroy_compress(&cinfo);
    if (!this->WriteToMemory)
      {
      fclose(fp);
      }
    this->SetErrorCode(vtkErrorCode::OutOfDiskSpaceError);
    return;
    }

  jpeg_create_compress(&cinfo);

  // set the destination file
  struct jpeg_destination_mgr compressionDestination;
  if (this->WriteToMemory)
    {
    // setup the compress structure to write to memory
    compressionDestination.init_destination = vtkJPEGWriteToMemoryInit;
    compressionDestination.empty_output_buffer = vtkJPEGWriteToMemoryEmpty;
    compressionDestination.term_destination = vtkJPEGWriteToMemoryTerm;
    cinfo.dest = &compressionDestination;
    cinfo.client_data = static_cast<void *>(this);
    }
  else
    {
    jpeg_stdio_dest(&cinfo, fp);
    }

  // set the information about image
  int *uExtent = data->GetUpdateExtent();
  unsigned int width, height;
  width = uExtent[1] - uExtent[0] + 1;
  height = uExtent[3] - uExtent[2] + 1;

  cinfo.image_width = width;    /* image width and height, in pixels */
  cinfo.image_height = height;

  cinfo.input_components = data->GetNumberOfScalarComponents();
  switch (cinfo.input_components)
    {
    case 1: cinfo.in_color_space = JCS_GRAYSCALE;
      break;
    case 3: cinfo.in_color_space = JCS_RGB;
      break;
    default: cinfo.in_color_space = JCS_UNKNOWN;
      break;
    }

  // set the compression parameters
  jpeg_set_defaults(&cinfo);         // start with reasonable defaults
  jpeg_set_quality(&cinfo, this->Quality, TRUE);
  if (this->Progressive)
    {
    jpeg_simple_progression(&cinfo);
    }

  // start compression
  jpeg_start_compress(&cinfo, TRUE);

  // write the data. in jpeg, the first row is the top row of the image
  void *outPtr;
  outPtr = data->GetScalarPointer(uExtent[0], uExtent[2], uExtent[4]);
  JSAMPROW *row_pointers = new JSAMPROW [height];
  int *outInc = data->GetIncrements();
  int rowInc = outInc[1];
  for (ui = 0; ui < height; ui++)
    {
    row_pointers[height - ui - 1] = (JSAMPROW) outPtr;
    outPtr = (unsigned char *)outPtr + rowInc;
    }
  jpeg_write_scanlines(&cinfo, row_pointers, height);

  if (!this->WriteToMemory)
    {
    if (fflush(fp) == EOF)
      {
      this->ErrorCode = vtkErrorCode::OutOfDiskSpaceError;
      fclose(fp);
      return;
      }
    }

  // finish the compression
  jpeg_finish_compress(&cinfo);

  // clean up and close the file
  delete [] row_pointers;
  jpeg_destroy_compress(&cinfo);

  if (!this->WriteToMemory)
    {
    fclose(fp);
    }
}

void vtkJPEGWriter::PrintSelf(ostream& os, vtkIndent indent)
{
  this->Superclass::PrintSelf(os,indent);

  os << indent << "Quality: " << this->Quality << "\n";
  os << indent << "Progressive: " << (this->Progressive ? "On" : "Off") << "\n";
  os << indent << "Result: " << this->Result << "\n";
  os << indent << "WriteToMemory: " << (this->WriteToMemory ? "On" : "Off") << "\n";
}
<|endoftext|>


<commit_before>#include "ImageThresholder.h"
#include <chrono>
#include <thread>

#define EDSIZE 24
#define ERODESIZE 10

//#define IMAGETHRESHOLDER_PARALLEL_FOR
#define IMAGETHRESHOLDER_PARALLEL_THREADS

#ifdef IMAGETHRESHOLDER_PARALLEL_FOR
#include <ppl.h>
#endif

ImageThresholder::ImageThresholder(ThresholdedImages &images, HSVColorRangeMap &objectMap) : ThreadedClass("ImageThresholder"), thresholdedImages(images), objectMap(objectMap)
{
	stop_thread = false;
	running = false;
	m_iWorkersInProgress = 0;

#if defined(IMAGETHRESHOLDER_PARALLEL_THREADS)
	for (auto objectRange : objectMap) {
		auto object = objectRange.first;
		//threads.create_thread(boost::bind(&ImageThresholder::Run2, this, objectRange.first));
		threads.add_thread(new boost::thread(&ImageThresholder::Run2, this, objectRange.first));

	}
#endif

	elemDilate = cv::getStructuringElement(cv::MORPH_RECT, cv::Size(EDSIZE, EDSIZE)); //millega hiljem erode ja dilatet teha
	elemErode = cv::getStructuringElement(cv::MORPH_RECT, cv::Size(EDSIZE + 6, EDSIZE + 6));
	elemErode2 = cv::getStructuringElement(cv::MORPH_RECT, cv::Size(ERODESIZE, ERODESIZE));

};

ImageThresholder::~ImageThresholder(){
	WaitForStop();
};

void ImageThresholder::Start(cv::Mat &frameHSV, std::vector<OBJECT> objectList) {
#if defined(IMAGETHRESHOLDER_PARALLEL_FOR)
		concurrency::parallel_for_each(begin(objectList), end(objectList), [&frameHSV, this](OBJECT object) {
			auto r = objectMap[object];
			inRange(frameHSV, cv::Scalar(r.hue.low, r.sat.low, r.val.low), cv::Scalar(r.hue.high, r.sat.high, r.val.high), thresholdedImages[object]);
		});
#elif defined(IMAGETHRESHOLDER_PARALLEL_THREADS)
	if (m_iWorkersInProgress > 0) {
		std::cout << "Still working" << std::endl;
	}
	frame = frameHSV;
	int mask = 0;
	for (auto &object : objectList) {
		//std::cout << "mask " << (1 << object) << " " <<( mask | (1 << object)) << std::endl;
		mask = mask | (1 << object);
	}
	m_iWorkersInProgress = mask;

	while (m_iWorkersInProgress > 0) {
		std::this_thread::sleep_for(std::chrono::milliseconds(1)); // limit fps to about 50fps
	}
	/*
		for (auto &object : objectList) {
			threads.create_thread([&frameHSV, object, this]{
				auto r = objectMap[object];
				do {
					inRange(frameHSV, cv::Scalar(r.hue.low, r.sat.low, r.val.low), cv::Scalar(r.hue.high, r.sat.high, r.val.high), thresholdedImages[object]);
				} while (thresholdedImages[object].size().height == 0);
			});
		}
	*/
#else
		for (auto &object : objectList) {
			auto r = objectMap[object];
			inRange(frameHSV, cv::Scalar(r.hue.low, r.sat.low, r.val.low), cv::Scalar(r.hue.high, r.sat.high, r.val.high), thresholdedImages[object]);
		}
#endif
		/*
		if (object == BLUE_GATE || object == YELLOW_GATE) {
		cv::erode(thresholdedImages[object],thresholdedImages[object],elemErode2);
		}
		cv::dilate(thresholdedImages[object],thresholdedImages[object],elemErode2);

		*/
	}

void  ImageThresholder::Run2(OBJECT object){
	while (!stop_thread) {
		if (m_iWorkersInProgress & (1 << object)) {
			auto r = objectMap[object];
			inRange(frame, cv::Scalar(r.hue.low, r.sat.low, r.val.low), cv::Scalar(r.hue.high, r.sat.high, r.val.high), thresholdedImages[object]);
			m_iWorkersInProgress &= ~(1 << object);
		}
		else {
			std::this_thread::sleep_for(std::chrono::milliseconds(1));
		}
	}
};

<commit_msg>placeholder for code<commit_after>#include "ImageThresholder.h"
#include <chrono>
#include <thread>

#define EDSIZE 24
#define ERODESIZE 10

//#define IMAGETHRESHOLDER_PARALLEL_FOR
//#define IMAGETHRESHOLDER_PARALLEL_THREADS
#define IMAGETHRESHOLDER_PARALLEL_INRANGE

#ifdef IMAGETHRESHOLDER_PARALLEL_FOR
#include <ppl.h>
#endif

ImageThresholder::ImageThresholder(ThresholdedImages &images, HSVColorRangeMap &objectMap) : ThreadedClass("ImageThresholder"), thresholdedImages(images), objectMap(objectMap)
{
	stop_thread = false;
	running = false;
	m_iWorkersInProgress = 0;

#if defined(IMAGETHRESHOLDER_PARALLEL_THREADS)
	for (auto objectRange : objectMap) {
		auto object = objectRange.first;
		//threads.create_thread(boost::bind(&ImageThresholder::Run2, this, objectRange.first));
		threads.add_thread(new boost::thread(&ImageThresholder::Run2, this, objectRange.first));

	}
#endif

	elemDilate = cv::getStructuringElement(cv::MORPH_RECT, cv::Size(EDSIZE, EDSIZE)); //millega hiljem erode ja dilatet teha
	elemErode = cv::getStructuringElement(cv::MORPH_RECT, cv::Size(EDSIZE + 6, EDSIZE + 6));
	elemErode2 = cv::getStructuringElement(cv::MORPH_RECT, cv::Size(ERODESIZE, ERODESIZE));

};

ImageThresholder::~ImageThresholder(){
	WaitForStop();
};

void ImageThresholder::Start(cv::Mat &frameHSV, std::vector<OBJECT> objectList) {
#if defined(IMAGETHRESHOLDER_PARALLEL_FOR)
		concurrency::parallel_for_each(begin(objectList), end(objectList), [&frameHSV, this](OBJECT object) {
			auto r = objectMap[object];
			inRange(frameHSV, cv::Scalar(r.hue.low, r.sat.low, r.val.low), cv::Scalar(r.hue.high, r.sat.high, r.val.high), thresholdedImages[object]);
		});
#elif defined(IMAGETHRESHOLDER_PARALLEL_THREADS)
	if (m_iWorkersInProgress > 0) {
		std::cout << "Still working" << std::endl;
	}
	frame = frameHSV;
	int mask = 0;
	for (auto &object : objectList) {
		//std::cout << "mask " << (1 << object) << " " <<( mask | (1 << object)) << std::endl;
		mask = mask | (1 << object);
	}
	m_iWorkersInProgress = mask;

	while (m_iWorkersInProgress > 0) {
		std::this_thread::sleep_for(std::chrono::milliseconds(1)); // limit fps to about 50fps
	}
	/*
		for (auto &object : objectList) {
			threads.create_thread([&frameHSV, object, this]{
				auto r = objectMap[object];
				do {
					inRange(frameHSV, cv::Scalar(r.hue.low, r.sat.low, r.val.low), cv::Scalar(r.hue.high, r.sat.high, r.val.high), thresholdedImages[object]);
				} while (thresholdedImages[object].size().height == 0);
			});
		}
	*/
#elif defined(IMAGETHRESHOLDER_PARALLEL_INRANGE)
	#error add code here
#else
		for (auto &object : objectList) {
			auto r = objectMap[object];
			inRange(frameHSV, cv::Scalar(r.hue.low, r.sat.low, r.val.low), cv::Scalar(r.hue.high, r.sat.high, r.val.high), thresholdedImages[object]);
		}
#endif
		/*
		if (object == BLUE_GATE || object == YELLOW_GATE) {
		cv::erode(thresholdedImages[object],thresholdedImages[object],elemErode2);
		}
		cv::dilate(thresholdedImages[object],thresholdedImages[object],elemErode2);

		*/
	}

void  ImageThresholder::Run2(OBJECT object){
	while (!stop_thread) {
		if (m_iWorkersInProgress & (1 << object)) {
			auto r = objectMap[object];
			inRange(frame, cv::Scalar(r.hue.low, r.sat.low, r.val.low), cv::Scalar(r.hue.high, r.sat.high, r.val.high), thresholdedImages[object]);
			m_iWorkersInProgress &= ~(1 << object);
		}
		else {
			std::this_thread::sleep_for(std::chrono::milliseconds(1));
		}
	}
};

<|endoftext|>


<commit_before>#include "hornet/java.hh"

#include "hornet/translator.hh"
#include "hornet/vm.hh"

#include <cassert>

#include <classfile_constants.h>
#include <jni.h>

#include "llvm/ExecutionEngine/ExecutionEngine.h"
#include "llvm/Support/TargetSelect.h"
#include "llvm/ExecutionEngine/JIT.h"
#include "llvm/Analysis/Verifier.h"
#include "llvm/IR/IRBuilder.h"
#include "llvm/IR/Module.h"

using namespace std;

namespace hornet {

using namespace llvm;

Module*          module;
ExecutionEngine* engine;

Type* typeof(type t)
{
    switch (t) {
    case type::t_int: return Type::getInt32Ty(getGlobalContext());
    default:          assert(0);
    }
}

Instruction::BinaryOps to_binary_op(binop op)
{
    switch (op) {
    case binop::op_add: return Instruction::BinaryOps::Add;
    default:            assert(0);
    }
}

class llvm_translator : public translator {
public:
    llvm_translator(method* method);
    ~llvm_translator();

    template<typename T>
    T trampoline();

    virtual void prologue () override;
    virtual void op_const (type t, int64_t value) override;
    virtual void op_load  (type t, uint16_t idx) override;
    virtual void op_store (type t, uint16_t idx) override;
    virtual void op_binary(type t, binop op) override;
    virtual void op_returnvoid() override;

private:
    AllocaInst* lookup_local(unsigned int idx, Type* type);

    std::stack<Value*> _mimic_stack;
    std::vector<AllocaInst*> _locals;
    IRBuilder<> _builder;
    Function* _func;
    method* _method;
};

FunctionType* function_type(IRBuilder<>& builder, method* method)
{
    return FunctionType::get(builder.getVoidTy(), false);
}

Function* function(IRBuilder<>& builder, method* method)
{
    auto func_type = function_type(builder, method);
    auto func = Function::Create(func_type, Function::ExternalLinkage, method->name, module);
    auto entry = BasicBlock::Create(builder.getContext(), "entry", func);
    builder.SetInsertPoint(entry);
    return func;
}

llvm_translator::llvm_translator(method* method)
    : translator(method)
    , _locals(method->max_locals)
    , _builder(module->getContext())
    , _method(method)
{
    _func = function(_builder, _method);
}

llvm_translator::~llvm_translator()
{
}

template<typename T> T llvm_translator::trampoline()
{
    verifyFunction(*_func, PrintMessageAction);
    return reinterpret_cast<T>(engine->getPointerToFunction(_func));
}

AllocaInst* llvm_translator::lookup_local(unsigned int idx, Type* type)
{
    if (_locals[idx]) {
        return _locals[idx];
    }
    IRBuilder<> builder(&_func->getEntryBlock(), _func->getEntryBlock().begin());
    auto ret = builder.CreateAlloca(type, nullptr, "");
    _locals[idx] = ret;
    return ret;
}

void llvm_translator::prologue()
{
}

void llvm_translator::op_const(type t, int64_t value)
{
    auto c = ConstantInt::get(typeof(t), value, 0);

    _mimic_stack.push(c);
}

void llvm_translator::op_load(type t, uint16_t idx)
{
    auto value = _builder.CreateLoad(_locals[idx]);

    _mimic_stack.push(value);
}

void llvm_translator::op_store(type t, uint16_t idx)
{
    auto value = _mimic_stack.top();
    _mimic_stack.pop();
    auto local = lookup_local(idx, typeof(t));
    _builder.CreateStore(value, local);
}

void llvm_translator::op_binary(type t, binop op)
{
    auto value2 = _mimic_stack.top();
    _mimic_stack.pop();
    auto value1 = _mimic_stack.top();
    _mimic_stack.pop();
    auto result = _builder.CreateBinOp(to_binary_op(op), value1, value2);
    _mimic_stack.push(result);
}

void llvm_translator::op_returnvoid()
{
    _builder.CreateRetVoid();
}

llvm_backend::llvm_backend()
{
    InitializeNativeTarget();
    module = new Module("JIT", getGlobalContext());
    auto engine_builder = EngineBuilder(module);
    std::string error_str;
    engine_builder.setErrorStr(&error_str);
    engine = engine_builder.create();
    if (!engine) {
        throw std::runtime_error(error_str);
    }
}

llvm_backend::~llvm_backend()
{
    delete engine;
}

value_t llvm_backend::execute(method* method, frame& frame)
{
    llvm_translator translator(method);

    translator.translate();

    auto fp = translator.trampoline<value_t (*)()>();

    return fp();
}

}
<commit_msg>llvm: Integer arithmetic<commit_after>#include "hornet/java.hh"

#include "hornet/translator.hh"
#include "hornet/vm.hh"

#include <cassert>

#include <classfile_constants.h>
#include <jni.h>

#include "llvm/ExecutionEngine/ExecutionEngine.h"
#include "llvm/Support/TargetSelect.h"
#include "llvm/ExecutionEngine/JIT.h"
#include "llvm/Analysis/Verifier.h"
#include "llvm/IR/IRBuilder.h"
#include "llvm/IR/Module.h"

using namespace std;

namespace hornet {

using namespace llvm;

Module*          module;
ExecutionEngine* engine;

Type* typeof(type t)
{
    switch (t) {
    case type::t_int: return Type::getInt32Ty(getGlobalContext());
    default:          assert(0);
    }
}

Instruction::BinaryOps to_binary_op(binop op)
{
    switch (op) {
    case binop::op_add: return Instruction::BinaryOps::Add;
    case binop::op_sub: return Instruction::BinaryOps::Sub;
    case binop::op_mul: return Instruction::BinaryOps::Mul;
    case binop::op_div: return Instruction::BinaryOps::SDiv;
    case binop::op_rem: return Instruction::BinaryOps::SRem;
    case binop::op_and: return Instruction::BinaryOps::And;
    case binop::op_or:  return Instruction::BinaryOps::Or;
    case binop::op_xor: return Instruction::BinaryOps::Xor;
    default:            assert(0);
    }
}

class llvm_translator : public translator {
public:
    llvm_translator(method* method);
    ~llvm_translator();

    template<typename T>
    T trampoline();

    virtual void prologue () override;
    virtual void op_const (type t, int64_t value) override;
    virtual void op_load  (type t, uint16_t idx) override;
    virtual void op_store (type t, uint16_t idx) override;
    virtual void op_binary(type t, binop op) override;
    virtual void op_returnvoid() override;

private:
    AllocaInst* lookup_local(unsigned int idx, Type* type);

    std::stack<Value*> _mimic_stack;
    std::vector<AllocaInst*> _locals;
    IRBuilder<> _builder;
    Function* _func;
    method* _method;
};

FunctionType* function_type(IRBuilder<>& builder, method* method)
{
    return FunctionType::get(builder.getVoidTy(), false);
}

Function* function(IRBuilder<>& builder, method* method)
{
    auto func_type = function_type(builder, method);
    auto func = Function::Create(func_type, Function::ExternalLinkage, method->name, module);
    auto entry = BasicBlock::Create(builder.getContext(), "entry", func);
    builder.SetInsertPoint(entry);
    return func;
}

llvm_translator::llvm_translator(method* method)
    : translator(method)
    , _locals(method->max_locals)
    , _builder(module->getContext())
    , _method(method)
{
    _func = function(_builder, _method);
}

llvm_translator::~llvm_translator()
{
}

template<typename T> T llvm_translator::trampoline()
{
    verifyFunction(*_func, PrintMessageAction);
    return reinterpret_cast<T>(engine->getPointerToFunction(_func));
}

AllocaInst* llvm_translator::lookup_local(unsigned int idx, Type* type)
{
    if (_locals[idx]) {
        return _locals[idx];
    }
    IRBuilder<> builder(&_func->getEntryBlock(), _func->getEntryBlock().begin());
    auto ret = builder.CreateAlloca(type, nullptr, "");
    _locals[idx] = ret;
    return ret;
}

void llvm_translator::prologue()
{
}

void llvm_translator::op_const(type t, int64_t value)
{
    auto c = ConstantInt::get(typeof(t), value, 0);

    _mimic_stack.push(c);
}

void llvm_translator::op_load(type t, uint16_t idx)
{
    auto value = _builder.CreateLoad(_locals[idx]);

    _mimic_stack.push(value);
}

void llvm_translator::op_store(type t, uint16_t idx)
{
    auto value = _mimic_stack.top();
    _mimic_stack.pop();
    auto local = lookup_local(idx, typeof(t));
    _builder.CreateStore(value, local);
}

void llvm_translator::op_binary(type t, binop op)
{
    auto value2 = _mimic_stack.top();
    _mimic_stack.pop();
    auto value1 = _mimic_stack.top();
    _mimic_stack.pop();
    auto result = _builder.CreateBinOp(to_binary_op(op), value1, value2);
    _mimic_stack.push(result);
}

void llvm_translator::op_returnvoid()
{
    _builder.CreateRetVoid();
}

llvm_backend::llvm_backend()
{
    InitializeNativeTarget();
    module = new Module("JIT", getGlobalContext());
    auto engine_builder = EngineBuilder(module);
    std::string error_str;
    engine_builder.setErrorStr(&error_str);
    engine = engine_builder.create();
    if (!engine) {
        throw std::runtime_error(error_str);
    }
}

llvm_backend::~llvm_backend()
{
    delete engine;
}

value_t llvm_backend::execute(method* method, frame& frame)
{
    llvm_translator translator(method);

    translator.translate();

    auto fp = translator.trampoline<value_t (*)()>();

    return fp();
}

}
<|endoftext|>