<commit_before>/* -*-  mode: c++; c-default-style: "google"; indent-tabs-mode: nil -*- */
/* -------------------------------------------------------------------------
ATS

License: see $ATS_DIR/COPYRIGHT
Author: Ethan Coon

Derived MPC for flow and energy.  This couples using a block-diagonal coupler.
------------------------------------------------------------------------- */

#include "wrm_richards_evaluator.hh"
#include "mpc_frozen_prec_coupled_flow_energy.hh"

namespace Amanzi {

#define DEBUG_FLAG 1

RegisteredPKFactory<MPCFrozenCoupledFlowEnergy> MPCFrozenCoupledFlowEnergy::reg_("frozen energy-flow preconditioner coupled");

bool MPCFrozenCoupledFlowEnergy::modify_predictor(double h, Teuchos::RCP<TreeVector> u) {
  Teuchos::RCP<CompositeVector> temp_guess = u->SubVector("energy")->data();
  Teuchos::RCP<const CompositeVector> temp = S_next_->GetFieldData("temperature");

  bool update_faces(false);

  int ncells = temp->size("cell",false);
  std::vector<bool> changed(ncells, false);
  for (int c=0; c!=ncells; ++c) {
    if ((*temp)("cell",c) >= 273.15 && (*temp_guess)("cell",c) < 273.15) {
      // freezing
      (*temp_guess)("cell",c) = 273.15 - 1.e-3;
      changed[c] = true;
      update_faces = true;
    } else if ((*temp)("cell",c) <= 273.15 && (*temp_guess)("cell",c) > 273.15) {
      // thawing
      (*temp_guess)("cell",c) = 273.15 - 1.e-3;
      changed[c] = true;
      update_faces = true;
    } else if (273.15 > (*temp)("cell",c) &&
               (*temp)("cell",c) >= 273.1 &&
               ((*temp)("cell",c) - (*temp_guess)("cell",c)) > 1.e-2) {
      // catch the 2nd step in freezing -- after the 2nd step the
      // extrapolation should be ok?
      (*temp_guess)("cell",c) = (*temp)("cell",c);
      changed[c] = true;
      update_faces = true;
    }
  }

  if (update_faces) {
    AmanziMesh::Entity_ID_List cells;

    int f_owned = temp_guess->size("face");
    for (int f=0; f!=f_owned; ++f) {
      cells.clear();
      temp_guess->mesh()->face_get_cells(f, AmanziMesh::USED, &cells);
      if (cells.size() == 2) {
        if (changed[cells[0]] || changed[cells[1]]) {
          (*temp_guess)("face",f) = ((*temp_guess)("cell",cells[0])
                  + (*temp_guess)("cell",cells[1])) / 2.0;
        }
      }
    }
    return true;
  }
  return false;
}

bool MPCFrozenCoupledFlowEnergy::modify_predictor_temp(double h, Teuchos::RCP<TreeVector> u) {
  // modification of the initial guess occurs by updating T using this guess,
  // then calculating the p that would be required to keep the same water
  // mass.

  // Stuff temperature into state
  Teuchos::RCP<TreeVector> uT = u->SubVector("energy");
  sub_pks_[1]->changed_solution();

#if DEBUG_FLAG
  std::cout << std::endl;
  std::cout << "Modifying guess:" << std::endl;
  std::cout << "  T0: " << (*uT->data())("cell",0) << std::endl;
  std::cout << "  T1: " << (*uT->data())("cell",99) << std::endl;
#endif

  // update water content, which will get all the needed vals updated at the new temp.
  S_next_->GetFieldEvaluator("water_content")
      ->HasFieldChanged(S_next_.ptr(), "richards_pk");

  // get the needed vals
  Teuchos::RCP<const CompositeVector> wc0 = S_inter_->GetFieldData("water_content");
  Teuchos::RCP<const CompositeVector> cv = S_inter_->GetFieldData("cell_volume");
  Teuchos::RCP<const CompositeVector> phi = S_next_->GetFieldData("porosity");
  Teuchos::RCP<const CompositeVector> n_g = S_next_->GetFieldData("molar_density_gas");
  Teuchos::RCP<const CompositeVector> omega_g = S_next_->GetFieldData("mol_frac_gas");
  Teuchos::RCP<const CompositeVector> n_l = S_next_->GetFieldData("molar_density_liquid");
  Teuchos::RCP<const CompositeVector> n_i = S_next_->GetFieldData("molar_density_ice");
  Teuchos::RCP<const CompositeVector> one_on_A = S_next_->GetFieldData("wrm_permafrost_one_on_A");
  Teuchos::RCP<const double> p_atm = S_next_->GetScalarData("atmospheric_pressure");

  // get the WRMs
  Teuchos::RCP<FieldEvaluator> wrm_B_eval_base = S_next_->GetFieldEvaluator("wrm_permafrost_one_on_B");
  Teuchos::RCP<Flow::FlowRelations::WRMRichardsEvaluator> wrm_B_eval =
      Teuchos::rcp_dynamic_cast<Flow::FlowRelations::WRMRichardsEvaluator>(wrm_B_eval_base);
  Teuchos::RCP<Flow::FlowRelations::WRMRegionPairList> wrms = wrm_B_eval->get_WRMs();

  // get the result pressure
  Teuchos::RCP<CompositeVector> pres = u->SubVector("flow")->data();
  for (Flow::FlowRelations::WRMRegionPairList::iterator region=wrms->begin();
       region!=wrms->end(); ++region) {
    std::string name = region->first;
    int ncells = pres->mesh()->get_set_size(name, AmanziMesh::CELL, AmanziMesh::OWNED);
    AmanziMesh::Entity_ID_List cells(ncells);
    pres->mesh()->get_set_entities(name, AmanziMesh::CELL, AmanziMesh::OWNED, &cells);

    for (AmanziMesh::Entity_ID_List::iterator c=cells.begin(); c!=cells.end(); ++c) {
      double p = (*pres)("cell",*c);
      double A_minus_one = (1.0/(*one_on_A)("cell",*c) - 1.0);

      double wc = (*wc0)("cell",*c) / (*cv)("cell",*c);
      double sstar = (wc - (*n_g)("cell",*c)*(*omega_g)("cell",*c)*(*phi)("cell",*c)) /
          ((*phi)("cell",*c) * ((*n_l)("cell",*c) - (*n_g)("cell",*c)*(*omega_g)("cell",*c)
                  + (*n_i)("cell",*c)*A_minus_one) - A_minus_one*wc);

      if (sstar > 0.) {
        if (*c==0) std::cout << "   A-1(0) = " << A_minus_one << std::endl;
        if (*c==99) std::cout << "   A-1(99) = " << A_minus_one << std::endl;
        if (*c==0) std::cout << "   S*(0) = " << sstar << std::endl;
        if (*c==99) std::cout << "   S*(99) = " << sstar << std::endl;

        double pc = region->second->capillaryPressure(sstar);

        if (*c==0) std::cout << "   pc(0) = " << pc << std::endl;
        if (*c==99) std::cout << "   pc(99) = " << pc << std::endl;

        (*pres)("cell",*c) = *p_atm - pc;

        if (*c==0) std::cout << "   p(0) = " << (*pres)("cell",*c) << std::endl;
        if (*c==99) std::cout << "   p(99) = " <<  (*pres)("cell",*c) << std::endl;

      }
    }
  }

  AmanziMesh::Entity_ID_List cells;
  pres->ScatterMasterToGhosted("cell");

  int f_owned = pres->size("face");
  for (int f=0; f!=f_owned; ++f) {
    cells.clear();
    pres->mesh()->face_get_cells(f, AmanziMesh::USED, &cells);
    int ncells = cells.size();

    double face_value = 0.0;
    for (int n=0; n!=ncells; ++n) {
      face_value += (*pres)("cell",cells[n]);
    }
    (*pres)("face",f) = face_value / ncells;
  }

  return true;
};

} // namespace
<commit_msg>updating the modification process to modify faces correctly as well<commit_after>/* -*-  mode: c++; c-default-style: "google"; indent-tabs-mode: nil -*- */
/* -------------------------------------------------------------------------
ATS

License: see $ATS_DIR/COPYRIGHT
Author: Ethan Coon

Derived MPC for flow and energy.  This couples using a block-diagonal coupler.
------------------------------------------------------------------------- */

#include "wrm_richards_evaluator.hh"
#include "mpc_frozen_prec_coupled_flow_energy.hh"

namespace Amanzi {

#define DEBUG_FLAG 0

RegisteredPKFactory<MPCFrozenCoupledFlowEnergy> MPCFrozenCoupledFlowEnergy::reg_("frozen energy-flow preconditioner coupled");

bool MPCFrozenCoupledFlowEnergy::modify_predictor(double h, Teuchos::RCP<TreeVector> u) {
  Teuchos::RCP<CompositeVector> temp_guess = u->SubVector("energy")->data();
  Epetra_MultiVector& guess_cells = *temp_guess->ViewComponent("cell",false);
  Epetra_MultiVector& guess_faces = *temp_guess->ViewComponent("face",false);

  Teuchos::RCP<const CompositeVector> temp = S_next_->GetFieldData("temperature");
  const Epetra_MultiVector& temp_cells = *temp->ViewComponent("cell",false);

  bool update_faces(false);

#if DEBUG_FLAG
  std::cout << "--- Modifying Guess: ---" << std::cout;
#endif

  int ncells = temp->size("cell",false);
  std::vector<bool> changed(ncells, false);
  for (int c=0; c!=ncells; ++c) {
    if (temp_cells[0][c] >= 273.15 && guess_cells[0][c] < 273.15) {
      // freezing
      guess_cells[0][c] = 273.15 - 1.e-4;
      changed[c] = true;
      update_faces = true;
    } else if (temp_cells[0][c] <= 273.15 && guess_cells[0][c] > 273.15) {
      // thawing
      guess_cells[0][c] = 273.15 - 1.e-3;
      changed[c] = true;
      update_faces = true;
    } else if (273.15 > temp_cells[0][c] &&
               temp_cells[0][c] >= 273.1 &&
               (temp_cells[0][c] - guess_cells[0][c]) > 1.e-2) {
      // catch the 2nd step in freezing -- after the 2nd step the
      // extrapolation should be ok?
      guess_cells[0][c] = temp_cells[0][c];
      changed[c] = true;
      update_faces = true;
    }
  }

  if (update_faces) {
    temp_guess->ScatterMasterToGhosted("cell");
    AmanziMesh::Entity_ID_List cells;

    int f_owned = temp_guess->size("face");
    for (int f=0; f!=f_owned; ++f) {
      cells.clear();
      temp_guess->mesh()->face_get_cells(f, AmanziMesh::USED, &cells);
      if (cells.size() == 2) {
        if (changed[cells[0]] || changed[cells[1]]) {
          guess_faces[0][f] = (guess_cells[0][cells[0]]
                  + guess_cells[0][cells[1]]) / 2.0;
        }
      }
    }
    return true;
  }
  return false;
}

bool MPCFrozenCoupledFlowEnergy::modify_predictor_temp(double h, Teuchos::RCP<TreeVector> u) {
  // modification of the initial guess occurs by updating T using this guess,
  // then calculating the p that would be required to keep the same water
  // mass.

  // Stuff temperature into state
  Teuchos::RCP<TreeVector> uT = u->SubVector("energy");
  sub_pks_[1]->changed_solution();

#if DEBUG_FLAG
  std::cout << std::endl;
  std::cout << "Modifying guess:" << std::endl;
  std::cout << "  T0: " << (*uT->data())("cell",0) << std::endl;
  std::cout << "  T1: " << (*uT->data())("cell",99) << std::endl;
#endif

  // update water content, which will get all the needed vals updated at the new temp.
  S_next_->GetFieldEvaluator("water_content")
      ->HasFieldChanged(S_next_.ptr(), "richards_pk");

  // get the needed vals
  Teuchos::RCP<const CompositeVector> wc0 = S_inter_->GetFieldData("water_content");
  Teuchos::RCP<const CompositeVector> cv = S_inter_->GetFieldData("cell_volume");
  Teuchos::RCP<const CompositeVector> phi = S_next_->GetFieldData("porosity");
  Teuchos::RCP<const CompositeVector> n_g = S_next_->GetFieldData("molar_density_gas");
  Teuchos::RCP<const CompositeVector> omega_g = S_next_->GetFieldData("mol_frac_gas");
  Teuchos::RCP<const CompositeVector> n_l = S_next_->GetFieldData("molar_density_liquid");
  Teuchos::RCP<const CompositeVector> n_i = S_next_->GetFieldData("molar_density_ice");
  Teuchos::RCP<const CompositeVector> one_on_A = S_next_->GetFieldData("wrm_permafrost_one_on_A");
  Teuchos::RCP<const double> p_atm = S_next_->GetScalarData("atmospheric_pressure");

  // get the WRMs
  Teuchos::RCP<FieldEvaluator> wrm_B_eval_base = S_next_->GetFieldEvaluator("wrm_permafrost_one_on_B");
  Teuchos::RCP<Flow::FlowRelations::WRMRichardsEvaluator> wrm_B_eval =
      Teuchos::rcp_dynamic_cast<Flow::FlowRelations::WRMRichardsEvaluator>(wrm_B_eval_base);
  Teuchos::RCP<Flow::FlowRelations::WRMRegionPairList> wrms = wrm_B_eval->get_WRMs();

  // get the result pressure
  Teuchos::RCP<CompositeVector> pres = u->SubVector("flow")->data();
  for (Flow::FlowRelations::WRMRegionPairList::iterator region=wrms->begin();
       region!=wrms->end(); ++region) {
    std::string name = region->first;
    int ncells = pres->mesh()->get_set_size(name, AmanziMesh::CELL, AmanziMesh::OWNED);
    AmanziMesh::Entity_ID_List cells(ncells);
    pres->mesh()->get_set_entities(name, AmanziMesh::CELL, AmanziMesh::OWNED, &cells);

    for (AmanziMesh::Entity_ID_List::iterator c=cells.begin(); c!=cells.end(); ++c) {
      double p = (*pres)("cell",*c);
      double A_minus_one = (1.0/(*one_on_A)("cell",*c) - 1.0);

      double wc = (*wc0)("cell",*c) / (*cv)("cell",*c);
      double sstar = (wc - (*n_g)("cell",*c)*(*omega_g)("cell",*c)*(*phi)("cell",*c)) /
          ((*phi)("cell",*c) * ((*n_l)("cell",*c) - (*n_g)("cell",*c)*(*omega_g)("cell",*c)
                  + (*n_i)("cell",*c)*A_minus_one) - A_minus_one*wc);

      if (sstar > 0.) {
        if (*c==0) std::cout << "   A-1(0) = " << A_minus_one << std::endl;
        if (*c==99) std::cout << "   A-1(99) = " << A_minus_one << std::endl;
        if (*c==0) std::cout << "   S*(0) = " << sstar << std::endl;
        if (*c==99) std::cout << "   S*(99) = " << sstar << std::endl;

        double pc = region->second->capillaryPressure(sstar);

        if (*c==0) std::cout << "   pc(0) = " << pc << std::endl;
        if (*c==99) std::cout << "   pc(99) = " << pc << std::endl;

        (*pres)("cell",*c) = *p_atm - pc;

        if (*c==0) std::cout << "   p(0) = " << (*pres)("cell",*c) << std::endl;
        if (*c==99) std::cout << "   p(99) = " <<  (*pres)("cell",*c) << std::endl;

      }
    }
  }

  AmanziMesh::Entity_ID_List cells;
  pres->ScatterMasterToGhosted("cell");

  int f_owned = pres->size("face");
  for (int f=0; f!=f_owned; ++f) {
    cells.clear();
    pres->mesh()->face_get_cells(f, AmanziMesh::USED, &cells);
    int ncells = cells.size();

    double face_value = 0.0;
    for (int n=0; n!=ncells; ++n) {
      face_value += (*pres)("cell",cells[n]);
    }
    (*pres)("face",f) = face_value / ncells;
  }

  return true;
};

} // namespace
<|endoftext|>


