text:
/* This file is part of the Tomographer project, which is distributed under the
 * terms of the MIT license.
 *
 * The MIT License (MIT)
 *
 * Copyright (c) 2016 ETH Zurich, Institute for Theoretical Physics, Philippe Faist
 * Copyright (c) 2017 Caltech, Institute for Quantum Information and Matter, Philippe Faist
 *
 * Permission is hereby granted, free of charge, to any person obtaining a copy
 * of this software and associated documentation files (the "Software"), to deal
 * in the Software without restriction, including without limitation the rights
 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
 * copies of the Software, and to permit persons to whom the Software is
 * furnished to do so, subject to the following conditions:
 *
 * The above copyright notice and this permission notice shall be included in
 * all copies or substantial portions of the Software.
 *
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
 * SOFTWARE.
 */

#include <cmath>

#include <string>
#include <iostream>
#include <random>

#include <boost/math/constants/constants.hpp>

// definitions for Tomographer test framework -- this must be included before any
// <Eigen/...> or <tomographer/...> header
#include "test_tomographer.h"

#include <tomographer/mathtools/solveclyap.h>
#include <tomographer/tools/eigenutil.h> // denseRandom
#include <tomographer/tools/loggers.h>
#include <tomographer/mathtools/random_unitary.h>

#include <tomographer/tools/boost_test_logger.h>

// -----------------------------------------------------------------------------
// fixture(s)

// template<typename MatrixType_, typename Rng_>
// class RandomPosSemiDef
// {
// public:
//   typedef MatrixType_ MatrixType;
//   typedef typename MatrixType::Scalar Scalar;
//   typedef typename Eigen::NumTraits<Scalar>::Real RealScalar;
//   typedef typename MatrixType::Index IndexType;
//   typedef Eigen::Matrix<RealScalar, Eigen::Dynamic, 1> RealVectorType;

//   typedef Rng_ Rng;

// private:
//   Rng & _rng;
//   IndexType _dim;

//   MatrixType _U;
//   RealVectorType _diag;

// public:
//   RandomPosSemiDef(Rng & rng, IndexType dim)
//     : _rng(rng), _dim(dim), _U(dim, dim), _diag(dim)
//   {
//   }

//   MatrixType withUnifEig(RealScalar max_eigenval = RealScalar(1),
// 			 IndexType max_rank = std::numeric_limits<IndexType>::max())
//   {
//     std::uniform_real_distribution<RealScalar> dist(0, max_eigenval);

//     Tomographer::MathTools::randomUnitary<MatrixType>(_U, _rng);

//     _diag = Tomographer::Tools::denseRandom<Eigen::VectorXd>(_rng, dist, _dim);

//     for (int i = max_rank; i < _dim; ++i) {
//       _diag(i) = 0;
//     }

//     // this is positive semidefinite.
//     return _U*_diag.asDiagonal()*_U.adjoint();
//   }

//   inline const MatrixType & lastU() const { return _U; }
//   inline const RealVectorType & lastDiag() const { return _diag; }

// };

struct test_solveclyap_fixture
{
  template<typename Rng>
  void do_test(Rng & rng, int d, int A_rank)
  {
    typedef Eigen::MatrixXcd MatType;

    std::uniform_real_distribution<double> dist(0.0, 1.0);

    MatType U(d,d);
    Tomographer::MathTools::randomUnitary<MatType>(U, rng);
    MatType W(U.block(0,0,d,A_rank));

    Eigen::VectorXd eigvals(Tomographer::Tools::denseRandom<Eigen::VectorXd>(rng, dist, A_rank));
    // this is positive semidefinite.
    MatType A(W * eigvals.asDiagonal() * W.adjoint());

    BOOST_MESSAGE("A = " << A) ;

    // create a random X in the support of A
    // MatType X(W * RandomPosSemiDef<MatType, std::mt19937>(rng, A_rank).withUnifEig(1.0, A_rank) * W.adjoint());
    MatType X(W * Tomographer::Tools::denseRandom<MatType>(rng, dist, A_rank, A_rank) * W.adjoint());

    BOOST_MESSAGE("X = " << X) ;

    const MatType C(A.adjoint()*X + X*A);

    BOOST_MESSAGE("--> C = " << C) ;

    MatType X2(d,d);

    Tomographer::Logger::BoostTestLogger logger(Tomographer::Logger::DEBUG);

    Tomographer::MathTools::SolveCLyap::solve<true>(X2, A, C, logger, 1e-8);

    MY_BOOST_CHECK_EIGEN_EQUAL(X, X2, 1e-8);
  }
};

// -----------------------------------------------------------------------------
// test suites

BOOST_FIXTURE_TEST_SUITE(test_mathtools_solveclyap, test_solveclyap_fixture)

BOOST_AUTO_TEST_CASE(random_test_7_4)
{
  std::mt19937 rng(4938221);

  const int d = 7; // dimension of problem
  const int A_rank = 4; // rank of A
  for (int repeat = 0; repeat < 1000; ++repeat) {
    BOOST_MESSAGE("Repeat : iteration #" << repeat) ;
    do_test(rng, d, A_rank);
  }
}

BOOST_AUTO_TEST_CASE(random_test_15_15)
{
  std::mt19937 rng(89120);

  const int d = 15; // dimension of problem
  const int A_rank = 15; // rank of A

  for (int repeat = 0; repeat < 100; ++repeat) {
    BOOST_MESSAGE("Repeat : iteration #" << repeat) ;
    do_test(rng, d, A_rank);
  }
}

BOOST_AUTO_TEST_SUITE_END()

max_stars_repo_name: Tomographer/tomographer

max_issues_repo_name: Tomographer/tomographer

max_forks_repo_name: Tomographer/tomographer


text:
// Copyright (c) 2015 Object Computing, Inc.
// All rights reserved.
// See the file license.txt for licensing information.
#include <Steps/StepPch.hpp>
#define BOOST_TEST_NO_MAIN StepsPerformance
#include <boost/test/unit_test.hpp>

#include <StepLibrary/MockMessageProducer.hpp>
#include <StepLibrary/MockMessageConsumer.hpp>

#include <StepLibrary/InputQueue.hpp>
#include <StepLibrary/SendToQueue.hpp>
#include <StepLibrary/CopyPassThru.hpp>
#include <StepLibrary/ForwardPassThru.hpp>
#include <StepLibrary/BinaryPassThru.hpp>

#include <Common/Stopwatch.hpp>
#include <Common/Stopwatch.hpp>
#include <Mocks/MockMessage.hpp>

using namespace HighQueue;
using namespace Steps;
namespace
{
    typedef MediumMockMessage ActualMessage;
    auto messageBytes = sizeof(ActualMessage);

    typedef MockMessageProducer<ActualMessage> ProducerType;
    typedef std::shared_ptr<ProducerType> ProducerPtr;

    typedef MockMessageConsumer<ActualMessage> ConsumerType;
    typedef std::shared_ptr<ConsumerType> ConsumerPtr;

#if 0
    typedef CopyPassThru<ActualMessage> CopierType;
#elif 0
    typedef BinaryPassThru CopierType;
#else
    typedef ForwardPassThru CopierType;
#endif
    typedef std::shared_ptr<CopierType> CopierPtr;
}

#define ENABLE_PIPELINE_TEST 0
#if ENABLE_PIPELINE_TEST
BOOST_AUTO_TEST_CASE(testPipeline)
{
    std::cout << "Queued Pipeline Test" << std::endl;
    size_t entryCount = 100000;
    size_t messageSize = sizeof(ActualMessage);
#if defined(_DEBUG)
    uint32_t messageCount = 10;
#else // _DEBUG
    uint32_t messageCount = 100000000;
#endif // _DEBUG

    const size_t numberOfConsumers = 1;   // Don't change this
    const size_t numberOfProducers = 1;   // Don't change this

    const size_t coreCount = std::thread::hardware_concurrency();
    const int32_t fudgeCopiers = 0; // if you want to see the clients fighting for cores, make this positive
    int32_t numberOfCopiers = int32_t(coreCount) - (numberOfConsumers + numberOfProducers) + fudgeCopiers;
    if(numberOfCopiers <= 0)
    {
        numberOfCopiers = 0;
        numberOfCopiers = 1; // for now, we always want at least one.
    }

    const size_t queueCount = numberOfCopiers + numberOfConsumers; // need a pool for each object that can receive messages
    // how many buffers do we need?
    size_t extraMessages = 0; // in case we need it someday (YAGNI)
    const size_t messagesNeeded = entryCount * queueCount + numberOfConsumers + numberOfCopiers + numberOfProducers + extraMessages;

    const size_t spinCount = 0;
    const size_t yieldCount = 0;
    const size_t sleepCount = WaitStrategy::FOREVER;
    const auto sleepTime = std::chrono::nanoseconds(10);
    WaitStrategy strategy(spinCount, yieldCount, sleepCount, sleepTime);

    bool discardMessagesIfNoConsumer = false;
    CreationParameters parameters(strategy, strategy, discardMessagesIfNoConsumer, entryCount, messageSize, messagesNeeded);
    MemoryPoolPtr memoryPool(new MemoryPool(messageSize, messagesNeeded));

    std::vector<ConnectionPtr> connections;
    for(size_t nConn = 0; nConn < queueCount; ++nConn)
    {
        std::shared_ptr<Connection> connection(new Connection);
        connections.push_back(connection);
        std::stringstream name;
        name << "Connection " << nConn;
        connection->createLocal(name.str(), parameters, memoryPool);
    }

    volatile bool producerGo = false;

    std::vector <StepPtr> steps;

    auto producer = std::make_shared<ProducerType>(&producerGo, messageCount, 1);
    producer->attachMemoryPool(memoryPool);
    steps.emplace_back(producer);

    auto producerPublisher = std::make_shared<SendToQueue>();
    producerPublisher->attachConnection(connections[0]);
    producer->attachDestination(producerPublisher);
    steps.emplace_back(producerPublisher);

    std::vector<CopierPtr> copiers;
    for(size_t nCopier = 1; nCopier < connections.size(); ++nCopier)
    {
        auto copyConsumer = std::make_shared<InputQueue>();
        copyConsumer->attachConnection(connections[nCopier-1]);
        steps.emplace_back(copyConsumer);

        auto copyPublisher = std::make_shared<SendToQueue>();
        copyPublisher->attachConnection(connections[nCopier]);
        copyConsumer->attachDestination(copyPublisher);
        steps.emplace_back(copyPublisher);
    }

    auto finalConsumer = std::make_shared<InputQueue>();
    finalConsumer->attachConnection(connections.back());
    steps.emplace_back(finalConsumer);

    auto consumer = std::make_shared<ConsumerType>(0);
    finalConsumer->attachDestination(consumer);

    // All wired up, ready to go.  Wait for the threads to initialize.
    for(auto & step : steps)
    {
        step->validate();
    }

    for(auto & step : steps)
    {
        step->start();
    }

    Stopwatch timer;
    producerGo = true;
    while(!consumer->isStopping())
    {
        std::this_thread::yield();
    }
    auto lapse = timer.nanoseconds();

    for(auto step : steps)
    {
        step->stop();
    }

    for(auto step : steps)
    {
        step->finish();
    }

    std::cout << "Steped Pipeline " << (numberOfProducers + numberOfCopiers + numberOfConsumers) << " step: ";
    std::cout << " Passed " << messageCount << ' ' << messageBytes << " byte messages in "
            << std::setprecision(9) << double(lapse) / double(Stopwatch::nanosecondsPerSecond) << " seconds.  ";
    if(lapse == 0)
    {
        std::cout << "Run time too short to measure.   Use a larger messageCount" << std::endl;
    }
    else
    {
        std::cout
            << lapse / messageCount << " nsec./message "
            << std::setprecision(3) << double(messageCount * 1000) / double(lapse) << " MMsg/second "
            << std::endl;
    }
}
#endif // ENABLE_PIPELINE_TEST