<commit_before>
#pragma once

#include "numerics/gradient_descent.hpp"

#include "geometry/grassmann.hpp"
#include "geometry/r3x3_matrix.hpp"
#include "geometry/symmetric_bilinear_form.hpp"
#include "mathematica/mathematica.hpp"
#include "quantities/named_quantities.hpp"
#include "quantities/si.hpp"

namespace principia {
namespace numerics {
namespace internal_gradient_descent {

using geometry::Displacement;
using geometry::InnerProduct;
using geometry::Normalize;
using geometry::R3x3Matrix;
using geometry::SymmetricBilinearForm;
using geometry::SymmetricProduct;
using quantities::Quotient;
using quantities::Square;
using quantities::si::Kilo;
using quantities::si::Metre;
namespace si = quantities::si;

// The type of Dₖ, which approximates the inverse of the Hessian.
template<typename Scalar, typename Frame>
using InverseHessian =
    SymmetricBilinearForm<Quotient<Square<Length>, Scalar>, Frame, Vector>;

constexpr Length initial_step_size = 1 * Metre;//Kilo(Metre);

// Parameters for the Armijo rule.
constexpr double s = 1;
constexpr double β = 0.5;
constexpr double σ = 1e-3;

template<typename Scalar, typename Frame>
double ArmijoRule(Position<Frame> const& xₖ,
                  Displacement<Frame> const& dₖ,
                  Gradient<Scalar, Frame> const& grad_f_xₖ,
                  Field<Scalar, Frame> const& f) {
  Scalar const f_xₖ = f(xₖ);
  Scalar const threshold =  -σ * InnerProduct(grad_f_xₖ, dₖ);
  CHECK_LT(Scalar{}, threshold)
      << "Encountered a Hessian that is not positive definite "
      << "xₖ = " << xₖ << ", dₖ = " << dₖ << " , grad_f_xₖ = " << grad_f_xₖ;
  for (double βᵐs = s;; βᵐs *= β) {
    if (f_xₖ - f(xₖ + βᵐs * dₖ) >= βᵐs * threshold) {
      LOG(ERROR)<<βᵐs;
      return βᵐs;
    }
  }
}

template<typename Scalar, typename Frame>
Position<Frame> BroydenFletcherGoldfarbShanno(
    Position<Frame> const& start_position,
    Field<Scalar, Frame> const& f,
    Field<Gradient<Scalar, Frame>, Frame> const& grad_f,
    Length const& tolerance) {
  static SymmetricBilinearForm<double, Frame, Vector> const identity =
      SymmetricBilinearForm<double, Frame, Vector>::Identity();

  mathematica::Logger logger(TEMP_DIR / "gradient_descent.wl");

  // The first step uses vanilla steepest descent.
  auto const x₀ = start_position;
  auto const grad_f_x₀ = grad_f(x₀);
  Displacement<Frame> const p₀ = -Normalize(grad_f_x₀) * initial_step_size;
  double const α₀ = ArmijoRule(x₀, p₀, grad_f_x₀, f);
  auto const x₁ = x₀+ α₀ * p₀;

  // Special computation of H₀ using eq. 6.20.
  auto const grad_f_x₁ = grad_f(x₁);
  Displacement<Frame> const s₀ = x₁ - x₀;
  auto const y₀ = grad_f_x₁ - grad_f_x₀;
  InverseHessian<Scalar, Frame> const H₀ =
      InnerProduct(s₀, y₀) * identity / y₀.Norm²();

  auto xₖ = x₁;
  auto grad_f_xₖ = grad_f_x₁;
  auto Hₖ = H₀;
  for (;;) {
    LOG(ERROR)<<xₖ;
    LOG(ERROR)<<Hₖ;
    logger.Append("grad",
                  std::tuple{xₖ, grad_f_xₖ},
                  mathematica::ExpressIn(quantities::si::Metre));
    logger.Append("inverseHessian",
                  Hₖ,
                  mathematica::ExpressIn(quantities::si::Metre));
    Displacement<Frame> const pₖ = -Hₖ * grad_f_xₖ;
    LOG(ERROR)<<InnerProduct(grad_f_xₖ, pₖ);
    if (pₖ.Norm() <= tolerance) {
      return xₖ;
    }
    double αₖ = ArmijoRule(xₖ, pₖ, grad_f_xₖ, f);
    Position<Frame> xₖ₊₁;
    Gradient<Scalar, Frame> grad_f_xₖ₊₁;
    do {
      xₖ₊₁ = xₖ + αₖ * pₖ;
      grad_f_xₖ₊₁ = grad_f(xₖ₊₁);
      αₖ *= 1.1;
    LOG(ERROR)<<xₖ₊₁;
      LOG(ERROR)<<-InnerProduct(grad_f_xₖ₊₁, pₖ) <<" "<<
             -0.9 * InnerProduct(grad_f_xₖ, pₖ);
    } while (-InnerProduct(grad_f_xₖ₊₁, pₖ) >
             -0.9 * InnerProduct(grad_f_xₖ, pₖ));
    auto const sₖ = xₖ₊₁ - xₖ;
    auto const yₖ = grad_f_xₖ₊₁ - grad_f_xₖ;
    // The formula (6.17) from [] is inconvenient because it uses external
    // products.  Elementary transformations yield the formula below.
    auto const ρ = 1 / InnerProduct(sₖ, yₖ);
    auto const Hₖ₊₁ =
        Hₖ + ρ * ((ρ * Hₖ(yₖ, yₖ) + 1) * SymmetricProduct(sₖ, sₖ) -
                  2 * SymmetricProduct(Hₖ * yₖ, sₖ));

    xₖ = xₖ₊₁;
    grad_f_xₖ = grad_f_xₖ₊₁;
    Hₖ = Hₖ₊₁;
  }
  return xₖ;
}

}  // namespace internal_gradient_descent
}  // namespace numerics
}  // namespace principia
<commit_msg>Line search.<commit_after>
#pragma once

#include "numerics/gradient_descent.hpp"

#include <optional>

#include "geometry/grassmann.hpp"
#include "geometry/r3x3_matrix.hpp"
#include "geometry/symmetric_bilinear_form.hpp"
#include "mathematica/mathematica.hpp"
#include "quantities/named_quantities.hpp"
#include "quantities/si.hpp"