#define ENABLE_DIRECT_PIPELINE_TEST 0
#if ENABLE_DIRECT_PIPELINE_TEST
BOOST_AUTO_TEST_CASE(testDirectPipeline)
{
    std::cout << "Direct Pipeline Test" << std::endl;
    size_t messageSize = sizeof(ActualMessage);
#if defined(_DEBUG)
    uint32_t messageCount = 10;
#else // _DEBUG
    uint32_t messageCount = 100000000;
#endif // _DEBUG

    const size_t numberOfConsumers = 1;   // Don't change this
    const size_t numberOfProducers = 1;   // Don't change this

    int32_t numberOfCopiers = 6; // pick a number, any number

    // how many buffers do we need?
    size_t extraMessages = 0; // in case we need it someday (YAGNI)
    const size_t messagesNeeded = numberOfCopiers + numberOfProducers + extraMessages;

    MemoryPoolPtr memoryPool(new MemoryPool(messageSize, messagesNeeded));

    volatile bool producerGo = false;
    auto producer = std::make_shared<ProducerType>(&producerGo, messageCount, 1);
    producer->attachMemoryPool(memoryPool);

    StepPtr previous = producer;

    std::vector<CopierPtr> copiers;
    for(size_t nCopier = 0; nCopier < numberOfCopiers; ++nCopier)
    {
        copiers.emplace_back(new CopierType());
        auto & copier = copiers.back();
        copier->attachMemoryPool(memoryPool);
        previous->attachDestination(copier);
        previous = copier;
    }
    auto consumer = std::make_shared<ConsumerType>(0);
    previous->attachDestination(consumer);

    // All wired up.  See if everybody is happy
    producer->validate();
    for(auto & copier : copiers)
    {
        copier->validate();
    }
    consumer->validate();

    // turn everything on
    producer->start();
    for(auto & copier : copiers)
    {
        copier->start();
    }
    consumer->start();

    Stopwatch timer;
    producerGo = true;
    while(!consumer->isStopping())
    {
        std::this_thread::yield();
    }
    auto lapse = timer.nanoseconds();

    producer->stop();
    for(auto copier : copiers)
    {
        copier->stop();
    }

    producer->finish();
    for(auto & copier : copiers)
    {
        copier->finish();
    }
    consumer->finish();

    std::cout << "Direct Pipeline " << (numberOfProducers + numberOfCopiers + numberOfConsumers) << " step: ";
    std::cout << " Passed " << messageCount << ' ' << messageBytes << " byte messages in "
        << std::setprecision(9) << double(lapse) / double(Stopwatch::nanosecondsPerSecond) << " seconds.  ";
    if(lapse == 0)
    {
        std::cout << "Run time too short to measure.   Use a larger messageCount" << std::endl;
    }
    else
    {
        std::cout
            << lapse / messageCount << " nsec./message "
            << std::setprecision(3) << double(messageCount * 1000) / double(lapse) << " MMsg/second "
            << std::endl;
    }
}
#endif // ENABLE_DIRECT_PIPELINE_TEST

ext: cpp

max_stars_repo_name: dale-wilson/HSQueue

max_issues_repo_name: dale-wilson/HighQueue

max_forks_repo_name: dale-wilson/HighQueue


text:
/********************************************************************
 * AUTHORS: Vijay Ganesh, Trevor Hansen
 *
 * BEGIN DATE: November, 2005
 *
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:

The above copyright notice and this permission notice shall be included in
all copies or substantial portions of the Software.

THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
THE SOFTWARE.
********************************************************************/

#include "main_common.h"

#include <boost/lexical_cast.hpp>
#include <boost/program_options.hpp>
using boost::lexical_cast;
namespace po = boost::program_options;

#ifdef EXT_HASH_MAP
using namespace __gnu_cxx;
#endif
using namespace BEEV;
using std::auto_ptr;
using std::cout;
using std::cerr;
using std::endl;

namespace BEEV
{
void setHardTimeout(int);
}

/********************************************************************
 * MAIN FUNCTION:
 *
 * step 0. Parse the input into an ASTVec.
 * step 1. Do BV Rewrites
 * step 2. Bitblasts the ASTNode.
 * step 3. Convert to CNF
 * step 4. Convert to SAT
 * step 5. Call SAT to determine if input is SAT or UNSAT
********************************************************************/

class ExtraMain : public Main
{
public:
  void try_parsing_options(int argc, char** argv, po::variables_map& vm,
                           po::positional_options_description& pos_options);
  int create_and_parse_options(int argc, char** argv);
  void create_options();
  int parse_options(int argc, char** argv);

  po::options_description cmdline_options;
  po::options_description visible_options;
  po::positional_options_description pos_options;
};

int ExtraMain::create_and_parse_options(int argc, char** argv)
{
  create_options();
  int ret = parse_options(argc, argv);
  if (ret != 0)
  {
    return ret;
  }
  return 0;
}

void
ExtraMain::try_parsing_options(int argc, char** argv, po::variables_map& vm,
                               po::positional_options_description& pos_options)
{
  try
  {
    po::store(po::command_line_parser(argc, argv)
                  .options(cmdline_options)
                  .positional(pos_options)
                  .run(),
              vm);

    if (vm.count("help"))
    {
      cout << "USAGE: " << argv[0] << " [options] <input-file>" << endl
           << " where input is SMTLIB1/2 or CVC depending on options and file "
              "extension" << endl;

      cout << cmdline_options << endl;
      exit(0);
    }

    po::notify(vm);
  }
  catch (boost::exception_detail::clone_impl<
      boost::exception_detail::error_info_injector<po::unknown_option>>& c)
  {
    cout << "Some option you gave was wrong. Please give '--help' to get help"
         << endl;
    cout << "Unkown option: " << c.what() << endl;
    exit(-1);
  }
  catch (boost::bad_any_cast& e)
  {
    std::cerr << "ERROR! You probably gave a wrong argument type (Bad cast): "
              << e.what() << endl;

    exit(-1);
  }
  catch (boost::exception_detail::clone_impl<
      boost::exception_detail::error_info_injector<po::invalid_option_value>>
             what)
  {
    cerr << "Invalid value '" << what.what() << "'"
         << " given to option '" << what.get_option_name() << "'" << endl;

    exit(-1);
  }
  catch (boost::exception_detail::clone_impl<
      boost::exception_detail::error_info_injector<po::multiple_occurrences>>
             what)
  {
    cerr << "Error: " << what.what() << " of option '" << what.get_option_name()
         << "'" << endl;

    exit(-1);
  }
  catch (boost::exception_detail::clone_impl<
      boost::exception_detail::error_info_injector<po::required_option>> what)
  {
    cerr << "You forgot to give a required option '" << what.get_option_name()
         << "'" << endl;

    exit(-1);
  }
}

void ExtraMain::create_options()
{
  po::options_description hiddenOptions("Hidden options");
  hiddenOptions.add_options()("file", po::value<string>(&infile), "input file");

  // Declare the supported options.
  po::options_description general_options("Most important options");
  general_options.add_options()("help,h", "print this help")(
      "version", "print version number")("disable-simplify",
                                         "disable all simplifications")(
      "switch-word,w", "switch off wordlevel solver")(
      "disable-opt-inc,a", "disable potentially size-increasing optimisations")(
      "disable-cbitp", "disable constant bit propagation")(
      "disable-equality", "disable equality propagation");

  po::options_description solver_options("SAT Solver options");
  solver_options.add_options()("cryptominisat",
                               "use cryptominisat2 as the solver")
#ifdef USE_CRYPTOMINISAT4
      ("cryptominisat4",
       "use cryptominisat4 as the solver. Only use CryptoMiniSat 4.2 or above.")
#endif
      ("simplifying-minisat", "use simplifying-minisat 2.2 as the solver")(
          "minisat", "use minisat 2.2 as the solver");

  po::options_description refinement_options("Refinement options");
  refinement_options.add_options()(
      "oldstyle-refinement",
      "Do abstraction-refinement outside the SAT solver")(
      "ackermanize,r", po::bool_switch(&(bm->UserFlags.ackermannisation)),
      "eagerly encode array-read axioms (Ackermannistaion)")(
      "flatten,x", po::bool_switch(&(bm->UserFlags.xor_flatten_flag)),
      "flatten XORs");

  po::options_description print_options("Printing options");
  print_options.add_options()(
      "print-stpinput,b",
      po::bool_switch(&(bm->UserFlags.print_STPinput_back_flag)),
      "print STP input back to cout")(
      "print-back-CVC",
      po::bool_switch(&(bm->UserFlags.print_STPinput_back_CVC_flag)),
      "print input in CVC format, then exit")(
      "print-back-SMTLIB2",
      po::bool_switch(&(bm->UserFlags.print_STPinput_back_SMTLIB2_flag)),
      "print input in SMT-LIB2 format, then exit")(
      "print-back-SMTLIB1",
      po::bool_switch((&bm->UserFlags.print_STPinput_back_SMTLIB1_flag)),
      "print input in SMT-LIB1 format, then exit")(
      "print-back-GDL",
      po::bool_switch(&(bm->UserFlags.print_STPinput_back_GDL_flag)),
      "print AiSee's graph format, then exit")(
      "print-back-dot",
      po::bool_switch(&(bm->UserFlags.print_STPinput_back_dot_flag)),
      "print dotty/neato's graph format, then exit")(
      "print-counterex,p",
      po::bool_switch(&(bm->UserFlags.print_counterexample_flag)),
      "print counterexample")(
      "print-counterexbin,y",
      po::bool_switch(&(bm->UserFlags.print_binary_flag)),
      "print counterexample in binary")(
      "print-arrayval,q",
      po::bool_switch(&(bm->UserFlags.print_arrayval_declaredorder_flag)),
      "print arrayval declared order")(
      "print-functionstat,s", po::bool_switch(&(bm->UserFlags.stats_flag)),
      "print function statistics")(
      "print-quickstat,t",
      po::bool_switch(&(bm->UserFlags.quick_statistics_flag)),
      "print quick statistics")(
      "print-nodes,v", po::bool_switch(&(bm->UserFlags.print_nodes_flag)),
      "print nodes ")
      /*("constr-counterex,c",
         po::bool_switch(&(bm->UserFlags.construct_counterexample_flag))
          , "construct counterexample")*/
      ("print-varorder,z",
       po::bool_switch(&(bm->UserFlags.print_sat_varorder_flag)),
       "Print SAT variable order")(
          "print-output,n", po::bool_switch(&(bm->UserFlags.print_output_flag)),
          "Print output");

  po::options_description input_options("Input options");
  input_options.add_options()("SMTLIB1,m", "use the SMT-LIB1 format parser")(
      "SMTLIB2", "use the SMT-LIB2 format parser");

  po::options_description output_options("Output options");
  output_options.add_options()(
      "output-CNF", po::bool_switch(&(bm->UserFlags.output_CNF_flag)),
      "save the CNF into output_[0..n].cnf")(
      "output-bench", po::bool_switch(&(bm->UserFlags.output_bench_flag)),
      "save in ABC's bench format to output.bench");

  po::options_description misc_options("Output options");
  misc_options.add_options()("exit-after-CNF",
                             po::bool_switch(&(bm->UserFlags.exit_after_CNF)),
                             "exit after the CNF has been generated")
#ifndef _MSC_VER
      ("timeout,g", po::value<size_t>(&hardTimeout),
       "timeout (seconds until STP gives up)")
#endif
      ("seed,i", po::value<size_t>(&random_seed),
       "set random seed for STP's satisfiable output. Random_seed is an "
       "integer >= 0")("random-seed",
                       "generate a random number for the SAT solver.")(
          "check-sanity,d", "construct counterexample and check it");

  cmdline_options.add(general_options)
      .add(solver_options)
      .add(refinement_options)
      .add(print_options)
      .add(input_options)
      .add(output_options)
      .add(misc_options)
      .add(hiddenOptions);

  // Register everything except hiddenOptions
  visible_options.add(general_options)
      .add(solver_options)
      .add(refinement_options)
      .add(print_options)
      .add(input_options)
      .add(output_options)
      .add(misc_options);

  pos_options.add("file", 1);
}

int ExtraMain::parse_options(int argc, char** argv)
{
  po::variables_map vm;
  try_parsing_options(argc, argv, vm, pos_options);
  onePrintBack = bm->UserFlags.get_print_output_at_all();

  if (vm.count("disable-size"))
  {
    bm->UserFlags.optimize_flag = false;
  }

  if (vm.count("switch-word"))
  {
    bm->UserFlags.wordlevel_solve_flag = false;
  }

  if (vm.count("disable-cbitp"))
  {
    bm->UserFlags.bitConstantProp_flag = false;
  }

  if (vm.count("SMTLIB2"))
  {
    bm->UserFlags.smtlib2_parser_flag = true;
    bm->UserFlags.division_by_zero_returns_one_flag = true;
    if (bm->UserFlags.smtlib1_parser_flag)
    {
      FatalError("Can't use both the smtlib and smtlib2 parsers");
    }
  }

  if (vm.count("SMTLIB1"))
  {
    bm->UserFlags.smtlib1_parser_flag = true;
    bm->UserFlags.division_by_zero_returns_one_flag = true;
    if (bm->UserFlags.smtlib2_parser_flag)
    {
      FatalError("Can't use both the smtlib and smtlib2 parsers");
    }
  }

  if (vm.count("simplifying-minisat"))
  {
    bm->UserFlags.solver_to_use = UserDefinedFlags::SIMPLIFYING_MINISAT_SOLVER;
  }

  if (vm.count("minisat"))
  {
    bm->UserFlags.solver_to_use = UserDefinedFlags::MINISAT_SOLVER;
  }

  if (vm.count("cryptominisat"))
  {
    bm->UserFlags.solver_to_use = UserDefinedFlags::CRYPTOMINISAT_SOLVER;
  }

#ifdef USE_CRYPTOMINISAT4
  if (vm.count("cryptominisat4"))
  {
    bm->UserFlags.solver_to_use = UserDefinedFlags::CRYPTOMINISAT4_SOLVER;
  }
#endif

  if (vm.count("cryptominisat")
#ifdef USE_CRYPTOMINISAT4
          + vm.count("cryptominisat4")
#endif
          + vm.count("minisat") + vm.count("simplifying-minisat") >
      1)
  {
    cout << "ERROR: You may only give one solver to use: minisat, "
            "simplifying-minisat, or cryptominisat" << endl;
    exit(-1);
  }

  if (vm.count("gauss"))
  {
    if (bm->UserFlags.solver_to_use != UserDefinedFlags::CRYPTOMINISAT_SOLVER)
    {
      cout << "ERROR: you specified a Gaussian elimination length" << endl
           << "       but you didn't ask cryptominisat to be used" << endl;
      exit(-1);
    }
  }

  if (vm.count("oldstyle-refinement"))
  {
    bm->UserFlags.solver_to_use = UserDefinedFlags::MINISAT_SOLVER;
  }

  if (vm.count("disable-simplifications"))
  {
    bm->UserFlags.disableSimplifications();
  }

  if (vm.count("disable-equality"))
  {
    bm->UserFlags.propagate_equalities = false;
  }

  if (vm.count("random-seed"))
  {
    srand(time(NULL));
    bm->UserFlags.random_seed_flag = true;
    bm->UserFlags.random_seed = rand();
  }

  // TODO this is not actually exposed by original main.cpp code
  if (vm.count("hash-nf"))
  {
    bm->defaultNodeFactory = bm->hashingNodeFactory;
  }

#ifndef _MSC_VER
  if (vm.count("timeout"))
  {
    BEEV::setHardTimeout(hardTimeout);
  }
#endif

  if (vm.count("seed"))
  {
    bm->UserFlags.random_seed_flag = true;
    bm->UserFlags.random_seed = random_seed;
  }

  if (vm.count("constr-check-counterex"))
  {
    bm->UserFlags.construct_counterexample_flag = true;
    bm->UserFlags.check_counterexample_flag = true;
  }

  if (!bm->UserFlags.smtlib1_parser_flag && !bm->UserFlags.smtlib2_parser_flag)
  {
    // No parser is explicity requested.
    check_infile_type();
  }

  if (vm.count("version"))
  {
    cout << "STP version " << get_git_version() << std::endl;
    exit(0);
  }

  return 0;
}

int main(int argc, char** argv)
{
  ExtraMain main;
  return main.main(argc, argv);
}

max_stars_repo_name: delcypher/stp

max_issues_repo_name: delcypher/stp

max_forks_repo_name: delcypher/stp


text:
// ======================================================================
/*!
 * \brief Implementation of QEngine
 */
// ======================================================================

#include "Engine.h"
#include "MetaQueryFilters.h"
#include "RepoManager.h"
#include "Repository.h"
#include "Synchro.h"
#include "WGS84EnvelopeFactory.h"
#include <boost/bind.hpp>
#include <boost/make_shared.hpp>
#include <boost/shared_ptr.hpp>
#include <boost/thread.hpp>
#include <gis/CoordinateTransformation.h>
#include <gis/OGR.h>
#include <gis/SpatialReference.h>
#include <json/reader.h>
#include <macgyver/Exception.h>
#include <macgyver/Hash.h>
#include <macgyver/StringConversion.h>
#include <spine/Convenience.h>
#include <spine/Reactor.h>
#include <chrono>
#include <exception>
#include <iomanip>
#include <libconfig.h++>
#include <ogr_spatialref.h>
#include <system_error>

namespace
{
auto badcoord = std::make_pair(std::numeric_limits<double>::quiet_NaN(),
                               std::numeric_limits<double>::quiet_NaN());
}