namespace principia {
namespace numerics {
namespace internal_gradient_descent {

using geometry::Displacement;
using geometry::InnerProduct;
using geometry::Normalize;
using geometry::R3x3Matrix;
using geometry::SymmetricBilinearForm;
using geometry::SymmetricProduct;
using quantities::Quotient;
using quantities::Square;
using quantities::si::Kilo;
using quantities::si::Metre;
namespace si = quantities::si;

// The type of Dₖ, which approximates the inverse of the Hessian.
template<typename Scalar, typename Frame>
using InverseHessian =
    SymmetricBilinearForm<Quotient<Square<Length>, Scalar>, Frame, Vector>;

constexpr Length initial_step_size = 1 * Metre;//Kilo(Metre);

// Parameters for the Armijo rule.
constexpr double s = 1;
constexpr double β = 0.5;
constexpr double σ = 1e-3;

template<typename Scalar, typename Frame>
double ArmijoRule(Position<Frame> const& xₖ,
                  Displacement<Frame> const& dₖ,
                  Gradient<Scalar, Frame> const& grad_f_xₖ,
                  Field<Scalar, Frame> const& f) {
  Scalar const f_xₖ = f(xₖ);
  Scalar const threshold =  -σ * InnerProduct(grad_f_xₖ, dₖ);
  CHECK_LT(Scalar{}, threshold)
      << "Encountered a Hessian that is not positive definite "
      << "xₖ = " << xₖ << ", dₖ = " << dₖ << " , grad_f_xₖ = " << grad_f_xₖ;
  for (double βᵐs = s;; βᵐs *= β) {
    if (f_xₖ - f(xₖ + βᵐs * dₖ) >= βᵐs * threshold) {
      LOG(ERROR)<<βᵐs;
      return βᵐs;
    }
  }
}

constexpr double c₁ = 1e-4;
constexpr double c₂ = 0.9;
constexpr double α_max = 1e3;

template<typename Scalar, typename Frame>
double LineSearch(Position<Frame> const& x,
                  Displacement<Frame> const& p,
                  Field<Scalar, Frame> const& f,
                  Field<Gradient<Scalar, Frame>, Frame> const& grad_f) {
  auto const ϕ_0 = f(x);
  auto const ϕʹ_0 = InnerProduct(grad_f(x), p);
  double αᵢ₋₁ = 0;  // α₀.
  double αᵢ = 1;    // α₁
  std::optional<Scalar> ϕ_αᵢ₋₁;
  while (αᵢ < α_max) {
    auto const ϕ_αᵢ = f(x + αᵢ * p);
    if (ϕ_αᵢ > ϕ_0 + c₁ * αᵢ * ϕʹ_0 ||
        (ϕ_αᵢ₋₁.has_value() && ϕ_αᵢ >= ϕ_αᵢ₋₁.value())) {
      return Zoom(αᵢ₋₁, αᵢ);
    }
    auto const ϕʹ_αᵢ = InnerProduct(grad_f(x + αᵢ * p), p);
    if (Abs(ϕʹ_αᵢ) <= -c₂ * ϕʹ_0) {
      return αᵢ;
    }
    if (ϕʹ_αᵢ >= 0) {
      return Zoom(αᵢ, αᵢ₋₁);
    }

    αᵢ₋₁ = αᵢ;
    ϕ_αᵢ₋₁ = ϕ_αᵢ;
    αᵢ = αᵢ * 2;  ////
  }
}

template<typename Scalar, typename Frame>
Position<Frame> BroydenFletcherGoldfarbShanno(
    Position<Frame> const& start_position,
    Field<Scalar, Frame> const& f,
    Field<Gradient<Scalar, Frame>, Frame> const& grad_f,
    Length const& tolerance) {
  static SymmetricBilinearForm<double, Frame, Vector> const identity =
      SymmetricBilinearForm<double, Frame, Vector>::Identity();

  mathematica::Logger logger(TEMP_DIR / "gradient_descent.wl");

  // The first step uses vanilla steepest descent.
  auto const x₀ = start_position;
  auto const grad_f_x₀ = grad_f(x₀);
  Displacement<Frame> const p₀ = -Normalize(grad_f_x₀) * initial_step_size;
  double const α₀ = ArmijoRule(x₀, p₀, grad_f_x₀, f);
  auto const x₁ = x₀+ α₀ * p₀;

  // Special computation of H₀ using eq. 6.20.
  auto const grad_f_x₁ = grad_f(x₁);
  Displacement<Frame> const s₀ = x₁ - x₀;
  auto const y₀ = grad_f_x₁ - grad_f_x₀;
  InverseHessian<Scalar, Frame> const H₀ =
      InnerProduct(s₀, y₀) * identity / y₀.Norm²();

  auto xₖ = x₁;
  auto grad_f_xₖ = grad_f_x₁;
  auto Hₖ = H₀;
  for (;;) {
    LOG(ERROR)<<xₖ;
    LOG(ERROR)<<Hₖ;
    logger.Append("grad",
                  std::tuple{xₖ, grad_f_xₖ},
                  mathematica::ExpressIn(quantities::si::Metre));
    logger.Append("inverseHessian",
                  Hₖ,
                  mathematica::ExpressIn(quantities::si::Metre));
    Displacement<Frame> const pₖ = -Hₖ * grad_f_xₖ;
    LOG(ERROR)<<InnerProduct(grad_f_xₖ, pₖ);
    if (pₖ.Norm() <= tolerance) {
      return xₖ;
    }
    double αₖ = ArmijoRule(xₖ, pₖ, grad_f_xₖ, f);
    Position<Frame> xₖ₊₁;
    Gradient<Scalar, Frame> grad_f_xₖ₊₁;
    do {
      xₖ₊₁ = xₖ + αₖ * pₖ;
      grad_f_xₖ₊₁ = grad_f(xₖ₊₁);
      αₖ *= 1.1;
    LOG(ERROR)<<xₖ₊₁;
      LOG(ERROR)<<-InnerProduct(grad_f_xₖ₊₁, pₖ) <<" "<<
             -0.9 * InnerProduct(grad_f_xₖ, pₖ);
    } while (-InnerProduct(grad_f_xₖ₊₁, pₖ) >
             -0.9 * InnerProduct(grad_f_xₖ, pₖ));
    auto const sₖ = xₖ₊₁ - xₖ;
    auto const yₖ = grad_f_xₖ₊₁ - grad_f_xₖ;
    // The formula (6.17) from [] is inconvenient because it uses external
    // products.  Elementary transformations yield the formula below.
    auto const ρ = 1 / InnerProduct(sₖ, yₖ);
    auto const Hₖ₊₁ =
        Hₖ + ρ * ((ρ * Hₖ(yₖ, yₖ) + 1) * SymmetricProduct(sₖ, sₖ) -
                  2 * SymmetricProduct(Hₖ * yₖ, sₖ));

    xₖ = xₖ₊₁;
    grad_f_xₖ = grad_f_xₖ₊₁;
    Hₖ = Hₖ₊₁;
  }
  return xₖ;
}

}  // namespace internal_gradient_descent
}  // namespace numerics
}  // namespace principia
<|endoftext|>


<commit_before>// Copyright (C) 2010-2012 Joshua Boyce.
// See the file COPYING for copying permission.

#include "hadesmem/pelib/pefile.hpp"

#include <sstream>
#include <utility>

#define BOOST_TEST_MODULE alloc
#include "hadesmem/detail/warning_disable_prefix.hpp"
#include <boost/test/unit_test.hpp>
#include "hadesmem/detail/warning_disable_suffix.hpp"

#include "hadesmem/error.hpp"
#include "hadesmem/config.hpp"
#include "hadesmem/module.hpp"
#include "hadesmem/process.hpp"

// Boost.Test causes the following warning under GCC:
// error: base class 'struct boost::unit_test::ut_detail::nil_t' has a
// non-virtual destructor [-Werror=effc++]
#if defined(HADESMEM_GCC)
#pragma GCC diagnostic ignored "-Weffc++"
#endif // #if defined(HADESMEM_GCC)

// Boost.Test causes the following warning under Clang:
// error: declaration requires a global constructor
// [-Werror,-Wglobal-constructors]
#if defined(HADESMEM_CLANG)
#pragma GCC diagnostic ignored "-Wglobal-constructors"
#endif // #if defined(HADESMEM_CLANG)

BOOST_AUTO_TEST_CASE(pefile)
{
  hadesmem::Process const process(::GetCurrentProcessId());

  hadesmem::PeFile pe_file_1(process, GetModuleHandle(nullptr),
    hadesmem::PeFileType::Image);

  hadesmem::PeFile pe_file_2(pe_file_1);
  BOOST_CHECK_EQUAL(pe_file_1, pe_file_2);
  pe_file_1 = pe_file_2;
  BOOST_CHECK_EQUAL(pe_file_1, pe_file_2);
  hadesmem::PeFile pe_file_3(std::move(pe_file_2));
  BOOST_CHECK_EQUAL(pe_file_3, pe_file_1);
  pe_file_2 = std::move(pe_file_3);
  BOOST_CHECK_EQUAL(pe_file_1, pe_file_2);

  hadesmem::PeFile pe_file_this(process, GetModuleHandle(nullptr),
    hadesmem::PeFileType::Image);
  BOOST_CHECK_EQUAL(pe_file_this.GetBase(), GetModuleHandle(nullptr));
  BOOST_CHECK(pe_file_this.GetType() == hadesmem::PeFileType::Image);
  BOOST_CHECK_EQUAL(hadesmem::RvaToVa(process, pe_file_this, 0),
    static_cast<void*>(nullptr));

  hadesmem::PeFile pe_file_ntdll(process, GetModuleHandle(L"ntdll"),
    hadesmem::PeFileType::Image);
  BOOST_CHECK_EQUAL(pe_file_ntdll.GetBase(), GetModuleHandle(L"ntdll"));
  BOOST_CHECK(pe_file_ntdll.GetType() == hadesmem::PeFileType::Image);
  BOOST_CHECK_EQUAL(hadesmem::RvaToVa(process, pe_file_ntdll, 0),
    static_cast<void*>(nullptr));

  BOOST_CHECK_EQUAL(pe_file_this, pe_file_this);
  BOOST_CHECK_NE(pe_file_this, pe_file_ntdll);
  BOOST_CHECK_NE(pe_file_ntdll, pe_file_this);
  if (pe_file_this > pe_file_ntdll)
  {
    BOOST_CHECK_GT(pe_file_this, pe_file_ntdll);
    BOOST_CHECK_GE(pe_file_this, pe_file_ntdll);
    BOOST_CHECK(!(pe_file_this < pe_file_ntdll));
    BOOST_CHECK(!(pe_file_this <= pe_file_ntdll));
  }
  else
  {
    BOOST_CHECK_GT(pe_file_ntdll, pe_file_this);
    BOOST_CHECK_GE(pe_file_ntdll, pe_file_this);
    BOOST_CHECK(!(pe_file_ntdll < pe_file_this));
    BOOST_CHECK(!(pe_file_ntdll <= pe_file_this));
  }

  std::stringstream test_str_1;
  test_str_1.imbue(std::locale::classic());
  test_str_1 << pe_file_this;
  std::stringstream test_str_2;
  test_str_2.imbue(std::locale::classic());
  test_str_2 << pe_file_this.GetBase();
  BOOST_CHECK_EQUAL(test_str_1.str(), test_str_2.str());
  std::stringstream test_str_3;
  test_str_3.imbue(std::locale::classic());
  test_str_3 << pe_file_ntdll.GetBase();
  BOOST_CHECK_NE(test_str_1.str(), test_str_3.str());
}
<commit_msg>* Fix test name.<commit_after>// Copyright (C) 2010-2012 Joshua Boyce.
// See the file COPYING for copying permission.

#include "hadesmem/pelib/pefile.hpp"

#include <sstream>
#include <utility>

#define BOOST_TEST_MODULE pefile
#include "hadesmem/detail/warning_disable_prefix.hpp"
#include <boost/test/unit_test.hpp>
#include "hadesmem/detail/warning_disable_suffix.hpp"

#include "hadesmem/error.hpp"
#include "hadesmem/config.hpp"
#include "hadesmem/module.hpp"
#include "hadesmem/process.hpp"

// Boost.Test causes the following warning under GCC:
// error: base class 'struct boost::unit_test::ut_detail::nil_t' has a
// non-virtual destructor [-Werror=effc++]
#if defined(HADESMEM_GCC)
#pragma GCC diagnostic ignored "-Weffc++"
#endif // #if defined(HADESMEM_GCC)

// Boost.Test causes the following warning under Clang:
// error: declaration requires a global constructor
// [-Werror,-Wglobal-constructors]
#if defined(HADESMEM_CLANG)
#pragma GCC diagnostic ignored "-Wglobal-constructors"
#endif // #if defined(HADESMEM_CLANG)