namespace SmartMet
{
namespace Engine
{
namespace Querydata
{
namespace
{
ParameterTranslations read_translations(const std::string& configfile)
{
  try
  {
    Json::Reader jsonreader;

    ParameterTranslations translations;

    libconfig::Config config;

    // Enable sensible relative include paths
    boost::filesystem::path p = configfile;
    p.remove_filename();
    config.setIncludeDir(p.c_str());

    config.readFile(configfile.c_str());

    // Establish default language

    std::string language;
    if (config.lookupValue("language", language))
      translations.setDefaultLanguage(language);

    // Read all parameter translations. We assume JSON encoded strings to avoid config file
    // encoding ambiguities. libconfig itself provides no extra Unicode support.

    if (!config.exists("translations"))
      return translations;

    const libconfig::Setting& settings = config.lookup("translations");

    if (!settings.isGroup())
      throw Fmi::Exception(
          BCP, "translations must be a group of parameter name to translations mappings");

    for (int i = 0; i < settings.getLength(); i++)
    {
      const auto& param_settings = settings[i];
      if (!param_settings.isList())
        throw Fmi::Exception(BCP,
                             "translations must be lists of groups consisting of parameter value "
                             "and its translations");

      std::string param_name = param_settings.getName();

      for (int j = 0; j < param_settings.getLength(); j++)
      {
        const auto& value_translations = param_settings[j];

        if (value_translations.isList())
          throw Fmi::Exception(BCP,
                               "translations for parameter " + param_name +
                                   " must be a list of translations for individual values");

        int param_value;
        if (!value_translations.lookupValue("value", param_value))
          throw Fmi::Exception(BCP,
                               "translation setting for " + param_name + " at position " +
                                   std::to_string(j) + " has no parameter value to be translated");

        for (int k = 0; k < value_translations.getLength(); k++)
        {
          const auto& translation = value_translations[k];

          std::string lang = translation.getName();
          if (lang == "value")
            continue;

          auto text = std::string("\"") + translation.c_str() + "\"";
          Json::Value json;
          bool ok = jsonreader.parse(text, json);
          if (!ok || !json.isString())
            throw Fmi::Exception(BCP, "Failed to parse JSON string '" + text + "'");

          translations.addTranslation(param_name, param_value, lang, json.asString());
        }
      }
    }

    return translations;
  }
  catch (const libconfig::ParseException& e)
  {
    throw Fmi::Exception(BCP,
                         "Qengine configuration " + configfile + " error '" +
                             std::string(e.getError()) + "' on line " +
                             std::to_string(e.getLine()));
  }
}

}  // namespace

// ----------------------------------------------------------------------
/*!
 * \brief The only permitted constructor requires a configfile
 */
// ----------------------------------------------------------------------

Engine::Engine(const std::string& configfile)
    : itsRepoManager(boost::make_shared<RepoManager>(configfile)),
      itsConfigFile(configfile),
      itsActiveThreadCount(0),
      itsParameterTranslations(boost::make_shared<ParameterTranslations>()),
      lastConfigErrno(EINPROGRESS)
{
}

// ----------------------------------------------------------------------
/*!
 * \brief Initializator (trivial in this case)
 */
// ----------------------------------------------------------------------
void Engine::init()
{
  try
  {
    itsCoordinateCache.resize(100);
    itsValuesCache.resize(5000);

    itsParameterTranslations =
        boost::make_shared<ParameterTranslations>(read_translations(itsConfigFile));

    auto repomanager = itsRepoManager.load();
    repomanager->init();

    itsSynchro = boost::make_shared<Synchronizer>(this, itsConfigFile);

    // Wait until all initial data has been loaded
    while (!repomanager->ready() && !Spine::Reactor::isShuttingDown())
    {
      boost::this_thread::sleep(boost::posix_time::milliseconds(100));
    }

    // We got this far, assume config file must be valid
    lastConfigErrno = 0;

    // Start watcher thread to watch for configuration changes
    configFileWatcher = boost::thread(&Engine::configFileWatch, this);
  }
  catch (...)
  {
    throw Fmi::Exception::Trace(BCP, "Operation failed!");
  }
}

// ----------------------------------------------------------------------
/*!
 * \brief Watch the config file to change
 * Should be run in a separate thread
 */
// ----------------------------------------------------------------------
void Engine::configFileWatch()
{
  boost::system::error_code ec;
  std::time_t filetime = getConfigModTime();

  while (!Spine::Reactor::isShuttingDown())
  {
    boost::this_thread::sleep_for(boost::chrono::seconds(1));

    // If file was deleted, skip and go waiting until it is back
    if (!boost::filesystem::exists(itsConfigFile, ec))
    {
      if (filetime > 0)
      {
        std::cout << "Querydata config " << itsConfigFile
                  << " removed - current configuration kept until new file appears" << std::endl;
        filetime = 0;
        lastConfigErrno = ENOENT;
      }
      continue;
    }

    std::time_t newfiletime = boost::filesystem::last_write_time(itsConfigFile, ec);

    // Was the file modified?
    if (newfiletime != filetime && !Spine::Reactor::isShuttingDown())
    {
      // File changed
      // Go into cooling period of waiting a few seconds and checking again
      // This assures there are no half completed writes
      lastConfigErrno = EINPROGRESS;

      try
      {
        while (newfiletime != filetime && !Spine::Reactor::isShuttingDown())
        {
          std::cout << Spine::log_time_str() + " Querydata config " + itsConfigFile +
                           " updated, rereading"
                    << std::endl;
          filetime = newfiletime;
          boost::this_thread::sleep_for(boost::chrono::seconds(3));
          newfiletime = boost::filesystem::last_write_time(itsConfigFile, ec);
        }

        if (!Spine::Reactor::isShuttingDown())
        {
          // Generate new repomanager according to new configs
          boost::shared_ptr<RepoManager> newrepomanager =
              boost::make_shared<RepoManager>(itsConfigFile);

          // The old manager can be used to initialize common data faster
          auto oldrepomanager = itsRepoManager.load();
          newrepomanager->setOldManager(oldrepomanager);
          newrepomanager->init();

          // Wait until all initial data has been loaded
          while (!newrepomanager->ready() && !Spine::Reactor::isShuttingDown())
          {
            boost::this_thread::sleep(boost::posix_time::milliseconds(100));
          }

          newrepomanager->removeOldManager();

          if (!Spine::Reactor::isShuttingDown())
          {
            // Update current repomanager
            itsRepoManager.store(newrepomanager);
            std::cout << Spine::log_time_str() + " Querydata config " + itsConfigFile +
                             " update done"
                      << std::endl;
            lastConfigErrno = 0;
            // Before poll cycling again, wait to avoid constant reload if the file changes many
            // times
            boost::this_thread::sleep_for(boost::chrono::seconds(2));
          }
        }
      }
      catch (const std::exception& e)
      {
        if (strstr(e.what(), "syntax error") != nullptr)
          lastConfigErrno = ENOEXEC;
        std::cerr << std::string{"Error reading new config: "} + e.what() + "\n";
      }

      filetime = newfiletime;  // Update time even if there is an error
      // We don't want to reread a damaged file continuously
    }
  }

  // Exit on shutdown
  lastConfigErrno = ESHUTDOWN;
}

// ----------------------------------------------------------------------
/*!
 * \brief Shutdown the engine
 */
// ----------------------------------------------------------------------

void Engine::shutdown()
{
  try
  {
    std::cout << "  -- Shutdown requested (qengine)\n";

    if (configFileWatcher.joinable())
    {
      configFileWatcher.interrupt();
      configFileWatcher.join();
    }

    auto repomanager = itsRepoManager.load();

    if (repomanager != nullptr)
      repomanager->shutdown();

    if (itsSynchro)
      itsSynchro->shutdown();
  }
  catch (...)
  {
    throw Fmi::Exception::Trace(BCP, "Operation failed!");
  }
}

// ----------------------------------------------------------------------
/*!
 * \brief Get caches sizes
 */
// ----------------------------------------------------------------------

CacheReportingStruct Engine::getCacheSizes() const
{
  return CacheReportingStruct{itsCoordinateCache.maxSize(),
                              itsCoordinateCache.size(),
                              itsValuesCache.maxSize(),
                              itsValuesCache.size()};
}

// ----------------------------------------------------------------------
/*!
 * \brief Get list of available producers
 */
// ----------------------------------------------------------------------

const ProducerList& Engine::producers() const
{
  try
  {
    // We didn't bother to add a producers() method for the Impl,
    // hence we take an explicit lock here instead of inside the Impl.
    // The other public methods call the Impl to do the job.
    auto repomanager = itsRepoManager.load();

    Spine::ReadLock lock(repomanager->itsMutex);
    return repomanager->itsProducerList;
  }
  catch (...)
  {
    throw Fmi::Exception::Trace(BCP, "Operation failed!");
  }
}

// ----------------------------------------------------------------------
/*!
 * \brief Test if the given producer is defined
 */
// ----------------------------------------------------------------------

bool Engine::hasProducer(const Producer& producer) const
{
  try
  {
    auto repomanager = itsRepoManager.load();

    Spine::ReadLock lock(repomanager->itsMutex);
    return repomanager->itsRepo.hasProducer(producer);
  }
  catch (...)
  {
    throw Fmi::Exception::Trace(BCP, "Operation failed!");
  }
}

// ----------------------------------------------------------------------
/*!
 * \brief Get list of available origintimes for a producer
 */
// ----------------------------------------------------------------------

OriginTimes Engine::origintimes(const Producer& producer) const
{
  try
  {
    auto repomanager = itsRepoManager.load();

    Spine::ReadLock lock(repomanager->itsMutex);
    return repomanager->itsRepo.originTimes(producer);
  }
  catch (...)
  {
    throw Fmi::Exception::Trace(BCP, "Operation failed!");
  }
}

// ----------------------------------------------------------------------
/*!
 * \brief Get data for the given producer
 */
// ----------------------------------------------------------------------

Q Engine::get(const Producer& producer) const
{
  try
  {
    auto repomanager = itsRepoManager.load();

    Spine::ReadLock lock(repomanager->itsMutex);
    auto q = repomanager->itsRepo.get(producer);
    q->setParameterTranslations(itsParameterTranslations.load());
    return q;
  }
  catch (...)
  {
    throw Fmi::Exception::Trace(BCP, "Operation failed!");
  }
}

// ----------------------------------------------------------------------
/*!
 * \brief Get data for the given producer and origintime
 */
// ----------------------------------------------------------------------

Q Engine::get(const Producer& producer, const boost::posix_time::ptime& origintime) const
{
  try
  {
    auto repomanager = itsRepoManager.load();

    Spine::ReadLock lock(repomanager->itsMutex);
    auto q = repomanager->itsRepo.get(producer, origintime);
    q->setParameterTranslations(itsParameterTranslations.load());
    return q;
  }
  catch (...)
  {
    throw Fmi::Exception::Trace(BCP, "Operation failed!");
  }
}

// ----------------------------------------------------------------------
/*!
 * \brief Select first model which covers the given point
 *
 * Returns empty producer if there are no matches.
 */
// ----------------------------------------------------------------------

Producer Engine::find(double lon,
                      double lat,
                      double maxdist,
                      bool usedatamaxdistance,
                      const std::string& leveltype) const
{
  try
  {
    auto repomanager = itsRepoManager.load();

    Spine::ReadLock lock(repomanager->itsMutex);
    return repomanager->itsRepo.find(repomanager->itsProducerList,
                                     repomanager->itsProducerList,
                                     lon,
                                     lat,
                                     maxdist,
                                     usedatamaxdistance,
                                     leveltype);
  }
  catch (...)
  {
    throw Fmi::Exception::Trace(BCP, "Operation failed!");
  }
}

// ----------------------------------------------------------------------
/*!
 * \brief Select first allowed model which covers the given point
 *
 * Returns empty producer if there are no matches.
 */
// ----------------------------------------------------------------------

Producer Engine::find(const ProducerList& producerlist,
                      double longitude,
                      double latitude,
                      double maxdistance,
                      bool usedatamaxdistance,
                      const std::string& leveltype) const
{
  try
  {
    auto repomanager = itsRepoManager.load();

    Spine::ReadLock lock(repomanager->itsMutex);
    return repomanager->itsRepo.find(producerlist,
                                     repomanager->itsProducerList,
                                     longitude,
                                     latitude,
                                     maxdistance,
                                     usedatamaxdistance,
                                     leveltype);
  }
  catch (...)
  {
    throw Fmi::Exception::Trace(BCP, "Operation failed!");
  }
}

// ----------------------------------------------------------------------
/*!
 *\ brief Return info of producers as table
 */
// ----------------------------------------------------------------------

Repository::ContentTable Engine::getProducerInfo(const std::string& timeFormat,
                                                 boost::optional<std::string> producer) const
{
  try
  {
    auto repomanager = itsRepoManager.load();

    Spine::ReadLock lock(repomanager->itsMutex);

    ProducerList producerList;
    if (producer)
      producerList.push_back(*producer);

    return repomanager->itsRepo.getProducerInfo(
        producer ? producerList : repomanager->itsProducerList, timeFormat);
  }
  catch (...)
  {
    throw Fmi::Exception::Trace(BCP, "Operation failed!");
  }
}

// ----------------------------------------------------------------------
/*!
 *\ brief Return info of parameters as table
 */
// ----------------------------------------------------------------------

Repository::ContentTable Engine::getParameterInfo(boost::optional<std::string> producer) const
{
  try
  {
    auto repomanager = itsRepoManager.load();

    Spine::ReadLock lock(repomanager->itsMutex);

    ProducerList producerList;
    if (producer)
      producerList.push_back(*producer);

    return repomanager->itsRepo.getParameterInfo(producer ? producerList
                                                          : repomanager->itsProducerList);
  }
  catch (...)
  {
    throw Fmi::Exception::Trace(BCP, "Operation failed!");
  }
}

// ----------------------------------------------------------------------
/*!
 *\ brief Return currently mapped files as table
 */
// ----------------------------------------------------------------------

Repository::ContentTable Engine::getEngineContents(const std::string& timeFormat,
                                                   const std::string& projectionFormat) const
{
  try
  {
    auto repomanager = itsRepoManager.load();

    Spine::ReadLock lock(repomanager->itsMutex);

    return repomanager->itsRepo.getRepoContents(timeFormat, projectionFormat);
  }
  catch (...)
  {
    throw Fmi::Exception::Trace(BCP, "Operation failed!");
  }
}

// ----------------------------------------------------------------------
/*!
 *\ brief Return currently mapped files for a producer as table
 */
// ----------------------------------------------------------------------

Repository::ContentTable Engine::getEngineContents(const std::string& producer,
                                                   const std::string& timeFormat,
                                                   const std::string& projectionFormat) const
{
  try
  {
    auto repomanager = itsRepoManager.load();

    Spine::ReadLock lock(repomanager->itsMutex);

    if (producer.empty())
      return repomanager->itsRepo.getRepoContents(timeFormat, projectionFormat);
    return repomanager->itsRepo.getRepoContents(producer, timeFormat, projectionFormat);
  }
  catch (...)
  {
    throw Fmi::Exception::Trace(BCP, "Operation failed!");
  }
}

// ----------------------------------------------------------------------
/*!
 * \brief Return the time period for the given producer
 *
 * Returns a timeperiod for which is_null() is true if there is no data.
 */
// ----------------------------------------------------------------------

boost::posix_time::time_period Engine::getProducerTimePeriod(const Producer& producer) const
{
  try
  {
    // Handle unknown producers such as observations quickly without exceptions
    if (!hasProducer(producer))
    {
      return {boost::posix_time::ptime(), boost::posix_time::hours(0)};  // is_null will return true
    }

    try
    {
      auto q = get(producer);
      auto validtimes = q->validTimes();
      if (validtimes->empty())
        return {boost::posix_time::ptime(),
                boost::posix_time::hours(0)};  // is_null will return true

      return {validtimes->front(), validtimes->back()};
    }
    catch (...)
    {
      return {boost::posix_time::ptime(), boost::posix_time::hours(0)};  // is_null will return true
    }
  }
  catch (...)
  {
    throw Fmi::Exception::Trace(BCP, "Operation failed!");
  }
}

std::list<MetaData> Engine::getEngineMetadata() const
{
  try
  {
    auto repomanager = itsRepoManager.load();

    Spine::ReadLock lock(repomanager->itsMutex);

    return repomanager->itsRepo.getRepoMetadata();
  }
  catch (...)
  {
    throw Fmi::Exception::Trace(BCP, "Operation failed!");
  }
}

std::list<MetaData> Engine::getEngineMetadata(const MetaQueryOptions& theOptions) const
{
  try
  {
    auto repomanager = itsRepoManager.load();

    Spine::ReadLock lock(repomanager->itsMutex);

    return repomanager->itsRepo.getRepoMetadata(theOptions);
  }
  catch (...)
  {
    throw Fmi::Exception::Trace(BCP, "Operation failed!");
  }
}

std::list<MetaData> Engine::getEngineSyncMetadata(const std::string& syncGroup) const
{
  try
  {
    auto syncProducers = itsSynchro->getSynchedData(syncGroup);

    if (!syncProducers)
      return std::list<MetaData>();  // Unknown sync group

    auto repomanager = itsRepoManager.load();

    std::list<MetaData> repocontent;
    {
      Spine::ReadLock lock(repomanager->itsMutex);
      repocontent = repomanager->itsRepo.getRepoMetadata();
    }

    if (repocontent.empty())
      return repocontent;  // No point filtering an empty list

    for (auto iter = repocontent.begin(); iter != repocontent.end();)
    {
      auto& producer = iter->producer;

      auto syncIt = syncProducers->find(producer);
      if (syncIt == syncProducers->end())
      {
        // This producer is not available in this synchronization group
        repocontent.erase(iter++);
        continue;
      }

      // Filter according to synchroed origin times
      if (!filterSynchro(*iter, syncIt->second))
      {
        repocontent.erase(iter++);
        continue;
      }

      ++iter;
    }

    return repocontent;
  }
  catch (...)
  {
    throw Fmi::Exception::Trace(BCP, "Operation failed!");
  }
}

std::list<MetaData> Engine::getEngineSyncMetadata(const std::string& syncGroup,
                                                  const MetaQueryOptions& options) const
{
  try
  {
    auto syncProducers = itsSynchro->getSynchedData(syncGroup);
    auto repomanager = itsRepoManager.load();

    if (!syncProducers)
      return std::list<MetaData>();  // Unknown sync group

    std::list<MetaData> repocontent;
    {
      Spine::ReadLock lock(repomanager->itsMutex);
      repocontent = repomanager->itsRepo.getRepoMetadata(options);
    }

    if (repocontent.empty())
      return repocontent;  // No point filtering an empty list

    for (auto iter = repocontent.begin(); iter != repocontent.end();)
    {
      auto& producer = iter->producer;
      auto syncIt = syncProducers->find(producer);
      if (syncIt == syncProducers->end())
      {
        // This producer is not available in this synchronization group
        repocontent.erase(iter++);
        continue;
      }

      // Filter according to synchroed origin times
      if (!filterSynchro(*iter, syncIt->second))
      {
        repocontent.erase(iter++);
        continue;
      }

      ++iter;
    }

    return repocontent;
  }
  catch (...)
  {
    throw Fmi::Exception::Trace(BCP, "Operation failed!");
  }
}

Repository::MetaObject Engine::getSynchroInfos() const
{
  try
  {
    auto repomanager = itsRepoManager.load();

    Spine::ReadLock lock(repomanager->itsMutex);

    return repomanager->itsRepo.getSynchroInfos();
  }
  catch (...)
  {
    throw Fmi::Exception::Trace(BCP, "Operation failed!");
  }
}

boost::optional<ProducerMap> Engine::getSyncProducers(const std::string& syncGroup) const
{
  try
  {
    return itsSynchro->getSynchedData(syncGroup);
  }
  catch (...)
  {
    throw Fmi::Exception::Trace(BCP, "Operation failed!");
  }
}

void Engine::startSynchronize(Spine::Reactor* theReactor)
{
  try
  {
    itsSynchro->launch(theReactor);
  }
  catch (...)
  {
    throw Fmi::Exception::Trace(BCP, "Operation failed!");
  }
}

// ----------------------------------------------------------------------
/*!
 *\ brief Get producer's configuration
 */
// ----------------------------------------------------------------------

const ProducerConfig& Engine::getProducerConfig(const std::string& producer) const
{
  try
  {
    auto repomanager = itsRepoManager.load();
    return repomanager->producerConfig(producer);
  }
  catch (...)
  {
    throw Fmi::Exception::Trace(BCP, "Operation failed!");
  }
}

// ----------------------------------------------------------------------
/*!
 * \brief Mark the given coordinate cell as bad
 */
// ----------------------------------------------------------------------

void mark_cell_bad(Fmi::CoordinateMatrix& theCoords, const NFmiPoint& theCoord)
{
  try
  {
    if (theCoord.X() == kFloatMissing || theCoord.Y() == kFloatMissing ||
        std::isnan(theCoord.X()) || std::isnan(theCoord.Y()))

      return;

    if (theCoord.X() >= 0 && theCoord.X() < theCoords.width() - 1 && theCoord.Y() >= 0 &&
        theCoord.Y() < theCoords.height() - 1)
    {
      auto i = static_cast<std::size_t>(theCoord.X());
      auto j = static_cast<std::size_t>(theCoord.Y());
      theCoords(i + 0, j + 0) = badcoord;
      theCoords(i + 1, j + 0) = badcoord;
      // Marking two vertices bad is enough to invalidate the cell
      // theCoords(i+0,j+1])= badcoord;
      // theCoords(i+1],+1])= badcoord;
    }
  }
  catch (...)
  {
    throw Fmi::Exception::Trace(BCP, "Operation failed!");
  }
}

// ----------------------------------------------------------------------
/*!
 * \brief Project coordinates
 */
// ----------------------------------------------------------------------

CoordinatesPtr project_coordinates(const CoordinatesPtr& theCoords,
                                   const Q& theQ,
                                   const Fmi::SpatialReference& theSR)
{
  try
  {
    // Copy the original coordinates for projection

    Fmi::CoordinateTransformation transformation(theQ->SpatialReference(), theSR);
    auto coords = std::make_shared<Fmi::CoordinateMatrix>(*theCoords);

    coords->transform(transformation);

    // If the target SR is geographic, we must discard the grid cells containing
    // the north or south poles since the cell vertex coordinates wrap around
    // the world. The more difficult alternative would be to divide the cell into
    // 4 triangles from the poles and contour the triangles.

    // We also have to check whether some grid cells cross the 180th meridian
    // and discard them

    // If the target SR is no geographic, we discard all very elongated cells
    // since they are likely spanning the world

    // TODO: Should probably be removed in favour of the grid analyzer

#if 0
    if (theSR.isGeographic() != 0)
    {
      auto& c = *coords;

      const auto& grid = theQ->grid();
      auto northpole = grid.LatLonToGrid(0, 90);
      mark_cell_bad(c, northpole);
      auto southpole = grid.LatLonToGrid(0, -90);
      mark_cell_bad(c, southpole);

      const auto nx = c.width();
      const auto ny = c.height();

      for (std::size_t j = 0; j < ny; j++)
        for (std::size_t i = 0; i + 1 < nx; i++)
        {
          double lon1 = c.x(i, j);
          double lon2 = c.x(i + 1, j);
          if (lon1 != kFloatMissing && lon2 != kFloatMissing && std::abs(lon1 - lon2) > 180)
            c.set(i, j, badcoord);
        }
    }
#endif

    return coords;
  }
  catch (...)
  {
    throw Fmi::Exception::Trace(BCP, "Operation failed!");
  }
}

CoordinatesPtr Engine::getWorldCoordinates(const Q& theQ, const Fmi::SpatialReference& theSR) const
{
  try
  {
    // Hash value of original WorldXY coordinates
    auto qhash = theQ->gridHashValue();

    // Hash value of projected coordinates
    auto projhash = qhash;

    // Return original world XY directly with get_world_xy if spatial
    // references match This is absolutely necessary to avoid gaps in
    // WMS tiles since with proj(invproj(p)) may differ significantly
    // from p outside the valid area of the projection.

    auto datawkt = theQ->info()->Area()->WKT();
    auto reqwkt = Fmi::OGR::exportToWkt(theSR);

    if (datawkt != reqwkt)
      Fmi::hash_combine(projhash, theSR.hashValue());

    if (qhash == projhash)
      return getWorldCoordinates(theQ);

    // Search cache for the projected coordinates
    auto cached_coords = itsCoordinateCache.find(projhash);
    if (cached_coords)
      return cached_coords->get();

    // Now we need to to get WorldXY coordinates - this is fast
    auto worldxy = getWorldCoordinates(theQ);

    // Project to target SR. Do NOT use intermediate latlons in any datum, or the Z value will not
    // be included in all stages of the projection, and large errors will occur if the datums
    // differ significantly (e.g. sphere vs ellipsoid)

    auto ftr2 = std::async([&] { return project_coordinates(worldxy, theQ, theSR); }).share();

    itsCoordinateCache.insert(projhash, ftr2);
    return ftr2.get();
  }
  catch (...)
  {
    throw Fmi::Exception::Trace(BCP, "Operation failed!");
  }
}

CoordinatesPtr Engine::getWorldCoordinates(const Q& theQ) const
{
  return std::make_shared<Fmi::CoordinateMatrix>(theQ->FullCoordinateMatrix());
}

// ----------------------------------------------------------------------
/*!
 * \brief Get the data values
 *
 * Retrieval is done asynchronously through a shared future so that for
 * example multiple WMS tile requests would not cause the same values
 * to be retrieved twice.
 */
// ----------------------------------------------------------------------

ValuesPtr Engine::getValues(const Q& theQ,
                            std::size_t theValuesHash,
                            boost::posix_time::ptime theTime) const
{
  try
  {
    // If there is a future in the cache, ask it for the values

    auto values = itsValuesCache.find(theValuesHash);
    if (values)
      return values->get();

    // Else create a shared future for calculating the values
    auto ftr = std::async(std::launch::async,
                          [&] { return std::make_shared<Values>(theQ->values(theTime)); })
                   .share();

    // Store the shared future into the cache for other threads to see too
    itsValuesCache.insert(theValuesHash, ftr);

    // And wait for the future to finish along with other threads
    return ftr.get();
  }
  catch (...)
  {
    throw Fmi::Exception::Trace(BCP, "Failed to retrieve data")
        .addParameter("time", Fmi::to_iso_extended_string(theTime));
  }
}

// ----------------------------------------------------------------------
/*!
 * \brief Get the data values
 *
 * Retrieval is done asynchronously through a shared future so that for
 * example multiple WMS tile requests would not cause the same values
 * to be retrieved twice.
 */
// ----------------------------------------------------------------------

ValuesPtr Engine::getValues(const Q& theQ,
                            const Spine::Parameter& theParam,
                            std::size_t theValuesHash,
                            boost::posix_time::ptime theTime) const
{
  try
  {
    // If there is a future in the cache, ask it for the values

    auto values = itsValuesCache.find(theValuesHash);
    if (values)
      return values->get();

    // Else create a shared future for calculating the values
    auto ftr = std::async(std::launch::async,
                          [&] { return std::make_shared<Values>(theQ->values(theParam, theTime)); })
                   .share();

    // Store the shared future into the cache for other threads to see too
    itsValuesCache.insert(theValuesHash, ftr);

    // And wait for the future to finish along with other threads
    return ftr.get();
  }
  catch (...)
  {
    throw Fmi::Exception::Trace(BCP, "Failed to retrieve data")
        .addParameter("time", Fmi::to_iso_extended_string(theTime));
  }
}

std::time_t Engine::getConfigModTime()
{
  auto repomanager = itsRepoManager.load();
  return repomanager->getConfigModTime();
}

int Engine::getLastConfigErrno()
{
  return lastConfigErrno;
}

Fmi::Cache::CacheStatistics Engine::getCacheStats() const
{
  Fmi::Cache::CacheStatistics ret;

  auto repomanager = itsRepoManager.load();
  ret.insert(std::make_pair("Querydata::lat_lon_cache", repomanager->getCacheStats()));
  ret.insert(std::make_pair("Querydata::wgs84_envelope_cache", WGS84EnvelopeFactory::getCacheStats()));

  return ret;
}

}  // namespace Querydata
}  // namespace Engine
}  // namespace SmartMet

// DYNAMIC MODULE CREATION TOOLS

extern "C" void* engine_class_creator(const char* configfile, void* /* user_data */)
{
  return new SmartMet::Engine::Querydata::Engine(configfile);
}

extern "C" const char* engine_name()
{
  return "Querydata";
}
// ======================================================================

max_stars_repo_name: fmidev/smartmet-engine-querydata

max_issues_repo_name: fmidev/smartmet-engine-querydata

max_forks_repo_name: fmidev/smartmet-engine-querydata


text:
/**
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *  http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

#ifndef __STOUT_INTERVAL_HPP__
#define __STOUT_INTERVAL_HPP__

#include <functional> // For std::less.
#include <iostream>

#include <boost/icl/interval.hpp>
#include <boost/icl/interval_set.hpp>

// Forward declarations.
template <typename T>
class Interval;

template <typename T>
class IntervalSet;

// Represents a bound (left or right) for an interval. A bound can
// either be open or closed.
template <typename T>
class Bound
{
public:
  // Creates an open bound.
  static Bound<T> open(const T& value)
  {
    return Bound<T>(OPEN, value);
  }

  // Creates an closed bound.
  static Bound<T> closed(const T& value)
  {
    return Bound<T>(CLOSED, value);
  }

  // Intervals can be created using the comma operator. For example:
  //   (2, 6):  (Bound<int>::open(2), Bound<int>::open(6))
  //   (3, 4]:  (Bound<int>::open(3), Bound<int>::closed(4))
  //   [0, 5):  (Bound<int>::closed(0), Bound<int>::open(5))
  //   [1, 2]:  (Bound<int>::closed(1), Bound<int>::closed(2))
  Interval<T> operator , (const Bound<T>& right) const;

private:
  enum Type
  {
    OPEN,
    CLOSED,
  };

  Bound(const Type _type, const T& _value)
    : type(_type), value(_value) {}

  const Type type;
  const T value;
};

// Represents an interval.
template <typename T>
class Interval
{
public:
  // We must provide a public default constructor as the boost
  // interval set expects that.
  Interval() {}

  // Returns the inclusive lower bound of this interval.
  T lower() const { return data.lower(); }

  // Returns the exclusive upper bound of this interval.
  T upper() const { return data.upper(); }

  // Checks if this interval intersects with another interval.
  bool intersects(const Interval<T>& interval) const;

  // Checks if this interval intersects with an interval set.
  bool intersects(const IntervalSet<T>& set) const;

  bool operator==(const Interval<T>& that) const
  {
    return data == that.data;
  }

  bool operator!=(const Interval<T>& that) const
  {
    return !(*this == that);
  }

private:
  friend class Bound<T>;

  template <typename X>
  friend std::ostream& operator<<(
      std::ostream& stream,
      const Interval<X>& interval);

  Interval(const boost::icl::right_open_interval<T, std::less>& _data)
    : data(_data) {}

  // We store the interval in right open format: [lower, upper).
  // Notice that we use composition here instead of inheritance to
  // prevent Interval from being passed to bare boost icl containers.
  boost::icl::right_open_interval<T, std::less> data;
};

template <typename T>
std::ostream& operator<<(std::ostream& stream, const Interval<T>& interval)
{
  return stream << interval.data;
}

template <typename T>
Interval<T> Bound<T>::operator , (const Bound<T>& right) const
{
  if (type == OPEN) {
    if (right.type == OPEN) {
      // For example: (1, 3).
      return boost::icl::static_interval<
          boost::icl::right_open_interval<T, std::less>, // Target.
          boost::icl::is_discrete<T>::value,
          boost::icl::interval_bounds::static_open,      // Input bounds.
          boost::icl::interval_bounds::static_right_open // Output bounds.
      >::construct(value, right.value);
    } else {
      // For example: (1, 3].
      return boost::icl::static_interval<
          boost::icl::right_open_interval<T, std::less>, // Target.
          boost::icl::is_discrete<T>::value,
          boost::icl::interval_bounds::static_left_open, // Input bounds.
          boost::icl::interval_bounds::static_right_open // Output bounds.
      >::construct(value, right.value);
    }
  } else {
    if (right.type == OPEN) {
      // For example: [1, 3).
      return boost::icl::static_interval<
          boost::icl::right_open_interval<T, std::less>,  // Target.
          boost::icl::is_discrete<T>::value,
          boost::icl::interval_bounds::static_right_open, // Input bounds.
          boost::icl::interval_bounds::static_right_open  // Output bounds.
      >::construct(value, right.value);
    } else {
      // For example: [1, 3].
      return boost::icl::static_interval<
          boost::icl::right_open_interval<T, std::less>,  // Target.
          boost::icl::is_discrete<T>::value,
          boost::icl::interval_bounds::static_closed,     // Input bounds.
          boost::icl::interval_bounds::static_right_open  // Output bounds.
      >::construct(value, right.value);
    }
  }
}

// Modeled after boost interval_set. Provides a compact representation
// of a set by merging adjacent elements into intervals.
template <typename T>
class IntervalSet : public boost::icl::interval_set<T, std::less, Interval<T> >
{
public:
  IntervalSet() {}

  explicit IntervalSet(const T& value)
  {
    Base::add(value);
  }

  explicit IntervalSet(const Interval<T>& interval)
  {
    Base::add(interval);
  }

  IntervalSet(const Bound<T>& lower, const Bound<T>& upper)
  {
    Base::add((lower, upper));
  }

  // Checks if an element is in this set.
  bool contains(const T& value) const
  {
    return boost::icl::contains(static_cast<const Base&>(*this), value);
  }

  // Checks if an interval is in this set.
  bool contains(const Interval<T>& interval) const
  {
    // TODO(jieyu): Boost has an issue regarding unqualified lookup in
    // template (http://clang.llvm.org/compatibility.html#dep_lookup),
    // and gcc-4.8 complains about it. We use a workaround here by
    // delegating this call to the IntervalSet version below.
    return contains(IntervalSet<T>(interval));
  }

  // Checks if an interval set is a subset of this set.
  bool contains(const IntervalSet<T>& set) const
  {
    return boost::icl::contains(
        static_cast<const Base&>(*this),
        static_cast<const Base&>(set));
  }

  // Checks if this set intersects with an interval.
  bool intersects(const Interval<T>& interval) const
  {
    return boost::icl::intersects(static_cast<const Base&>(*this), interval);
  }

  // Checks if this set intersects with another interval set.
  bool intersects(const IntervalSet<T>& set) const
  {
    return boost::icl::intersects(
        static_cast<const Base&>(*this),
        static_cast<const Base&>(set));
  }

  // Returns the number of intervals in this set.
  size_t intervalCount() const
  {
    return boost::icl::interval_count(static_cast<const Base&>(*this));
  }

  // Overloaded operators.
  bool operator==(const IntervalSet<T>& that) const
  {
    return static_cast<const Base&>(*this) == static_cast<const Base&>(that);
  }

  bool operator!=(const IntervalSet<T>& that) const
  {
    return !(*this == that);
  }

  IntervalSet<T>& operator+=(const T& value)
  {
    static_cast<Base&>(*this) += value;
    return *this;
  }

  IntervalSet<T>& operator+=(const Interval<T>& interval)
  {
    static_cast<Base&>(*this) += interval;
    return *this;
  }

  IntervalSet<T>& operator+=(const IntervalSet<T>& set)
  {
    static_cast<Base&>(*this) += static_cast<const Base&>(set);
    return *this;
  }

  IntervalSet<T>& operator-=(const T& value)
  {
    static_cast<Base&>(*this) -= value;
    return *this;
  }

  IntervalSet<T>& operator-=(const Interval<T>& interval)
  {
    static_cast<Base&>(*this) -= interval;
    return *this;
  }

  IntervalSet<T>& operator-=(const IntervalSet<T>& set)
  {
    static_cast<Base&>(*this) -= static_cast<const Base&>(set);
    return *this;
  }

  IntervalSet<T>& operator&=(const T& value)
  {
    static_cast<Base&>(*this) &= value;
    return *this;
  }

  IntervalSet<T>& operator&=(const Interval<T>& interval)
  {
    static_cast<Base&>(*this) &= interval;
    return *this;
  }

  IntervalSet<T>& operator&=(const IntervalSet<T>& set)
  {
    static_cast<Base&>(*this) &= static_cast<const Base&>(set);
    return *this;
  }

private:
  template <typename X>
  friend std::ostream& operator<<(
      std::ostream& stream,
      const IntervalSet<X>& set);

  // We use typedef here to make the code less verbose.
  typedef boost::icl::interval_set<T, std::less, Interval<T> > Base;
};

template <typename T>
std::ostream& operator<<(std::ostream& stream, const IntervalSet<T>& set)
{
  return stream << static_cast<const typename IntervalSet<T>::Base&>(set);
}

template <typename T>
bool Interval<T>::intersects(const Interval<T>& interval) const
{
  return IntervalSet<T>(*this).intersects(interval);
}

template <typename T>
bool Interval<T>::intersects(const IntervalSet<T>& set) const
{
  return set.intersects(*this);
}

template <typename T, typename X>
IntervalSet<T> operator+(const IntervalSet<T>& set, const X& x)
{
  IntervalSet<T> result(set);
  result += x;
  return result;
}

template <typename T, typename X>
IntervalSet<T> operator-(const IntervalSet<T>& set, const X& x)
{
  IntervalSet<T> result(set);
  result -= x;
  return result;
}

// Defines type traits for the custom Interval above. These type
// traits are required by the boost interval set.
namespace boost {
namespace icl {

template <typename T>
struct interval_traits<Interval<T> >
{
  typedef interval_traits type;
  typedef T domain_type;
  typedef std::less<T> domain_compare;

  static Interval<T> construct(const T& lower, const T& upper)
  {
    return (Bound<T>::closed(lower), Bound<T>::open(upper));
  }

  static T lower(const Interval<T>& interval)
  {
    return interval.lower();
  }

  static T upper(const Interval<T>& interval)
  {
    return interval.upper();
  }
};

template <typename T>
struct interval_bound_type<Interval<T> >
  : public interval_bound_type<right_open_interval<T, std::less> >
{
  typedef interval_bound_type type;
};

} // namespace icl {
} // namespace boost {

#endif // __STOUT_INTERVAL_HPP__

ext: hpp

max_stars_repo_name: CodeTickler/mesos

max_issues_repo_name: CodeTickler/mesos

max_forks_repo_name: CodeTickler/mesos


text:
// test/tag_tree/tree_iterator.cpp

#include <boost/test/unit_test.hpp>

#include <wordring/tag_tree/tag_tree.hpp>
#include <wordring/tree/tree_iterator.hpp>

#include <wordring/html/simple_html.hpp>
#include <wordring/html/simple_node.hpp>

#include <iterator>
#include <string>
#include <string_view>
#include <vector>

BOOST_AUTO_TEST_SUITE(tag_tree_tree_iterator_test)

BOOST_AUTO_TEST_CASE(tree_iterator_1)
{
	using namespace wordring;
	using namespace wordring::html;

	u8simple_tree t1;
	t1.insert(t1.end(), simple_element<std::u8string>{});

	tree_iterator<u8simple_tree::iterator> it1(t1.begin()), it2;

	int i = 0;
	while (it1 != it2)
	{
		++i;
		++it1;
	}

	BOOST_CHECK(i == 1);
}

BOOST_AUTO_TEST_CASE(tree_iterator_2)
{
	using namespace wordring;
	using namespace wordring::html;

	u8simple_tree t1;
	auto it1 = t1.insert(t1.end(), simple_element<std::u8string>{});
	auto it2 = t1.insert(it1.end(), simple_element<std::u8string>{});
	t1.insert(it2.end(), simple_element<std::u8string>{});

	tree_iterator<u8simple_tree::iterator> first(t1.begin()), last;

	int i = 0;
	while (first != last)
	{
		++i;
		++first;
	}

	BOOST_CHECK(i == 3);
}

BOOST_AUTO_TEST_CASE(tree_iterator_3)
{
	using namespace wordring;
	using namespace wordring::html;

	u8simple_tree t1;
	auto it1 = t1.insert(t1.end(), simple_element<std::u8string>{});
	t1.insert(it1.end(), simple_element<std::u8string>{});
	t1.insert(it1.end(), simple_element<std::u8string>{});

	tree_iterator<u8simple_tree::iterator> first(t1.begin()), last;

	int i = 0;
	while (first != last)
	{
		++i;
		++first;
	}

	BOOST_CHECK(i == 3);
}

BOOST_AUTO_TEST_CASE(tree_iterator_4)
{
	using namespace wordring;
	using namespace wordring::html;

	u8simple_tree t1;
	auto it1 = t1.insert(t1.end(), simple_element<std::u8string>{});
	t1.insert(it1.end(), simple_text<std::u8string>{});

	tree_iterator<u8simple_tree::iterator> first(t1.begin()), last;

	int i = 0;
	while (first != last)
	{
		++i;
		++first;
	}

	BOOST_CHECK(i == 2);
}

BOOST_AUTO_TEST_CASE(tree_iterator_5)
{
	using namespace wordring;
	using namespace wordring::html;

	u8simple_tree t1;
	t1.insert(t1.end(), simple_text<std::u8string>{});

	tree_iterator<u8simple_tree::iterator> first(t1.begin()), last;

	int i = 0;
	while (first != last)
	{
		++i;
		++first;
	}

	BOOST_CHECK(i == 1);
}

BOOST_AUTO_TEST_CASE(tree_iterator_6)
{
	using namespace wordring;
	using namespace wordring::html;

	u8simple_tree t1;
	t1.insert(t1.end(), simple_text<std::u8string>{});

	tree_iterator<u8simple_tree::iterator> first(t1.begin()), last;

	int i = 0;
	while (first != last)
	{
		++i;
		++first;
	}

	BOOST_CHECK(i == 1);
}

BOOST_AUTO_TEST_SUITE_END()

max_stars_repo_name: wordring/wordring

max_issues_repo_name: wordring/libwordring

max_forks_repo_name: wordring/libwordring


text:
//
//   Copyright 2019 University of Sheffield
//
//   Licensed under the Apache License, Version 2.0 (the "License");
//   you may not use this file except in compliance with the License.
//   You may obtain a copy of the License at
//
//       http://www.apache.org/licenses/LICENSE-2.0
//
//   Unless required by applicable law or agreed to in writing, software
//   distributed under the License is distributed on an "AS IS" BASIS,
//   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
//   See the License for the specific language governing permissions and
//   limitations under the License.

#ifndef CONFIGURATION_HPP
#define CONFIGURATION_HPP

#include <iostream>
#include <iterator>
#include <map>
#include <sstream>
#include <string>
#include <string_view>
#include <type_traits>
#include <vector>

#include <boost/filesystem.hpp>

namespace bf = boost::filesystem;

#include "types.hpp"
#include "exceptions.hpp"

using config_map = std::map<std::string, std::string>;

class ConfigurationBase {
public:

  template <typename T>
  typename std::enable_if<std::is_same<T, bool>::value, T>::type grab(const std::string &key) const
  {
    try
    {
      T val;
      std::istringstream(config.at(key)) >> std::boolalpha >> val;
      return val;
    }
    catch (std::out_of_range &err)
    {
      std::ostringstream errss;
      errss << "Attempt to access non-existent configuration option \"" << key << "\"";
      throw InternalError(errss.str(), __FILE__, __LINE__);
    }
  }

  template <typename T>
  typename std::enable_if<std::is_integral<T>::value && !std::is_same<T, bool>::value, T>::type
  grab(const std::string &key) const
  {
    try
    {
      return static_cast<T>(std::stoll(config.at(key)));
    }
    catch (std::out_of_range &err)
    {
      std::ostringstream errss;
      errss << "Attempt to access non-existent configuration option \"" << key << "\"";
      throw InternalError(errss.str(), __FILE__, __LINE__);
    }
  }

  template <typename T>
  typename std::enable_if<std::is_floating_point<T>::value && !std::is_same<T, bool>::value, T>::type
  grab(const std::string key) const
  {
    try
    {
      return static_cast<T>(std::stold(config.at(key)));
    }
    catch (std::out_of_range &err)
    {
      std::ostringstream errss;
      errss << "Attempt to access non-existent configuration option \"" << key << "\"";
      throw InternalError(errss.str(), __FILE__, __LINE__);
    }
}

  template <typename T>
  typename std::enable_if<std::is_same<T, std::string>::value, T>::type grab(std::string key) const
  {
    try
    {
      return config.at(key);
    }
    catch (std::out_of_range &err)
    {
      std::ostringstream errss;
      errss << "Attempt to access non-existent configuration option \"" << key << "\"";
      throw InternalError(errss.str(), __FILE__, __LINE__);
    }
  }

  static std::string get_invocation_name(const std::string& argzero);

  void validate_config();

  static const std::string k_stem_token;
  static const std::string k_extension_token;
  static const std::string k_outer_token;
  static const std::string k_inner_token;

protected:
  ConfigurationBase(const int& argc, char const* const* argv);

  config_map config;
  std::vector<std::string> arguments;
  std::string invocation_name;

  static const std::vector<std::string> required_options;
  static const config_map arg_options;
  static const config_map bool_options;
};

#endif // CONFIGURATION_HPP

max_stars_repo_name: willfurnass/pFIRE

max_issues_repo_name: willfurnass/pFIRE

max_forks_repo_name: tartarini/pFIRE


text: #include <boost/preprocessor/list/first_n.hpp>

max_stars_repo_name: miathedev/BoostForArduino

max_issues_repo_name: miathedev/BoostForArduino

max_forks_repo_name: miathedev/BoostForArduino


text:
// Distributed under the MIT License.
// See LICENSE.txt for details.

#include "tests/Unit/TestingFramework.hpp"

#include <array>
#include <boost/optional.hpp>
#include <cstddef>
#include <string>
#include <unordered_map>

#include "ControlSystem/FunctionOfTime.hpp"
#include "ControlSystem/PiecewisePolynomial.hpp"
#include "DataStructures/DataVector.hpp"
#include "DataStructures/Tensor/Tensor.hpp"
#include "Domain/CoordinateMaps/CubicScale.hpp"
#include "Utilities/ConstantExpressions.hpp"
#include "Utilities/StdArrayHelpers.hpp"
#include "Utilities/TypeTraits.hpp"
#include "tests/Unit/Domain/CoordinateMaps/TestMapHelpers.hpp"
#include "tests/Unit/TestHelpers.hpp"

namespace {
// We will call with this function with arguments that are designed
// to fail in a certain way.
void cubic_scale_non_invertible(const double a0, const double b0,
                                const double outer_boundary) noexcept {
  double t = 4.0;
  constexpr size_t deriv_order = 2;

  const std::array<DataVector, deriv_order + 1> init_func_a{
      {{a0}, {0.0}, {0.0}}};
  FunctionsOfTime::PiecewisePolynomial<deriv_order> expansion_a(t, init_func_a);
  FunctionOfTime& expansion_a_base = expansion_a;

  const std::array<DataVector, deriv_order + 1> init_func_b{
      {{b0}, {0.0}, {0.0}}};
  FunctionsOfTime::PiecewisePolynomial<deriv_order> expansion_b(t, init_func_b);
  FunctionOfTime& expansions_b_base = expansion_b;

  const std::unordered_map<std::string, FunctionOfTime&> f_of_t_list = {
      {"expansion_a", expansion_a_base}, {"expansion_b", expansions_b_base}};

  const CoordMapsTimeDependent::CubicScale scale_map(outer_boundary);
  const std::array<double, 1> point_xi{{19.2}};

  const std::array<double, 1> mapped_point{
      {point_xi[0] *
       (expansion_a_base.func(t)[0][0] +
        (expansions_b_base.func(t)[0][0] - expansion_a_base.func(t)[0][0]) *
            square(point_xi[0] / outer_boundary))}};

  // this call should fail.
  scale_map.inverse(mapped_point, t, f_of_t_list);
}
}  // namespace

SPECTRE_TEST_CASE("Unit.Domain.CoordMapsTimeDependent.CubicScale",
                  "[Domain][Unit]") {
  static constexpr size_t deriv_order = 2;

  const auto run_tests = [](
      const std::array<DataVector, deriv_order + 1>& init_func_a,
      const std::array<DataVector, deriv_order + 1>& init_func_b,
      const double outer_b, const double x0, const double final_time) {
    double t = -0.5;
    const double dt = 0.6;

    FunctionsOfTime::PiecewisePolynomial<deriv_order> expansion_a(t,
                                                                  init_func_a);
    FunctionOfTime& expansion_a_base = expansion_a;

    FunctionsOfTime::PiecewisePolynomial<deriv_order> expansion_b(t,
                                                                  init_func_b);
    FunctionOfTime& expansions_b_base = expansion_b;

    const std::unordered_map<std::string, FunctionOfTime&> f_of_t_list = {
        {"expansion_a", expansion_a_base}, {"expansion_b", expansions_b_base}};

    const double outer_boundary = outer_b;
    const CoordMapsTimeDependent::CubicScale scale_map(outer_boundary);
    const std::array<double, 1> point_xi{{x0}};

    // test serialized/deserialized map
    const auto scale_map_deserialized = serialize_and_deserialize(scale_map);

    while (t < final_time) {
      const double a = expansion_a_base.func_and_deriv(t)[0][0];
      const double b = expansions_b_base.func_and_deriv(t)[0][0];

      const std::array<double, 1> mapped_point{
          {point_xi[0] * (a + (b - a) * square(point_xi[0] / outer_boundary))}};

      CHECK_ITERABLE_APPROX(scale_map(point_xi, t, f_of_t_list), mapped_point);
      CHECK_ITERABLE_APPROX(
          scale_map.inverse(mapped_point, t, f_of_t_list).get(), point_xi);
      CHECK_ITERABLE_APPROX(scale_map_deserialized(point_xi, t, f_of_t_list),
                            mapped_point);
      CHECK_ITERABLE_APPROX(
          scale_map_deserialized.inverse(mapped_point, t, f_of_t_list).get(),
          point_xi);

      // Check that inverse map returns invalid for mapped point outside
      // the outer boundary and inside the inner boundary.
      const std::array<double, 1> bad_mapped_point_1{{1.1 * outer_boundary}};
      const std::array<double, 1> bad_mapped_point_2{{-0.1 * outer_boundary}};
      CHECK(not scale_map.inverse(bad_mapped_point_1, t, f_of_t_list));
      CHECK(not scale_map.inverse(bad_mapped_point_2, t, f_of_t_list));

      const double jacobian =
          a + 3.0 * (b - a) * square(point_xi[0] / outer_boundary);
      const double inv_jacobian =
          1.0 / (a + 3.0 * (b - a) * square(point_xi[0] / outer_boundary));

      CHECK(scale_map.jacobian(point_xi, t, f_of_t_list).get(0, 0) == jacobian);
      CHECK(scale_map.inv_jacobian(point_xi, t, f_of_t_list).get(0, 0) ==
            inv_jacobian);
      CHECK(
          scale_map_deserialized.jacobian(point_xi, t, f_of_t_list).get(0, 0) ==
          jacobian);
      CHECK(scale_map_deserialized.inv_jacobian(point_xi, t, f_of_t_list)
                .get(0, 0) == inv_jacobian);

      const double a_dot = expansion_a_base.func_and_deriv(t)[1][0];
      const double b_dot = expansions_b_base.func_and_deriv(t)[1][0];
      const std::array<double, 1> frame_vel =
          point_xi *
          (a_dot + (b_dot - a_dot) * square(point_xi[0] / outer_boundary));

      CHECK_ITERABLE_APPROX(scale_map.frame_velocity(point_xi, t, f_of_t_list),
                            frame_vel);
      CHECK_ITERABLE_APPROX(
          scale_map_deserialized.frame_velocity(point_xi, t, f_of_t_list),
          frame_vel);

      const double a_ddot = expansion_a_base.func_and_2_derivs(t)[2][0];
      const double b_ddot = expansions_b_base.func_and_2_derivs(t)[2][0];
      const double time_time =
          a_ddot * point_xi[0] +
          (b_ddot - a_ddot) * cube(point_xi[0]) / square(outer_boundary);
      const double time_space =
          a_dot + 3.0 * (b_dot - a_dot) * square(point_xi[0] / outer_boundary);
      const double space_space =
          6.0 * (b - a) * point_xi[0] / square(outer_boundary);

      CHECK(approx(scale_map.hessian(point_xi, t, f_of_t_list).get(0, 0, 0)) ==
            time_time);
      CHECK(approx(scale_map.hessian(point_xi, t, f_of_t_list).get(0, 1, 0)) ==
            time_space);
      CHECK(approx(scale_map.hessian(point_xi, t, f_of_t_list).get(0, 0, 1)) ==
            time_space);
      CHECK(approx(scale_map.hessian(point_xi, t, f_of_t_list).get(0, 1, 1)) ==
            space_space);

      CHECK(approx(scale_map_deserialized.hessian(point_xi, t, f_of_t_list)
                       .get(0, 0, 0)) == time_time);
      CHECK(approx(scale_map_deserialized.hessian(point_xi, t, f_of_t_list)
                       .get(0, 1, 0)) == time_space);
      CHECK(approx(scale_map_deserialized.hessian(point_xi, t, f_of_t_list)
                   .get(0, 0, 1)) == time_space);
      CHECK(approx(scale_map_deserialized.hessian(point_xi, t, f_of_t_list)
                       .get(0, 1, 1)) == space_space);

      // Check inequivalence operator
      CHECK_FALSE(scale_map != scale_map);
      CHECK_FALSE(scale_map_deserialized != scale_map_deserialized);

      // Check serialization
      CHECK(scale_map == scale_map_deserialized);
      CHECK_FALSE(scale_map != scale_map_deserialized);

      test_coordinate_map_argument_types(scale_map, point_xi, t, f_of_t_list);

      t += dt;
    }
  };

  std::array<DataVector, deriv_order + 1> init_func_a1{
      {{1.0}, {0.0007}, {-0.004}}};
  std::array<DataVector, deriv_order + 1> init_func_b1{
      {{1.0}, {-0.001}, {0.003}}};
  run_tests(init_func_a1, init_func_b1, 20.0, 19.2, 4.0);
  // test again with inputs that explicitly result in multiple roots
  std::array<DataVector, deriv_order + 1> init_func_a2{{{1.0}, {0.0}, {0.0}}};
  std::array<DataVector, deriv_order + 1> init_func_b2{{{0.99}, {0.0}, {0.0}}};
  run_tests(init_func_a2, init_func_b2, 6.0, 5.0, 0.0);
}

SPECTRE_TEST_CASE(
    "Unit.Domain.CoordMapsTimeDependent.CubicScale.TestBoundaries",
    "[Domain][Unit]") {
  static constexpr size_t deriv_order = 2;

  const auto run_tests = [](const double x0) {
    double t = -0.5;
    const double dt = 0.6;
    const double final_time = 4.0;

    const std::array<DataVector, deriv_order + 1> init_func_a{
        {{1.0}, {0.0}, {0.0}}};
    const std::array<DataVector, deriv_order + 1> init_func_b{
        {{0.99}, {0.0}, {0.0}}};

    FunctionsOfTime::PiecewisePolynomial<deriv_order> expansion_a(t,
                                                                  init_func_a);
    FunctionOfTime& expansion_a_base = expansion_a;

    FunctionsOfTime::PiecewisePolynomial<deriv_order> expansion_b(t,
                                                                  init_func_b);
    FunctionOfTime& expansions_b_base = expansion_b;

    const std::unordered_map<std::string, FunctionOfTime&> f_of_t_list = {
        {"expansion_a", expansion_a_base}, {"expansion_b", expansions_b_base}};

    const double outer_boundary = 20.0;
    const CoordMapsTimeDependent::CubicScale scale_map(outer_boundary);
    const std::array<double, 1> point_xi{{x0}};

    while (t < final_time) {
      const double a = expansion_a_base.func_and_deriv(t)[0][0];
      const double b = expansions_b_base.func_and_deriv(t)[0][0];

      const std::array<double, 1> mapped_point{
          {point_xi[0] * (a + (b - a) * square(point_xi[0] / outer_boundary))}};

      CHECK_ITERABLE_APPROX(scale_map(point_xi, t, f_of_t_list), mapped_point);
      CHECK_ITERABLE_APPROX(
          scale_map.inverse(mapped_point, t, f_of_t_list).get(), point_xi);
      t += dt;
    }
  };

  // test inverse at inner and outer boundary values
  run_tests(0.0);
  run_tests(20.0);
}

// [[OutputRegex, The map is invertible only if 0 < expansion_b <
// expansion_a\*2/3]]
SPECTRE_TEST_CASE(
    "Unit.Domain.CoordMapsTimeDependent.CubicScale.NonInvertible1",
    "[Domain][Unit]") {
  ERROR_TEST();
  // the two expansion factors are chosen such that the map is non-invertible
  cubic_scale_non_invertible(0.96, 0.58, 20.0);
}

// [[OutputRegex, We require expansion_a > 0 for invertibility]]
SPECTRE_TEST_CASE(
    "Unit.Domain.CoordMapsTimeDependent.CubicScale.NonInvertible2",
    "[Domain][Unit]") {
  ERROR_TEST();
  // Make a<0
  cubic_scale_non_invertible(-0.0001, 1.0, 20.0);
}

// [[OutputRegex, The map is invertible only if 0 < expansion_b <
// expansion_a\*2/3]]
SPECTRE_TEST_CASE(
    "Unit.Domain.CoordMapsTimeDependent.CubicScale.NonInvertible3",
    "[Domain][Unit]") {
  ERROR_TEST();
  // Make b==0
  cubic_scale_non_invertible(0.96, 0.0, 20.0);
}

// [[OutputRegex, For invertability, we require outer_boundary to be positive]]
SPECTRE_TEST_CASE(
    "Unit.Domain.CoordMapsTimeDependent.CubicScale.NonInvertible4",
    "[Domain][Unit]") {
  ERROR_TEST();
  cubic_scale_non_invertible(0.96, 1.0, 0.0);
}

max_stars_repo_name: marissawalker/spectre

max_issues_repo_name: marissawalker/spectre

max_forks_repo_name: marissawalker/spectre