BOOST_AUTO_TEST_CASE(pefile)
{
  hadesmem::Process const process(::GetCurrentProcessId());

  hadesmem::PeFile pe_file_1(process, GetModuleHandle(nullptr),
    hadesmem::PeFileType::Image);

  hadesmem::PeFile pe_file_2(pe_file_1);
  BOOST_CHECK_EQUAL(pe_file_1, pe_file_2);
  pe_file_1 = pe_file_2;
  BOOST_CHECK_EQUAL(pe_file_1, pe_file_2);
  hadesmem::PeFile pe_file_3(std::move(pe_file_2));
  BOOST_CHECK_EQUAL(pe_file_3, pe_file_1);
  pe_file_2 = std::move(pe_file_3);
  BOOST_CHECK_EQUAL(pe_file_1, pe_file_2);

  hadesmem::PeFile pe_file_this(process, GetModuleHandle(nullptr),
    hadesmem::PeFileType::Image);
  BOOST_CHECK_EQUAL(pe_file_this.GetBase(), GetModuleHandle(nullptr));
  BOOST_CHECK(pe_file_this.GetType() == hadesmem::PeFileType::Image);
  BOOST_CHECK_EQUAL(hadesmem::RvaToVa(process, pe_file_this, 0),
    static_cast<void*>(nullptr));

  hadesmem::PeFile pe_file_ntdll(process, GetModuleHandle(L"ntdll"),
    hadesmem::PeFileType::Image);
  BOOST_CHECK_EQUAL(pe_file_ntdll.GetBase(), GetModuleHandle(L"ntdll"));
  BOOST_CHECK(pe_file_ntdll.GetType() == hadesmem::PeFileType::Image);
  BOOST_CHECK_EQUAL(hadesmem::RvaToVa(process, pe_file_ntdll, 0),
    static_cast<void*>(nullptr));

  BOOST_CHECK_EQUAL(pe_file_this, pe_file_this);
  BOOST_CHECK_NE(pe_file_this, pe_file_ntdll);
  BOOST_CHECK_NE(pe_file_ntdll, pe_file_this);
  if (pe_file_this > pe_file_ntdll)
  {
    BOOST_CHECK_GT(pe_file_this, pe_file_ntdll);
    BOOST_CHECK_GE(pe_file_this, pe_file_ntdll);
    BOOST_CHECK(!(pe_file_this < pe_file_ntdll));
    BOOST_CHECK(!(pe_file_this <= pe_file_ntdll));
  }
  else
  {
    BOOST_CHECK_GT(pe_file_ntdll, pe_file_this);
    BOOST_CHECK_GE(pe_file_ntdll, pe_file_this);
    BOOST_CHECK(!(pe_file_ntdll < pe_file_this));
    BOOST_CHECK(!(pe_file_ntdll <= pe_file_this));
  }

  std::stringstream test_str_1;
  test_str_1.imbue(std::locale::classic());
  test_str_1 << pe_file_this;
  std::stringstream test_str_2;
  test_str_2.imbue(std::locale::classic());
  test_str_2 << pe_file_this.GetBase();
  BOOST_CHECK_EQUAL(test_str_1.str(), test_str_2.str());
  std::stringstream test_str_3;
  test_str_3.imbue(std::locale::classic());
  test_str_3 << pe_file_ntdll.GetBase();
  BOOST_CHECK_NE(test_str_1.str(), test_str_3.str());
}
<|endoftext|>


<commit_before>/****************************************************************************
**
** Copyright (C) 2013 Digia Plc and/or its subsidiary(-ies).
** Contact: http://www.qt-project.org/legal
**
** This file is part of Qt Creator.
**
** Commercial License Usage
** Licensees holding valid commercial Qt licenses may use this file in
** accordance with the commercial license agreement provided with the
** Software or, alternatively, in accordance with the terms contained in
** a written agreement between you and Digia.  For licensing terms and
** conditions see http://qt.digia.com/licensing.  For further information
** use the contact form at http://qt.digia.com/contact-us.
**
** GNU Lesser General Public License Usage
** Alternatively, this file may be used under the terms of the GNU Lesser
** General Public License version 2.1 as published by the Free Software
** Foundation and appearing in the file LICENSE.LGPL included in the
** packaging of this file.  Please review the following information to
** ensure the GNU Lesser General Public License version 2.1 requirements
** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
**
** In addition, as a special exception, Digia gives you certain additional
** rights.  These rights are described in the Digia Qt LGPL Exception
** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
**
****************************************************************************/

#include "cmakevalidator.h"

#include <QProcess>
#include <QFileInfo>
#include <QTextDocument>

using namespace CMakeProjectManager::Internal;

///////////////////////////
// CMakeValidator
///////////////////////////
CMakeValidator::CMakeValidator()
    : m_state(Invalid), m_process(0), m_hasCodeBlocksMsvcGenerator(false), m_hasCodeBlocksNinjaGenerator(false)
{

}

CMakeValidator::~CMakeValidator()
{
    cancel();
}

void CMakeValidator::cancel()
{
    if (m_process) {
        disconnect(m_process, SIGNAL(finished(int)));
        m_process->waitForFinished();
        delete m_process;
        m_process = 0;
    }
}

void CMakeValidator::setCMakeExecutable(const QString &executable)
{
    cancel();
    m_process = new QProcess();
    connect(m_process, SIGNAL(finished(int)),
            this, SLOT(finished(int)));

    m_executable = executable;
    QFileInfo fi(m_executable);
    if (fi.exists() && fi.isExecutable()) {
        // Run it to find out more
        m_state = CMakeValidator::RunningBasic;
        if (!startProcess(QStringList(QLatin1String("--help"))))
            m_state = CMakeValidator::Invalid;
    } else {
        m_state = CMakeValidator::Invalid;
    }
}

void CMakeValidator::finished(int exitCode)
{
    if (exitCode) {
        m_state = CMakeValidator::Invalid;
        return;
    }
    if (m_state == CMakeValidator::RunningBasic) {
        QByteArray response = m_process->readAll();
        QRegExp versionRegexp(QLatin1String("^cmake version ([\\d\\.]*)"));
        versionRegexp.indexIn(QString::fromLocal8Bit(response));

        //m_supportsQtCreator = response.contains(QLatin1String("QtCreator"));
        m_hasCodeBlocksMsvcGenerator = response.contains("CodeBlocks - NMake Makefiles");
        m_hasCodeBlocksNinjaGenerator = response.contains("CodeBlocks - Ninja");
        m_version = versionRegexp.cap(1);
        if (!(versionRegexp.capturedTexts().size() > 3))
            m_version += QLatin1Char('.') + versionRegexp.cap(3);

        if (m_version.isEmpty()) {
            m_state = CMakeValidator::Invalid;
        } else {
            m_state = CMakeValidator::RunningFunctionList;
            if (!startProcess(QStringList(QLatin1String("--help-command-list"))))
                finished(0); // shoud never happen, just continue
        }
    } else if (m_state == CMakeValidator::RunningFunctionList) {
        parseFunctionOutput(m_process->readAll());
        m_state = CMakeValidator::RunningFunctionDetails;
        if (!startProcess(QStringList(QLatin1String("--help-commands"))))
            finished(0); // shoud never happen, just continue
    } else if (m_state == CMakeValidator::RunningFunctionDetails) {
        parseFunctionDetailsOutput(m_process->readAll());
        m_state = CMakeValidator::ValidFunctionDetails;
    }
}

bool CMakeValidator::isValid() const
{
    if (m_state == CMakeValidator::Invalid)
        return false;
    if (m_state == CMakeValidator::RunningBasic)
        m_process->waitForFinished();
    return (m_state != CMakeValidator::Invalid);
}

bool CMakeValidator::startProcess(const QStringList &args)
{
    m_process->start(m_executable, args);
    return m_process->waitForStarted(2000);
}

QString CMakeValidator::cmakeExecutable() const
{
    return m_executable;
}

bool CMakeValidator::hasCodeBlocksMsvcGenerator() const
{
    if (!isValid())
        return false;
    return m_hasCodeBlocksMsvcGenerator;
}

bool CMakeValidator::hasCodeBlocksNinjaGenerator() const
{
    if (!isValid())
        return false;
    return m_hasCodeBlocksNinjaGenerator;
}

TextEditor::Keywords CMakeValidator::keywords()
{
    while (m_state != ValidFunctionDetails && m_state != CMakeValidator::Invalid) {
        m_process->waitForFinished();
    }

    if (m_state == CMakeValidator::Invalid)
        return TextEditor::Keywords(QStringList(), QStringList(), QMap<QString, QStringList>());

    return TextEditor::Keywords(m_variables, m_functions, m_functionArgs);
}

static void extractKeywords(const QByteArray &input, QStringList *destination)
{
    if (!destination)
        return;

    QString keyword;
    int ignoreZone = 0;
    for (int i = 0; i < input.count(); ++i) {
        const QChar chr = QLatin1Char(input.at(i));
        if (chr == QLatin1Char('{'))
            ++ignoreZone;
        if (chr == QLatin1Char('}'))
            --ignoreZone;
        if (ignoreZone == 0) {
            if ((chr.isLetterOrNumber() && chr.isUpper())
                || chr == QLatin1Char('_')) {
                keyword += chr;
            } else {
                if (!keyword.isEmpty()) {
                    if (keyword.size() > 1)
                        *destination << keyword;
                    keyword.clear();
                }
            }
        }
    }
    if (keyword.size() > 1)
        *destination << keyword;
}

void CMakeValidator::parseFunctionOutput(const QByteArray &output)
{
    QList<QByteArray> cmakeFunctionsList = output.split('\n');
    m_functions.clear();
    if (!cmakeFunctionsList.isEmpty()) {
        cmakeFunctionsList.removeFirst(); //remove version string
        foreach (const QByteArray &function, cmakeFunctionsList)
            m_functions << QString::fromLocal8Bit(function.trimmed());
    }
}

QString CMakeValidator::formatFunctionDetails(const QString &command, const QString &args)
{
    return QString::fromLatin1("

%1	%2
")
            .arg(Qt::escape(command)).arg(Qt::escape(args));
}

void CMakeValidator::parseFunctionDetailsOutput(const QByteArray &output)
{
    QStringList cmakeFunctionsList = m_functions;
    QList<QByteArray> cmakeCommandsHelp = output.split('\n');
    for (int i = 0; i < cmakeCommandsHelp.count(); ++i) {
        QByteArray lineTrimmed = cmakeCommandsHelp.at(i).trimmed();
        if (cmakeFunctionsList.first().toLatin1() == lineTrimmed) {
            QStringList commandSyntaxes;
            QString currentCommandSyntax;
            QString currentCommand = cmakeFunctionsList.takeFirst();
            ++i;
            for (; i < cmakeCommandsHelp.count(); ++i) {
                lineTrimmed = cmakeCommandsHelp.at(i).trimmed();

                if (cmakeFunctionsList.first().toLatin1() == lineTrimmed) {
                    //start of next function in output
                    if (!currentCommandSyntax.isEmpty())
                        commandSyntaxes << currentCommandSyntax.append(QLatin1String("
"));
                    --i;
                    break;
                }
                if (lineTrimmed.startsWith(currentCommand.toLatin1() + "(")) {
                    if (!currentCommandSyntax.isEmpty())
                        commandSyntaxes << currentCommandSyntax.append(QLatin1String("
"));

                    QByteArray argLine = lineTrimmed.mid(currentCommand.length());
                    extractKeywords(argLine, &m_variables);
                    currentCommandSyntax = formatFunctionDetails(currentCommand, QString::fromUtf8(argLine));
                } else {
                    if (!currentCommandSyntax.isEmpty()) {
                        if (lineTrimmed.isEmpty()) {
                            commandSyntaxes << currentCommandSyntax.append(QLatin1String("
"));
                            currentCommandSyntax.clear();
                        } else {
                            extractKeywords(lineTrimmed, &m_variables);
                            currentCommandSyntax += QString::fromLatin1("
 	%1
")
                                    .arg(Qt::escape(QString::fromLocal8Bit(lineTrimmed)));
                        }
                    }
                }
            }
            m_functionArgs[currentCommand] = commandSyntaxes;
        }
    }
    m_functions = m_functionArgs.keys();
    m_variables.sort();
    m_variables.removeDuplicates();
}
<commit_msg>Get the correct CMake Version<commit_after>/****************************************************************************
**
** Copyright (C) 2013 Digia Plc and/or its subsidiary(-ies).
** Contact: http://www.qt-project.org/legal
**
** This file is part of Qt Creator.
**
** Commercial License Usage
** Licensees holding valid commercial Qt licenses may use this file in
** accordance with the commercial license agreement provided with the
** Software or, alternatively, in accordance with the terms contained in
** a written agreement between you and Digia.  For licensing terms and
** conditions see http://qt.digia.com/licensing.  For further information
** use the contact form at http://qt.digia.com/contact-us.
**
** GNU Lesser General Public License Usage
** Alternatively, this file may be used under the terms of the GNU Lesser
** General Public License version 2.1 as published by the Free Software
** Foundation and appearing in the file LICENSE.LGPL included in the
** packaging of this file.  Please review the following information to
** ensure the GNU Lesser General Public License version 2.1 requirements
** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
**
** In addition, as a special exception, Digia gives you certain additional
** rights.  These rights are described in the Digia Qt LGPL Exception
** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
**
****************************************************************************/

#include "cmakevalidator.h"

#include <QProcess>
#include <QFileInfo>
#include <QTextDocument>

using namespace CMakeProjectManager::Internal;

///////////////////////////
// CMakeValidator
///////////////////////////
CMakeValidator::CMakeValidator()
    : m_state(Invalid), m_process(0), m_hasCodeBlocksMsvcGenerator(false), m_hasCodeBlocksNinjaGenerator(false)
{

}

CMakeValidator::~CMakeValidator()
{
    cancel();
}

void CMakeValidator::cancel()
{
    if (m_process) {
        disconnect(m_process, SIGNAL(finished(int)));
        m_process->waitForFinished();
        delete m_process;
        m_process = 0;
    }
}

void CMakeValidator::setCMakeExecutable(const QString &executable)
{
    cancel();
    m_process = new QProcess();
    connect(m_process, SIGNAL(finished(int)),
            this, SLOT(finished(int)));

    m_executable = executable;
    QFileInfo fi(m_executable);
    if (fi.exists() && fi.isExecutable()) {
        // Run it to find out more
        m_state = CMakeValidator::RunningBasic;
        if (!startProcess(QStringList(QLatin1String("--help"))))
            m_state = CMakeValidator::Invalid;
    } else {
        m_state = CMakeValidator::Invalid;
    }
}

void CMakeValidator::finished(int exitCode)
{
    if (exitCode) {
        m_state = CMakeValidator::Invalid;
        return;
    }
    if (m_state == CMakeValidator::RunningBasic) {
        QByteArray response = m_process->readAll();
        QRegExp versionRegexp(QLatin1String("^cmake version ([\\d\\.]*)"));
        versionRegexp.indexIn(QString::fromLocal8Bit(response));

        //m_supportsQtCreator = response.contains(QLatin1String("QtCreator"));
        m_hasCodeBlocksMsvcGenerator = response.contains("CodeBlocks - NMake Makefiles");
        m_hasCodeBlocksNinjaGenerator = response.contains("CodeBlocks - Ninja");
        m_version = versionRegexp.cap(1);
        if (versionRegexp.capturedTexts().size() > 3)
            m_version += QLatin1Char('.') + versionRegexp.cap(3);

        if (m_version.isEmpty()) {
            m_state = CMakeValidator::Invalid;
        } else {
            m_state = CMakeValidator::RunningFunctionList;
            if (!startProcess(QStringList(QLatin1String("--help-command-list"))))
                finished(0); // shoud never happen, just continue
        }
    } else if (m_state == CMakeValidator::RunningFunctionList) {
        parseFunctionOutput(m_process->readAll());
        m_state = CMakeValidator::RunningFunctionDetails;
        if (!startProcess(QStringList(QLatin1String("--help-commands"))))
            finished(0); // shoud never happen, just continue
    } else if (m_state == CMakeValidator::RunningFunctionDetails) {
        parseFunctionDetailsOutput(m_process->readAll());
        m_state = CMakeValidator::ValidFunctionDetails;
    }
}

bool CMakeValidator::isValid() const
{
    if (m_state == CMakeValidator::Invalid)
        return false;
    if (m_state == CMakeValidator::RunningBasic)
        m_process->waitForFinished();
    return (m_state != CMakeValidator::Invalid);
}

bool CMakeValidator::startProcess(const QStringList &args)
{
    m_process->start(m_executable, args);
    return m_process->waitForStarted(2000);
}

QString CMakeValidator::cmakeExecutable() const
{
    return m_executable;
}

bool CMakeValidator::hasCodeBlocksMsvcGenerator() const
{
    if (!isValid())
        return false;
    return m_hasCodeBlocksMsvcGenerator;
}

bool CMakeValidator::hasCodeBlocksNinjaGenerator() const
{
    if (!isValid())
        return false;
    return m_hasCodeBlocksNinjaGenerator;
}

TextEditor::Keywords CMakeValidator::keywords()
{
    while (m_state != ValidFunctionDetails && m_state != CMakeValidator::Invalid) {
        m_process->waitForFinished();
    }

    if (m_state == CMakeValidator::Invalid)
        return TextEditor::Keywords(QStringList(), QStringList(), QMap<QString, QStringList>());

    return TextEditor::Keywords(m_variables, m_functions, m_functionArgs);
}

static void extractKeywords(const QByteArray &input, QStringList *destination)
{
    if (!destination)
        return;

    QString keyword;
    int ignoreZone = 0;
    for (int i = 0; i < input.count(); ++i) {
        const QChar chr = QLatin1Char(input.at(i));
        if (chr == QLatin1Char('{'))
            ++ignoreZone;
        if (chr == QLatin1Char('}'))
            --ignoreZone;
        if (ignoreZone == 0) {
            if ((chr.isLetterOrNumber() && chr.isUpper())
                || chr == QLatin1Char('_')) {
                keyword += chr;
            } else {
                if (!keyword.isEmpty()) {
                    if (keyword.size() > 1)
                        *destination << keyword;
                    keyword.clear();
                }
            }
        }
    }
    if (keyword.size() > 1)
        *destination << keyword;
}

void CMakeValidator::parseFunctionOutput(const QByteArray &output)
{
    QList<QByteArray> cmakeFunctionsList = output.split('\n');
    m_functions.clear();
    if (!cmakeFunctionsList.isEmpty()) {
        cmakeFunctionsList.removeFirst(); //remove version string
        foreach (const QByteArray &function, cmakeFunctionsList)
            m_functions << QString::fromLocal8Bit(function.trimmed());
    }
}

QString CMakeValidator::formatFunctionDetails(const QString &command, const QString &args)
{
    return QString::fromLatin1("

%1	%2
")
            .arg(Qt::escape(command)).arg(Qt::escape(args));
}

void CMakeValidator::parseFunctionDetailsOutput(const QByteArray &output)
{
    QStringList cmakeFunctionsList = m_functions;
    QList<QByteArray> cmakeCommandsHelp = output.split('\n');
    for (int i = 0; i < cmakeCommandsHelp.count(); ++i) {
        QByteArray lineTrimmed = cmakeCommandsHelp.at(i).trimmed();
        if (cmakeFunctionsList.first().toLatin1() == lineTrimmed) {
            QStringList commandSyntaxes;
            QString currentCommandSyntax;
            QString currentCommand = cmakeFunctionsList.takeFirst();
            ++i;
            for (; i < cmakeCommandsHelp.count(); ++i) {
                lineTrimmed = cmakeCommandsHelp.at(i).trimmed();

                if (cmakeFunctionsList.first().toLatin1() == lineTrimmed) {
                    //start of next function in output
                    if (!currentCommandSyntax.isEmpty())
                        commandSyntaxes << currentCommandSyntax.append(QLatin1String("
"));
                    --i;
                    break;
                }
                if (lineTrimmed.startsWith(currentCommand.toLatin1() + "(")) {
                    if (!currentCommandSyntax.isEmpty())
                        commandSyntaxes << currentCommandSyntax.append(QLatin1String("
"));

                    QByteArray argLine = lineTrimmed.mid(currentCommand.length());
                    extractKeywords(argLine, &m_variables);
                    currentCommandSyntax = formatFunctionDetails(currentCommand, QString::fromUtf8(argLine));
                } else {
                    if (!currentCommandSyntax.isEmpty()) {
                        if (lineTrimmed.isEmpty()) {
                            commandSyntaxes << currentCommandSyntax.append(QLatin1String("
"));
                            currentCommandSyntax.clear();
                        } else {
                            extractKeywords(lineTrimmed, &m_variables);
                            currentCommandSyntax += QString::fromLatin1("
 	%1
")
                                    .arg(Qt::escape(QString::fromLocal8Bit(lineTrimmed)));
                        }
                    }
                }
            }
            m_functionArgs[currentCommand] = commandSyntaxes;
        }
    }
    m_functions = m_functionArgs.keys();
    m_variables.sort();
    m_variables.removeDuplicates();
}
<|endoftext|>


<commit_before>/*
 * Copyright (C) 2017 Jean-Damien Durand <jeandamiendurand@gmail.com>
 *
 * This library 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 of the License, or
 * (at your option) any later version.
 *
 * This library 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 library; if not, see <http://www.gnu.org/licenses/>.
 */

#include "plibsys.h"
#include "ptestmacros.h"

#include <stdio.h>
#include <stdarg.h>

P_TEST_MODULE_INIT ();

static void f (int i, ...) {
  p_va_list args1, args2;

  p_va_start (args1, i);
  p_va_copy(args2, args1);

  P_TEST_CHECK (va_arg (args1, int) == 42);
  P_TEST_CHECK (va_arg (args2, int) == 42);

  p_va_end (args1);
  p_va_end (args2);
}

P_TEST_CASE_BEGIN (pstdarg_general_test)
{
	p_libsys_init ();

        f(0 ,42);

	p_libsys_shutdown ();
}
P_TEST_CASE_END ()

P_TEST_SUITE_BEGIN()
{
	P_TEST_SUITE_RUN_CASE (pstdarg_general_test);
}
P_TEST_SUITE_END()
<commit_msg>Add string.h because of eventual memcpy<commit_after>/*
 * Copyright (C) 2017 Jean-Damien Durand <jeandamiendurand@gmail.com>
 *
 * This library 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 of the License, or
 * (at your option) any later version.
 *
 * This library 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 library; if not, see <http://www.gnu.org/licenses/>.
 */

#include "plibsys.h"
#include "ptestmacros.h"

#include <stdio.h>
#include <stdarg.h>
#include <string.h>

P_TEST_MODULE_INIT ();

static void f (int i, ...) {
  p_va_list args1, args2;

  p_va_start (args1, i);
  p_va_copy(args2, args1);

  P_TEST_CHECK (va_arg (args1, int) == 42);
  P_TEST_CHECK (va_arg (args2, int) == 42);

  p_va_end (args1);
  p_va_end (args2);
}

P_TEST_CASE_BEGIN (pstdarg_general_test)
{
	p_libsys_init ();

        f(0 ,42);

	p_libsys_shutdown ();
}
P_TEST_CASE_END ()

P_TEST_SUITE_BEGIN()
{
	P_TEST_SUITE_RUN_CASE (pstdarg_general_test);
}
P_TEST_SUITE_END()
<|endoftext|>


<commit_before>/****************************************************************************
**
** Copyright (C) 2014 Digia Plc and/or its subsidiary(-ies).
** Contact: http://www.qt-project.org/legal
**
** This file is part of Qt Creator.
**
** Commercial License Usage
** Licensees holding valid commercial Qt licenses may use this file in
** accordance with the commercial license agreement provided with the
** Software or, alternatively, in accordance with the terms contained in
** a written agreement between you and Digia.  For licensing terms and
** conditions see http://qt.digia.com/licensing.  For further information
** use the contact form at http://qt.digia.com/contact-us.
**
** GNU Lesser General Public License Usage
** Alternatively, this file may be used under the terms of the GNU Lesser
** General Public License version 2.1 as published by the Free Software
** Foundation and appearing in the file LICENSE.LGPL included in the
** packaging of this file.  Please review the following information to
** ensure the GNU Lesser General Public License version 2.1 requirements
** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
**
** In addition, as a special exception, Digia gives you certain additional
** rights.  These rights are described in the Digia Qt LGPL Exception
** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
**
****************************************************************************/

#include "qbsprojectparser.h"

#include "qbslogsink.h"
#include "qbsproject.h"
#include "qbsprojectmanagerconstants.h"

#include <coreplugin/icore.h>
#include <utils/qtcassert.h>

#include <qbs.h>

#include <QCoreApplication>
#include <QDir>
#include <QFileInfo>

using namespace Utils;

namespace QbsProjectManager {
namespace Internal {

// --------------------------------------------------------------------
// QbsProjectParser:
// --------------------------------------------------------------------

QbsProjectParser::QbsProjectParser(QbsProject *project, QFutureInterface<bool> *fi) :
    m_qbsSetupProjectJob(0),
    m_fi(fi),
    m_currentProgressBase(0)
{
    m_project = project->qbsProject();
    m_projectFilePath = project->projectFilePath().toString();
}

QbsProjectParser::~QbsProjectParser()
{
    if (m_qbsSetupProjectJob) {
        m_qbsSetupProjectJob->disconnect(this);
        m_qbsSetupProjectJob->cancel();
        m_qbsSetupProjectJob->deleteLater();
        m_qbsSetupProjectJob = 0;
    }
    m_fi = 0; // we do not own m_fi, do not delete
}

void QbsProjectParser::setForced(bool f)
{
    m_wasForced = f;
}

bool QbsProjectParser::parse(const QVariantMap &config, const Environment &env, const QString &dir)
{
    QTC_ASSERT(!m_qbsSetupProjectJob, return false);
    QTC_ASSERT(!dir.isNull(), return false);

    m_currentProgressBase = 0;

    qbs::SetupProjectParameters params;
    QVariantMap userConfig = config;
    QString specialKey = QLatin1String(Constants::QBS_CONFIG_PROFILE_KEY);
    const QString profileName = userConfig.take(specialKey).toString();
    params.setTopLevelProfile(profileName);
    specialKey = QLatin1String(Constants::QBS_CONFIG_VARIANT_KEY);
    params.setBuildVariant(userConfig.take(specialKey).toString());
    params.setSettingsDirectory(QbsManager::settings()->baseDirectoy());
    params.setOverriddenValues(userConfig);
    m_error = params.expandBuildConfiguration();
    if (m_error.hasError()) {
        emit done(false);
        return false;
    }

    // Avoid useless reparsing:
    if (!m_wasForced
            && m_project.isValid()
            && m_project.projectConfiguration() == params.finalBuildConfigurationTree()) {
        QHash<QString, QString> usedEnv = m_project.usedEnvironment();
        for (QHash<QString, QString>::const_iterator i = usedEnv.constBegin();
             i != usedEnv.constEnd(); ++i) {
            if (env.value(i.key()) != i.value()) {
                emit done(true);
                return true;
            }
        }
    }

    // Some people don't like it when files are created as a side effect of opening a project,
    // so do not store the build graph if the build directory does not exist yet.
    params.setDryRun(!QFileInfo(dir).exists());

    params.setBuildRoot(dir);
    params.setProjectFilePath(m_projectFilePath);
    params.setIgnoreDifferentProjectFilePath(false);
    params.setEnvironment(env.toProcessEnvironment());
    const qbs::Preferences prefs(QbsManager::settings(), profileName);
    params.setSearchPaths(prefs.searchPaths(resourcesBaseDirectory()));
    params.setPluginPaths(prefs.pluginPaths(pluginsBaseDirectory()));

    m_qbsSetupProjectJob = qbs::Project::setupProject(params, QbsManager::logSink(), 0);

    connect(m_qbsSetupProjectJob, SIGNAL(finished(bool,qbs::AbstractJob*)),
            this, SLOT(handleQbsParsingDone(bool)));
    connect(m_qbsSetupProjectJob, SIGNAL(taskStarted(QString,int,qbs::AbstractJob*)),
            this, SIGNAL(taskChanged(QString,int)));
    connect(m_qbsSetupProjectJob, SIGNAL(taskProgress(int,qbs::AbstractJob*)),
            this, SIGNAL(progress(int)));

    return true;
}

qbs::Project QbsProjectParser::qbsProject() const
{
    return m_project;
}

qbs::ErrorInfo QbsProjectParser::error()
{
    return m_error;
}

void QbsProjectParser::handleQbsParsingDone(bool success)
{
    QTC_ASSERT(m_qbsSetupProjectJob, return);

    m_project = m_qbsSetupProjectJob->project();
    m_error = m_qbsSetupProjectJob->error();

    if (!success)
        m_fi->reportCanceled();

    emit done(success);
}

void QbsProjectParser::handleQbsParsingProgress(int progress)
{
    if (m_fi)
        m_fi->setProgressValue(m_currentProgressBase + progress);
}

void QbsProjectParser::handleQbsParsingTaskSetup(const QString &description, int maximumProgressValue)
{
    Q_UNUSED(description);
    if (m_fi) {
        m_currentProgressBase = m_fi->progressValue();
        m_fi->setProgressRange(0, m_currentProgressBase + maximumProgressValue);
    }
}

QString QbsProjectParser::resourcesBaseDirectory() const
{
    const QString qbsInstallDir = QLatin1String(QBS_INSTALL_DIR);
    if (!qbsInstallDir.isEmpty())
        return qbsInstallDir;
    return Core::ICore::resourcePath() + QLatin1String("/qbs");
}

QString QbsProjectParser::pluginsBaseDirectory() const
{
    const QString qbsInstallDir = QLatin1String(QBS_INSTALL_DIR);
    if (!qbsInstallDir.isEmpty())
        return qbsInstallDir + QLatin1String("/lib/");
    if (Utils::HostOsInfo::isMacHost())
        return QDir::cleanPath(QCoreApplication::applicationDirPath()
                               + QLatin1String("/../PlugIns"));
    else
        return QDir::cleanPath(QCoreApplication::applicationDirPath()
                               + QLatin1String("/../" IDE_LIBRARY_BASENAME "/qtcreator"));
}

} // namespace Internal
} // namespace QbsProjectManager
<commit_msg>QbsProjectManager: Fix signal/slot connection in QbsProjectParser.<commit_after>/****************************************************************************
**
** Copyright (C) 2014 Digia Plc and/or its subsidiary(-ies).
** Contact: http://www.qt-project.org/legal
**
** This file is part of Qt Creator.
**
** Commercial License Usage
** Licensees holding valid commercial Qt licenses may use this file in
** accordance with the commercial license agreement provided with the
** Software or, alternatively, in accordance with the terms contained in
** a written agreement between you and Digia.  For licensing terms and
** conditions see http://qt.digia.com/licensing.  For further information
** use the contact form at http://qt.digia.com/contact-us.
**
** GNU Lesser General Public License Usage
** Alternatively, this file may be used under the terms of the GNU Lesser
** General Public License version 2.1 as published by the Free Software
** Foundation and appearing in the file LICENSE.LGPL included in the
** packaging of this file.  Please review the following information to
** ensure the GNU Lesser General Public License version 2.1 requirements
** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
**
** In addition, as a special exception, Digia gives you certain additional
** rights.  These rights are described in the Digia Qt LGPL Exception
** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
**
****************************************************************************/

#include "qbsprojectparser.h"

#include "qbslogsink.h"
#include "qbsproject.h"
#include "qbsprojectmanagerconstants.h"

#include <coreplugin/icore.h>
#include <utils/qtcassert.h>

#include <qbs.h>

#include <QCoreApplication>
#include <QDir>
#include <QFileInfo>

using namespace Utils;

namespace QbsProjectManager {
namespace Internal {

// --------------------------------------------------------------------
// QbsProjectParser:
// --------------------------------------------------------------------

QbsProjectParser::QbsProjectParser(QbsProject *project, QFutureInterface<bool> *fi) :
    m_qbsSetupProjectJob(0),
    m_fi(fi),
    m_currentProgressBase(0)
{
    m_project = project->qbsProject();
    m_projectFilePath = project->projectFilePath().toString();
}

QbsProjectParser::~QbsProjectParser()
{
    if (m_qbsSetupProjectJob) {
        m_qbsSetupProjectJob->disconnect(this);
        m_qbsSetupProjectJob->cancel();
        m_qbsSetupProjectJob->deleteLater();
        m_qbsSetupProjectJob = 0;
    }
    m_fi = 0; // we do not own m_fi, do not delete
}

void QbsProjectParser::setForced(bool f)
{
    m_wasForced = f;
}

bool QbsProjectParser::parse(const QVariantMap &config, const Environment &env, const QString &dir)
{
    QTC_ASSERT(!m_qbsSetupProjectJob, return false);
    QTC_ASSERT(!dir.isNull(), return false);

    m_currentProgressBase = 0;

    qbs::SetupProjectParameters params;
    QVariantMap userConfig = config;
    QString specialKey = QLatin1String(Constants::QBS_CONFIG_PROFILE_KEY);
    const QString profileName = userConfig.take(specialKey).toString();
    params.setTopLevelProfile(profileName);
    specialKey = QLatin1String(Constants::QBS_CONFIG_VARIANT_KEY);
    params.setBuildVariant(userConfig.take(specialKey).toString());
    params.setSettingsDirectory(QbsManager::settings()->baseDirectoy());
    params.setOverriddenValues(userConfig);
    m_error = params.expandBuildConfiguration();
    if (m_error.hasError()) {
        emit done(false);
        return false;
    }

    // Avoid useless reparsing:
    if (!m_wasForced
            && m_project.isValid()
            && m_project.projectConfiguration() == params.finalBuildConfigurationTree()) {
        QHash<QString, QString> usedEnv = m_project.usedEnvironment();
        for (QHash<QString, QString>::const_iterator i = usedEnv.constBegin();
             i != usedEnv.constEnd(); ++i) {
            if (env.value(i.key()) != i.value()) {
                emit done(true);
                return true;
            }
        }
    }

    // Some people don't like it when files are created as a side effect of opening a project,
    // so do not store the build graph if the build directory does not exist yet.
    params.setDryRun(!QFileInfo(dir).exists());

    params.setBuildRoot(dir);
    params.setProjectFilePath(m_projectFilePath);
    params.setIgnoreDifferentProjectFilePath(false);
    params.setEnvironment(env.toProcessEnvironment());
    const qbs::Preferences prefs(QbsManager::settings(), profileName);
    params.setSearchPaths(prefs.searchPaths(resourcesBaseDirectory()));
    params.setPluginPaths(prefs.pluginPaths(pluginsBaseDirectory()));

    m_qbsSetupProjectJob = qbs::Project::setupProject(params, QbsManager::logSink(), 0);

    connect(m_qbsSetupProjectJob, SIGNAL(finished(bool,qbs::AbstractJob*)),
            this, SLOT(handleQbsParsingDone(bool)));
    connect(m_qbsSetupProjectJob, SIGNAL(taskStarted(QString,int,qbs::AbstractJob*)),
            this, SLOT(handleQbsParsingTaskSetup(QString,int)));
    connect(m_qbsSetupProjectJob, SIGNAL(taskProgress(int,qbs::AbstractJob*)),
            this, SLOT(handleQbsParsingProgress(int)));

    return true;
}

qbs::Project QbsProjectParser::qbsProject() const
{
    return m_project;
}

qbs::ErrorInfo QbsProjectParser::error()
{
    return m_error;
}

void QbsProjectParser::handleQbsParsingDone(bool success)
{
    QTC_ASSERT(m_qbsSetupProjectJob, return);

    m_project = m_qbsSetupProjectJob->project();
    m_error = m_qbsSetupProjectJob->error();

    if (!success)
        m_fi->reportCanceled();

    emit done(success);
}

void QbsProjectParser::handleQbsParsingProgress(int progress)
{
    if (m_fi)
        m_fi->setProgressValue(m_currentProgressBase + progress);
}

void QbsProjectParser::handleQbsParsingTaskSetup(const QString &description, int maximumProgressValue)
{
    Q_UNUSED(description);
    if (m_fi) {
        m_currentProgressBase = m_fi->progressValue();
        m_fi->setProgressRange(0, m_currentProgressBase + maximumProgressValue);
    }
}

QString QbsProjectParser::resourcesBaseDirectory() const
{
    const QString qbsInstallDir = QLatin1String(QBS_INSTALL_DIR);
    if (!qbsInstallDir.isEmpty())
        return qbsInstallDir;
    return Core::ICore::resourcePath() + QLatin1String("/qbs");
}

QString QbsProjectParser::pluginsBaseDirectory() const
{
    const QString qbsInstallDir = QLatin1String(QBS_INSTALL_DIR);
    if (!qbsInstallDir.isEmpty())
        return qbsInstallDir + QLatin1String("/lib/");
    if (Utils::HostOsInfo::isMacHost())
        return QDir::cleanPath(QCoreApplication::applicationDirPath()
                               + QLatin1String("/../PlugIns"));
    else
        return QDir::cleanPath(QCoreApplication::applicationDirPath()
                               + QLatin1String("/../" IDE_LIBRARY_BASENAME "/qtcreator"));
}

} // namespace Internal
} // namespace QbsProjectManager
<|endoftext|>


<commit_before><commit_msg>0.5 pixel switch between opencv 2.4.8 and standard notation<commit_after><|endoftext|>


<commit_before>// Time:  O(n * (C(2n, n) - C(2n, n - 1)))
// Space: O(n * (C(2n, n) - C(2n, n - 1)))

class Solution {
  public:
    vector<int> diffWaysToCompute(string input) {
        vector<vector<vector<int>>> lookup(input.length() + 1,
                                           vector<vector<int>>(input.length() + 1, vector<int>()));
        return diffWaysToComputeRecu(input, 0, input.length(), lookup);
    }

    vector<int> diffWaysToComputeRecu(const string& input,
                                      const int start, const int end,
                                      vector<vector<vector<int>>>& lookup) {
        if (!lookup[start][end].empty()) {
            return lookup[start][end];
        }
        vector<int> result;
        for (int i = start; i < end; ++i) {
            const auto cur = input[i];
            if (cur == '+' || cur == '-' || cur == '*') {
                vector<int> left = move(diffWaysToComputeRecu(input, start, i, lookup));
                vector<int> right = move(diffWaysToComputeRecu(input, i + 1, end, lookup));
                for (const auto& num1 : left) {
                    for (const auto& num2 : right) {
                        if (cur == '+') {
                            result.emplace_back(num1 + num2);
                        } else if (cur == '-') {
                            result.emplace_back(num1 - num2);
                        } else {
                            result.emplace_back(num1 * num2);
                        }
                    }
                }
            }
        }
        // If the input string contains only number.
        if (result.empty()) {
            result.emplace_back(stoi(input.substr(start, end - start)));
        }
        lookup[start][end] = move(result);
        return lookup[start][end];
    }
};

// Time:  O(n * (C(2n, n) - C(2n, n - 1)))
// Space: O(C(2n, n) - C(2n, n - 1))
class Solution2 {
  public:
    vector<int> diffWaysToCompute(string input) {
        vector<int> result;
        for (int i = 0; i < input.size(); ++i) {
            const auto cur = input[i];
            if (cur == '+' || cur == '-' || cur == '*') {
                vector<int> left = move(diffWaysToCompute(input.substr(0, i)));
                vector<int> right = move(diffWaysToCompute(input.substr(i + 1)));
                for (const auto& num1 : left) {
                    for (const auto& num2 : right) {
                        if (cur == '+') {
                            result.emplace_back(num1 + num2);
                        } else if (cur == '-') {
                            result.emplace_back(num1 - num2);
                        } else {
                            result.emplace_back(num1 * num2);
                        }
                    }
                }
            }
        }
        // If the input string contains only number.
        if (result.empty()) {
            result.emplace_back(stoi(input));
        }
        return result;
    }
};
<commit_msg>Update different-ways-to-add-parentheses.cpp<commit_after>// Time:  O(n * (C(2n, n) - C(2n, n - 1))), at most time
// Space: O(n * (C(2n, n) - C(2n, n - 1)))

class Solution {
  public:
    vector<int> diffWaysToCompute(string input) {
        vector<vector<vector<int>>> lookup(input.length() + 1,
                                           vector<vector<int>>(input.length() + 1, vector<int>()));
        return diffWaysToComputeRecu(input, 0, input.length(), lookup);
    }

    vector<int> diffWaysToComputeRecu(const string& input,
                                      const int start, const int end,
                                      vector<vector<vector<int>>>& lookup) {
        if (!lookup[start][end].empty()) {
            return lookup[start][end];
        }
        vector<int> result;
        for (int i = start; i < end; ++i) {
            const auto cur = input[i];
            if (cur == '+' || cur == '-' || cur == '*') {
                vector<int> left = move(diffWaysToComputeRecu(input, start, i, lookup));
                vector<int> right = move(diffWaysToComputeRecu(input, i + 1, end, lookup));
                for (const auto& num1 : left) {
                    for (const auto& num2 : right) {
                        if (cur == '+') {
                            result.emplace_back(num1 + num2);
                        } else if (cur == '-') {
                            result.emplace_back(num1 - num2);
                        } else {
                            result.emplace_back(num1 * num2);
                        }
                    }
                }
            }
        }
        // If the input string contains only number.
        if (result.empty()) {
            result.emplace_back(stoi(input.substr(start, end - start)));
        }
        lookup[start][end] = move(result);
        return lookup[start][end];
    }
};

// Time:  O(n * (C(2n, n) - C(2n, n - 1))), at least time
// Space: O(C(2n, n) - C(2n, n - 1))
class Solution2 {
  public:
    vector<int> diffWaysToCompute(string input) {
        vector<int> result;
        for (int i = 0; i < input.size(); ++i) {
            const auto cur = input[i];
            if (cur == '+' || cur == '-' || cur == '*') {
                vector<int> left = move(diffWaysToCompute(input.substr(0, i)));
                vector<int> right = move(diffWaysToCompute(input.substr(i + 1)));
                for (const auto& num1 : left) {
                    for (const auto& num2 : right) {
                        if (cur == '+') {
                            result.emplace_back(num1 + num2);
                        } else if (cur == '-') {
                            result.emplace_back(num1 - num2);
                        } else {
                            result.emplace_back(num1 * num2);
                        }
                    }
                }
            }
        }
        // If the input string contains only number.
        if (result.empty()) {
            result.emplace_back(stoi(input));
        }
        return result;
    }
};
<|endoftext|>


<commit_before><commit_msg>Using unique_ptr for search<commit_after><|endoftext|>


<commit_before>#include "amuse/Engine.hpp"
#include "amuse/Voice.hpp"
#include "amuse/Submix.hpp"
#include "amuse/Sequencer.hpp"
#include "amuse/IBackendVoice.hpp"
#include "amuse/IBackendVoiceAllocator.hpp"
#include "amuse/AudioGroupData.hpp"
#include "amuse/AudioGroup.hpp"
#include "amuse/Common.hpp"

namespace amuse
{

Engine::Engine(IBackendVoiceAllocator& backend)
: m_backend(backend)
{}

std::shared_ptr<Voice> Engine::_allocateVoice(const AudioGroup& group, double sampleRate,
                                              bool dynamicPitch, bool emitter, Submix* smx)
{
    auto it = m_activeVoices.emplace(m_activeVoices.end(), new Voice(*this, group, m_nextVid++, emitter, smx));
    m_activeVoices.back()->m_backendVoice =
        m_backend.allocateVoice(*m_activeVoices.back(), sampleRate, dynamicPitch);
    m_activeVoices.back()->m_engineIt = it;
    return m_activeVoices.back();
}

Submix* Engine::_allocateSubmix(Submix* smx)
{
    auto it = m_activeSubmixes.emplace(m_activeSubmixes.end(), *this, smx);
    m_activeSubmixes.back().m_backendSubmix = m_backend.allocateSubmix(m_activeSubmixes.back());
    m_activeSubmixes.back().m_engineIt = it;
    return &m_activeSubmixes.back();
}

std::list<std::shared_ptr<Voice>>::iterator Engine::_destroyVoice(Voice* voice)
{
#ifndef NDEBUG
    assert(this == &voice->getEngine());
#endif
    voice->_destroy();
    return m_activeVoices.erase(voice->m_engineIt);
}

std::list<Submix>::iterator Engine::_destroySubmix(Submix* smx)
{
#ifndef NDEBUG
    assert(this == &smx->getEngine());
#endif
    smx->_destroy();
    return m_activeSubmixes.erase(smx->m_engineIt);
}

void Engine::_bringOutYourDead()
{
    for (auto it = m_activeEmitters.begin() ; it != m_activeEmitters.end() ;)
    {
        Emitter* emitter = it->get();
        if (emitter->getVoice()->m_voxState == VoiceState::Finished)
        {
            emitter->_destroy();
            it = m_activeEmitters.erase(it);
        }
    }

    for (auto it = m_activeVoices.begin() ; it != m_activeVoices.end() ;)
    {
        Voice* vox = it->get();
        vox->_bringOutYourDead();
        if (vox->m_voxState == VoiceState::Finished)
        {
            it = _destroyVoice(vox);
            continue;
        }
        ++it;
    }
}

/** Update all active audio entities and fill OS audio buffers as needed */
void Engine::pumpEngine()
{
    m_backend.pumpAndMixVoices();
    _bringOutYourDead();

    /* Determine lowest available free vid */
    int maxVid = -1;
    for (std::shared_ptr<Voice>& vox : m_activeVoices)
        maxVid = std::max(maxVid, vox->maxVid());
    m_nextVid = maxVid + 1;
}

/** Add audio group data pointers to engine; must remain resident! */
const AudioGroup* Engine::addAudioGroup(int groupId, const AudioGroupData& data)
{
    std::unique_ptr<AudioGroup> grp = std::make_unique<AudioGroup>(groupId, data);
    if (!grp)
        return nullptr;
    AudioGroup* ret = grp.get();
    m_audioGroups.emplace(std::make_pair(groupId, std::move(grp)));

    /* setup SFX index for contained objects */
    for (const auto& pair : ret->getProj().sfxGroups())
    {
        const SFXGroupIndex& sfxGroup = pair.second;
        m_sfxLookup.reserve(m_sfxLookup.size() + sfxGroup.m_sfxEntries.size());
        for (const auto& pair : sfxGroup.m_sfxEntries)
            m_sfxLookup[pair.first] = std::make_pair(ret, pair.second->objId);
    }

    return ret;
}

/** Remove audio group from engine */
void Engine::removeAudioGroup(int groupId)
{
    auto search = m_audioGroups.find(groupId);
    if (search == m_audioGroups.end())
        return;
    AudioGroup* grp = search->second.get();

    /* Destroy runtime entities within group */
    for (auto it = m_activeVoices.begin() ; it != m_activeVoices.end() ;)
    {
        Voice* vox = it->get();
        if (vox->getAudioGroup().groupId() == groupId)
        {
            vox->_destroy();
            it = m_activeVoices.erase(it);
            continue;
        }
        ++it;
    }

    for (auto it = m_activeEmitters.begin() ; it != m_activeEmitters.end() ;)
    {
        Emitter* emitter = it->get();
        if (emitter->getAudioGroup().groupId() == groupId)
        {
            emitter->_destroy();
            it = m_activeEmitters.erase(it);
            continue;
        }
        ++it;
    }

    for (auto it = m_activeSequencers.begin() ; it != m_activeSequencers.end() ;)
    {
        Sequencer* seq = it->get();
        if (seq->getAudioGroup().groupId() == groupId)
        {
            seq->_destroy();
            it = m_activeSequencers.erase(it);
            continue;
        }
        ++it;
    }

    /* teardown SFX index for contained objects */
    for (const auto& pair : grp->getProj().sfxGroups())
    {
        const SFXGroupIndex& sfxGroup = pair.second;
        for (const auto& pair : sfxGroup.m_sfxEntries)
            m_sfxLookup.erase(pair.first);
    }

    m_audioGroups.erase(groupId);
}

/** Create new Submix (a.k.a 'Studio') within root mix engine */
Submix* Engine::addSubmix(Submix* smx)
{
    return _allocateSubmix(smx);
}

/** Remove Submix and deallocate */
void Engine::removeSubmix(Submix* smx)
{
    /* Delete all voices bound to submix */
    for (auto it = m_activeVoices.begin() ; it != m_activeVoices.end() ;)
    {
        Voice* vox = it->get();

        Submix* vsmx = vox->getSubmix();
        if (vsmx && vsmx == smx)
        {
            vox->_destroy();
            it = m_activeVoices.erase(it);
            continue;
        }
        ++it;
    }

    /* Delete all submixes bound to submix */
    for (auto it = m_activeSubmixes.begin() ; it != m_activeSubmixes.end() ;)
    {
        Submix* ssmx = it->getParentSubmix();
        if (ssmx && ssmx == smx)
        {
            it->_destroy();
            it = m_activeSubmixes.erase(it);
            continue;
        }
        ++it;
    }

    /* Delete submix */
    _destroySubmix(smx);
}

/** Start soundFX playing from loaded audio groups */
std::shared_ptr<Voice> Engine::fxStart(int sfxId, float vol, float pan, Submix* smx)
{
    auto search = m_sfxLookup.find(sfxId);
    if (search == m_sfxLookup.end())
        return nullptr;

    AudioGroup* grp = search->second.first;
    if (!grp)
        return nullptr;

    std::shared_ptr<Voice> ret = _allocateVoice(*grp, 32000.0, true, false, smx);
    if (!ret->loadSoundMacro(search->second.second, 0, 1000.f, 0x3c, 0, 0))
    {
        _destroyVoice(ret.get());
        return {};
    }
    ret->setVolume(vol);
    ret->setPan(pan);
    return ret;
}

/** Start soundFX playing from loaded audio groups, attach to positional emitter */
std::shared_ptr<Emitter> Engine::addEmitter(const Vector3f& pos, const Vector3f& dir, float maxDist,
                                            float falloff, int sfxId, float minVol, float maxVol, Submix* smx)
{
    auto search = m_sfxLookup.find(sfxId);
    if (search == m_sfxLookup.end())
        return nullptr;

    AudioGroup* grp = search->second.first;
    if (!grp)
        return nullptr;

    std::shared_ptr<Voice> vox = _allocateVoice(*grp, 32000.0, true, true, smx);
    m_activeEmitters.emplace(m_activeEmitters.end(), new Emitter(*this, *grp, std::move(vox)));
    Emitter& ret = *m_activeEmitters.back();
    if (!ret.getVoice()->loadSoundMacro(search->second.second, 0, 1000.f, 0x3c, 0, 0))
    {
        ret._destroy();
        m_activeEmitters.pop_back();
        return {};
    }
    ret.setPos(pos);
    ret.setDir(dir);
    ret.setMaxDist(maxDist);
    ret.setFalloff(falloff);
    ret.setMinVol(minVol);
    ret.setMaxVol(maxVol);

    return m_activeEmitters.back();
}

/** Start song playing from loaded audio groups */
std::shared_ptr<Sequencer> Engine::seqPlay(int groupId, int songId, const unsigned char* arrData)
{
    return {};
}

/** Find voice from VoiceId */
std::shared_ptr<Voice> Engine::findVoice(int vid)
{
    for (std::shared_ptr<Voice>& vox : m_activeVoices)
    {
        std::shared_ptr<Voice> ret = vox->_findVoice(vid, vox);
        if (ret)
            return ret;
    }
    return {};
}

/** Stop all voices in `kg`, stops immediately (no KeyOff) when `flag` set */
void Engine::killKeygroup(uint8_t kg, bool now)
{
    for (auto it = m_activeVoices.begin() ; it != m_activeVoices.end() ;)
    {
        Voice* vox = it->get();
        if (vox->m_keygroup == kg)
        {
            if (now)
            {
                it = _destroyVoice(vox);
                continue;
            }
            vox->keyOff();
        }
        ++it;
    }
}

/** Send all voices using `macroId` the message `val` */
void Engine::sendMacroMessage(ObjectId macroId, int32_t val)
{
    for (auto it = m_activeVoices.begin() ; it != m_activeVoices.end() ; ++it)
    {
        Voice* vox = it->get();
        if (vox->getObjectId() == macroId)
            vox->message(val);
    }
}

}
<commit_msg>Fix iterator fail<commit_after>#include "amuse/Engine.hpp"
#include "amuse/Voice.hpp"
#include "amuse/Submix.hpp"
#include "amuse/Sequencer.hpp"
#include "amuse/IBackendVoice.hpp"
#include "amuse/IBackendVoiceAllocator.hpp"
#include "amuse/AudioGroupData.hpp"
#include "amuse/AudioGroup.hpp"
#include "amuse/Common.hpp"

namespace amuse
{

Engine::Engine(IBackendVoiceAllocator& backend)
: m_backend(backend)
{}

std::shared_ptr<Voice> Engine::_allocateVoice(const AudioGroup& group, double sampleRate,
                                              bool dynamicPitch, bool emitter, Submix* smx)
{
    auto it = m_activeVoices.emplace(m_activeVoices.end(), new Voice(*this, group, m_nextVid++, emitter, smx));
    m_activeVoices.back()->m_backendVoice =
        m_backend.allocateVoice(*m_activeVoices.back(), sampleRate, dynamicPitch);
    m_activeVoices.back()->m_engineIt = it;
    return m_activeVoices.back();
}

Submix* Engine::_allocateSubmix(Submix* smx)
{
    auto it = m_activeSubmixes.emplace(m_activeSubmixes.end(), *this, smx);
    m_activeSubmixes.back().m_backendSubmix = m_backend.allocateSubmix(m_activeSubmixes.back());
    m_activeSubmixes.back().m_engineIt = it;
    return &m_activeSubmixes.back();
}

std::list<std::shared_ptr<Voice>>::iterator Engine::_destroyVoice(Voice* voice)
{
#ifndef NDEBUG
    assert(this == &voice->getEngine());
#endif
    voice->_destroy();
    return m_activeVoices.erase(voice->m_engineIt);
}

std::list<Submix>::iterator Engine::_destroySubmix(Submix* smx)
{
#ifndef NDEBUG
    assert(this == &smx->getEngine());
#endif
    smx->_destroy();
    return m_activeSubmixes.erase(smx->m_engineIt);
}

void Engine::_bringOutYourDead()
{
    for (auto it = m_activeEmitters.begin() ; it != m_activeEmitters.end() ;)
    {
        Emitter* emitter = it->get();
        if (emitter->getVoice()->m_voxState == VoiceState::Finished)
        {
            emitter->_destroy();
            it = m_activeEmitters.erase(it);
            continue;
        }
        ++it;
    }

    for (auto it = m_activeVoices.begin() ; it != m_activeVoices.end() ;)
    {
        Voice* vox = it->get();
        vox->_bringOutYourDead();
        if (vox->m_voxState == VoiceState::Finished)
        {
            it = _destroyVoice(vox);
            continue;
        }
        ++it;
    }
}

/** Update all active audio entities and fill OS audio buffers as needed */
void Engine::pumpEngine()
{
    m_backend.pumpAndMixVoices();
    _bringOutYourDead();

    /* Determine lowest available free vid */
    int maxVid = -1;
    for (std::shared_ptr<Voice>& vox : m_activeVoices)
        maxVid = std::max(maxVid, vox->maxVid());
    m_nextVid = maxVid + 1;
}

/** Add audio group data pointers to engine; must remain resident! */
const AudioGroup* Engine::addAudioGroup(int groupId, const AudioGroupData& data)
{
    std::unique_ptr<AudioGroup> grp = std::make_unique<AudioGroup>(groupId, data);
    if (!grp)
        return nullptr;
    AudioGroup* ret = grp.get();
    m_audioGroups.emplace(std::make_pair(groupId, std::move(grp)));

    /* setup SFX index for contained objects */
    for (const auto& pair : ret->getProj().sfxGroups())
    {
        const SFXGroupIndex& sfxGroup = pair.second;
        m_sfxLookup.reserve(m_sfxLookup.size() + sfxGroup.m_sfxEntries.size());
        for (const auto& pair : sfxGroup.m_sfxEntries)
            m_sfxLookup[pair.first] = std::make_pair(ret, pair.second->objId);
    }

    return ret;
}

/** Remove audio group from engine */
void Engine::removeAudioGroup(int groupId)
{
    auto search = m_audioGroups.find(groupId);
    if (search == m_audioGroups.end())
        return;
    AudioGroup* grp = search->second.get();

    /* Destroy runtime entities within group */
    for (auto it = m_activeVoices.begin() ; it != m_activeVoices.end() ;)
    {
        Voice* vox = it->get();
        if (vox->getAudioGroup().groupId() == groupId)
        {
            vox->_destroy();
            it = m_activeVoices.erase(it);
            continue;
        }
        ++it;
    }

    for (auto it = m_activeEmitters.begin() ; it != m_activeEmitters.end() ;)
    {
        Emitter* emitter = it->get();
        if (emitter->getAudioGroup().groupId() == groupId)
        {
            emitter->_destroy();
            it = m_activeEmitters.erase(it);
            continue;
        }
        ++it;
    }

    for (auto it = m_activeSequencers.begin() ; it != m_activeSequencers.end() ;)
    {
        Sequencer* seq = it->get();
        if (seq->getAudioGroup().groupId() == groupId)
        {
            seq->_destroy();
            it = m_activeSequencers.erase(it);
            continue;
        }
        ++it;
    }

    /* teardown SFX index for contained objects */
    for (const auto& pair : grp->getProj().sfxGroups())
    {
        const SFXGroupIndex& sfxGroup = pair.second;
        for (const auto& pair : sfxGroup.m_sfxEntries)
            m_sfxLookup.erase(pair.first);
    }

    m_audioGroups.erase(groupId);
}

/** Create new Submix (a.k.a 'Studio') within root mix engine */
Submix* Engine::addSubmix(Submix* smx)
{
    return _allocateSubmix(smx);
}

/** Remove Submix and deallocate */
void Engine::removeSubmix(Submix* smx)
{
    /* Delete all voices bound to submix */
    for (auto it = m_activeVoices.begin() ; it != m_activeVoices.end() ;)
    {
        Voice* vox = it->get();

        Submix* vsmx = vox->getSubmix();
        if (vsmx && vsmx == smx)
        {
            vox->_destroy();
            it = m_activeVoices.erase(it);
            continue;
        }
        ++it;
    }

    /* Delete all submixes bound to submix */
    for (auto it = m_activeSubmixes.begin() ; it != m_activeSubmixes.end() ;)
    {
        Submix* ssmx = it->getParentSubmix();
        if (ssmx && ssmx == smx)
        {
            it->_destroy();
            it = m_activeSubmixes.erase(it);
            continue;
        }
        ++it;
    }

    /* Delete submix */
    _destroySubmix(smx);
}

/** Start soundFX playing from loaded audio groups */
std::shared_ptr<Voice> Engine::fxStart(int sfxId, float vol, float pan, Submix* smx)
{
    auto search = m_sfxLookup.find(sfxId);
    if (search == m_sfxLookup.end())
        return nullptr;

    AudioGroup* grp = search->second.first;
    if (!grp)
        return nullptr;

    std::shared_ptr<Voice> ret = _allocateVoice(*grp, 32000.0, true, false, smx);
    if (!ret->loadSoundMacro(search->second.second, 0, 1000.f, 0x3c, 0, 0))
    {
        _destroyVoice(ret.get());
        return {};
    }
    ret->setVolume(vol);
    ret->setPan(pan);
    return ret;
}

/** Start soundFX playing from loaded audio groups, attach to positional emitter */
std::shared_ptr<Emitter> Engine::addEmitter(const Vector3f& pos, const Vector3f& dir, float maxDist,
                                            float falloff, int sfxId, float minVol, float maxVol, Submix* smx)
{
    auto search = m_sfxLookup.find(sfxId);
    if (search == m_sfxLookup.end())
        return nullptr;

    AudioGroup* grp = search->second.first;
    if (!grp)
        return nullptr;

    std::shared_ptr<Voice> vox = _allocateVoice(*grp, 32000.0, true, true, smx);
    m_activeEmitters.emplace(m_activeEmitters.end(), new Emitter(*this, *grp, std::move(vox)));
    Emitter& ret = *m_activeEmitters.back();
    if (!ret.getVoice()->loadSoundMacro(search->second.second, 0, 1000.f, 0x3c, 0, 0))
    {
        ret._destroy();
        m_activeEmitters.pop_back();
        return {};
    }
    ret.setPos(pos);
    ret.setDir(dir);
    ret.setMaxDist(maxDist);
    ret.setFalloff(falloff);
    ret.setMinVol(minVol);
    ret.setMaxVol(maxVol);

    return m_activeEmitters.back();
}

/** Start song playing from loaded audio groups */
std::shared_ptr<Sequencer> Engine::seqPlay(int groupId, int songId, const unsigned char* arrData)
{
    return {};
}

/** Find voice from VoiceId */
std::shared_ptr<Voice> Engine::findVoice(int vid)
{
    for (std::shared_ptr<Voice>& vox : m_activeVoices)
    {
        std::shared_ptr<Voice> ret = vox->_findVoice(vid, vox);
        if (ret)
            return ret;
    }
    return {};
}

/** Stop all voices in `kg`, stops immediately (no KeyOff) when `flag` set */
void Engine::killKeygroup(uint8_t kg, bool now)
{
    for (auto it = m_activeVoices.begin() ; it != m_activeVoices.end() ;)
    {
        Voice* vox = it->get();
        if (vox->m_keygroup == kg)
        {
            if (now)
            {
                it = _destroyVoice(vox);
                continue;
            }
            vox->keyOff();
        }
        ++it;
    }
}

/** Send all voices using `macroId` the message `val` */
void Engine::sendMacroMessage(ObjectId macroId, int32_t val)
{
    for (auto it = m_activeVoices.begin() ; it != m_activeVoices.end() ; ++it)
    {
        Voice* vox = it->get();
        if (vox->getObjectId() == macroId)
            vox->message(val);
    }
}

}
<|endoftext|>