text:
////////////////////////////////////////////////////////////////////////////////
/// Copyright of this program is the property of AMADEUS, without
/// whose written permission reproduction in whole or in part is prohibited.
////////////////////////////////////////////////////////////////////////////////

#include <mdw/formula/Parser.hpp>
#include <mdw/formula/Container.hpp>
#include <mdw/formula/IContext.hpp>
#include <mdw/formula/Grammar.hpp>
#include <mdw/formula/StandardTypes.hpp>
#include <mdw/formula/Repeated.hpp>
#include <mdw/formula/Casts.hpp>
#include <mdw/formula/cache/Factorizer.hpp>
#include <mdw/formula/Facts.hpp>
#include <mdw/Tracer.hpp>
#include <boost/mem_fn.hpp>
#include <iostream>

#define ASSERT_TRUE(x) if (!(x)) {std::cerr << "Failed to check: " #x << std::endl; return 1;}
#define ASSERT_FALSE(x) if (x) {std::cerr << "Failed to fail: " #x << std::endl; return 1;}
#define ASSERT_EQ(x,y) ASSERT_TRUE(x == y)

namespace mdw { namespace formula {

  int ConstantBool()
  {
    Grammar aGrammar;
    std::string aTest("true");
    Container aContainer(aTest, aGrammar);

    IContext aContext;
    ASSERT_TRUE(aContainer.getExpression().getBool().evaluate(aContext) == true);
    FORMULA_DEBUG("Expression is: " << aContainer.getExpression().getBool().toString());
    ASSERT_TRUE(aContainer.getExpression().getBool().toString() == "true");
    return 0;
  }

  int ConstantInt()
  {
    ArenaAllocator aAlloc;
    Grammar aGrammar;
    std::string aTest("64");
    aGrammar.registerStandardOperators(aAlloc);
    Container aContainer(aTest, aGrammar);

    IContext aContext;
    ASSERT_TRUE(aContainer.getExpression().getInt().evaluate(aContext) == 64);
    return 0;
  }

  int ConstantDouble()
  {
    Grammar aGrammar;
    std::string aTest(".684");
    Container aContainer(aTest, aGrammar);

    IContext aContext;
    ASSERT_TRUE(aContainer.getExpression().getDouble().evaluate(aContext) == .684);
    return 0;
  }

  int ConstantString()
  {
    Grammar aGrammar;
    std::string aTest("('Pouet' )");
    Container aContainer(aTest, aGrammar);

    IContext aContext;
    ASSERT_TRUE(aContainer.getExpression().getType() == mdw::formula::kExprString);
    FORMULA_DEBUG("Expression is: " << aContainer.getExpression().getString().toString());
    ASSERT_TRUE(aContainer.getExpression().getString().evaluate(aContext) == "Pouet");
    return 0;
  }

  int NotBool()
  {
    ArenaAllocator aAlloc;
    Grammar aGrammar;
    aGrammar.registerStandardOperators(aAlloc);
    std::string aTest("!true");
    Container aContainer(aTest, aGrammar);

    IContext aContext;
    ASSERT_TRUE(aContainer.getExpression().getBool().evaluate(aContext) == false);
    return 0;
  }

  int MinusInt()
  {
    ArenaAllocator aAlloc;
    Grammar aGrammar;
    aGrammar.registerStandardOperators(aAlloc);
    std::string aTest("-64");
    Container aContainer(aTest, aGrammar);

    IContext aContext;
    ASSERT_TRUE(aContainer.getExpression().getInt().evaluate(aContext) == -64);
    return 0;
  }

  int MinusDouble()
  {
    ArenaAllocator aAlloc;
    Grammar aGrammar;
    aGrammar.registerStandardOperators(aAlloc);
    std::string aTest("-.684");
    Container aContainer(aTest, aGrammar);

    IContext aContext;
    ASSERT_TRUE(aContainer.getExpression().getDouble().evaluate(aContext) == -0.684);
    return 0;
  }

  int IntTest()
  {
    ArenaAllocator aAlloc;
    Grammar aGrammar;
    aGrammar.registerStandardOperators(aAlloc);
    IContext aContext;
    std::string aTest("4");
    Container aContainer(aTest, aGrammar);
    ASSERT_TRUE(aContainer.getExpression().getInt().evaluate(aContext) == 4);
    return 0;
  }

  int SimpleFalseGreaterOrEqualTest()
  {
    ArenaAllocator aAlloc;
    Grammar aGrammar;
    aGrammar.registerStandardOperators(aAlloc);
    IContext aContext;
    std::string aTest("3 >= 5");
    Container aContainer(aTest, aGrammar);
    ASSERT_TRUE(aContainer.getExpression().getBool().evaluate(aContext) == false);
    return 0;
  }

  int SimpleTrueGreaterOrEqualTest()
  {
    ArenaAllocator aAlloc;
    Grammar aGrammar;
    aGrammar.registerStandardOperators(aAlloc);
    IContext aContext;
    std::string aTest("6 >= -5");
    Container aContainer(aTest, aGrammar);
    ASSERT_TRUE(aContainer.getExpression().getBool().evaluate(aContext) == true);
    return 0;
  }

  int SimpleTrueANDCombinationTest()
  {
    ArenaAllocator aAlloc;
    Grammar aGrammar;
    aGrammar.registerStandardOperators(aAlloc);
    IContext aContext;
    std::string aTest("(6 >= 5) AND (4 > 3)");
    FORMULA_DEBUG(aTest);
    Container aContainer(aTest, aGrammar);
    ASSERT_TRUE(aContainer.getExpression().getBool().evaluate(aContext) == true);

    Container aContainer2(aContainer.getExpression().toString(), aGrammar);
    ASSERT_EQ(aContainer.getExpression().getBool().evaluate(aContext),
              aContainer2.getExpression().getBool().evaluate(aContext));
    return 0;
  }

  int SimpleFalseANDCombinationTest()
  {
    ArenaAllocator aAlloc;
    Grammar aGrammar;
    aGrammar.registerStandardOperators(aAlloc);
    IContext aContext;
    std::string aTest("(6 >= 5) AND (3 >= 4)");
    FORMULA_DEBUG(aTest);
    Container aContainer(aTest, aGrammar);
    ASSERT_TRUE(aContainer.getExpression().getBool().evaluate(aContext) == false);
    return 0;
  }

  int FalseORCombinationTest()
  {
    ArenaAllocator aAlloc;
    Grammar aGrammar;
    aGrammar.registerStandardOperators(aAlloc);
    IContext aContext;
    std::string aTest("6 > 5 AND 3 >= 4 OR 3 >= 1");
    FORMULA_DEBUG(aTest);
    Container aContainer(aTest, aGrammar);
    ASSERT_TRUE(aContainer.getExpression().getBool().evaluate(aContext) == true);
    return 0;
  }

  int TrueORCombinationTest()
  {
    ArenaAllocator aAlloc;
    Grammar aGrammar;
    aGrammar.registerStandardOperators(aAlloc);
    IContext aContext;
    std::string aTest("6 < 5 AND 3 <= 4 OR 4 <= 3");
    FORMULA_DEBUG(aTest);
    Container aContainer(aTest, aGrammar);
    ASSERT_TRUE(aContainer.getExpression().getBool().evaluate(aContext) == false);

    Container aContainer2(aContainer.getExpression().toString(), aGrammar);
    ASSERT_EQ(aContainer.getExpression().getBool().evaluate(aContext),
              aContainer2.getExpression().getBool().evaluate(aContext));
    return 0;
  }

  int FalseORANDCombinationTest()
  {
    ArenaAllocator aAlloc;
    Grammar aGrammar;
    aGrammar.registerStandardOperators(aAlloc);
    IContext aContext;
    std::string aTest("(6 >= 5 AND 3 >= 4) OR (5 >= 0)");
    FORMULA_DEBUG(aTest);
    Container aContainer(aTest, aGrammar);
    ASSERT_TRUE(aContainer.getExpression().getBool().evaluate(aContext) == true);

    Container aContainer2(aContainer.getExpression().toString(), aGrammar);
    ASSERT_EQ(aContainer.getExpression().getBool().evaluate(aContext),
              aContainer2.getExpression().getBool().evaluate(aContext));
    return 0;
  }

  int TrueAndORCombinationtest()
  {
    ArenaAllocator aAlloc;
    Grammar aGrammar;
    aGrammar.registerStandardOperators(aAlloc);
    IContext aContext;
    std::string aTest("(((6 >= 5) AND (3 >= 4)) OR (5 >= 4)) AND (5 >= 0)");
    FORMULA_DEBUG(aTest);
    Container aContainer(aTest, aGrammar);
    ASSERT_TRUE(aContainer.getExpression().getBool().evaluate(aContext) == true);

    Container aContainer2(aContainer.getExpression().toString(), aGrammar);
    ASSERT_EQ(aContainer.getExpression().getBool().evaluate(aContext),
              aContainer2.getExpression().getBool().evaluate(aContext));
    return 0;
  }

  int AndNoParenthesisTest()
  {
    ArenaAllocator aAlloc;
    Grammar aGrammar;
    aGrammar.registerStandardOperators(aAlloc);
    IContext aContext;
    std::string aTest("6 < 6 AND 9 >= 6");
    FORMULA_DEBUG(aTest);
    Parser aParser(aAlloc, aGrammar);
    aParser.parse(aTest);
    ASSERT_FALSE(aParser.getTopExpression().getBool().evaluate(aContext));

    Expression& anExpr = aParser.getTopExpression();
    aParser.parse(anExpr.toString());
    ASSERT_EQ(anExpr.getBool().evaluate(aContext),
              aParser.getTopExpression().getBool().evaluate(aContext));
    return 0;
  }

  int OrNoParenthesisTest()
  {
    ArenaAllocator aAlloc;
    Grammar aGrammar;
    aGrammar.registerStandardOperators(aAlloc);
    IContext aContext;
    std::string aTest("3 >= 5 OR 3 >= 3");
    FORMULA_DEBUG(aTest);
    Container aContainer(aTest, aGrammar);
    ASSERT_TRUE(aContainer.getExpression().getBool().evaluate(aContext) == true);
    return 0;
  }

  int OrNotOperatorTest()
  {
    ArenaAllocator aAlloc;
    Grammar aGrammar;
    aGrammar.registerStandardOperators(aAlloc);
    IContext aContext;
    std::string aTest("(3 >= 5 AND 3 == 1) OR (3 != 2)");
    FORMULA_DEBUG(aTest);
    Parser aParser(aAlloc, aGrammar, aTest);
    ASSERT_TRUE(aParser.getTopExpression().getBool().evaluate(aContext) == true);

    Container aContainer2(aParser.getTopExpression().toString(), aGrammar);
    ASSERT_EQ(aParser.getTopExpression().getBool().evaluate(aContext),
              aContainer2.getExpression().getBool().evaluate(aContext));
    return 0;
  }

  int NotOperatorTest()
  {
    ArenaAllocator aAlloc;
    Grammar aGrammar;
    aGrammar.registerStandardOperators(aAlloc);
    IContext aContext;
    std::string aTest("!(1>=1)");
    FORMULA_DEBUG(aTest);
    Container aContainer(aTest, aGrammar);
    ASSERT_TRUE(aContainer.getExpression().getBool().evaluate(aContext) == false);
    return 0;
  }

  int Choice1()
  {
    ArenaAllocator aAlloc;
    Grammar aGrammar;
    aGrammar.registerStandardOperators(aAlloc);
    IContext aContext;
    std::string aTest("-6 > 5 ? 'Wrong' : 'Right' ");
    FORMULA_DEBUG(aTest);
    Container aContainer(aTest, aGrammar);
    ASSERT_TRUE(aContainer.getExpression().getString().evaluate(aContext) == "Right");
    return 0;
  }

  int Choice2()
  {
    ArenaAllocator aAlloc;
    Grammar aGrammar;
    aGrammar.registerStandardOperators(aAlloc);
    IContext aContext;
    std::string aTest("!(6 >= 6) ? 2 > 1 : 2 < 1");
    FORMULA_DEBUG(aTest);
    Container aContainer(aTest, aGrammar);
    ASSERT_TRUE(aContainer.getExpression().getBool().evaluate(aContext) == false);

    Container aContainer2(aContainer.getExpression().toString(), aGrammar);
    ASSERT_EQ(aContainer.getExpression().getBool().evaluate(aContext),
              aContainer2.getExpression().getBool().evaluate(aContext));
    return 0;
  }

  int StringAt()
  {
    ArenaAllocator aAlloc;
    Grammar aGrammar;
    aGrammar.registerStandardOperators(aAlloc);
    IContext aContext;
    std::string aTest("'Pouet'[2] == 'u'[0] && 'Pouet'[1] != 'u'[0] ");
    FORMULA_DEBUG(aTest);
    Container aContainer(aTest, aGrammar);
    ASSERT_TRUE(aContainer.getExpression().getBool().evaluate(aContext));
    return 0;
  }

  int CastInt()
  {
    ArenaAllocator aAlloc;
    Grammar aGrammar;
    aGrammar.registerStandardOperators(aAlloc);
    IContext aContext;
    std::string aTest("(int)65.89");
    FORMULA_DEBUG(aTest);
    Container aContainer(aTest, aGrammar);
    ASSERT_TRUE(aContainer.getExpression().getInt().evaluate(aContext) == 66);

    Container aContainer2(aContainer.getExpression().toString(), aGrammar);
    ASSERT_EQ(aContainer.getExpression().getInt().evaluate(aContext),
              aContainer2.getExpression().getInt().evaluate(aContext));
    return 0;
  }

  int CastStringInt()
  {
    ArenaAllocator aAlloc;
    Grammar aGrammar;
    aGrammar.registerStandardOperators(aAlloc);
    IContext aContext;
    std::string aTest("(int)'-23'");
    FORMULA_DEBUG(aTest);
    Container aContainer(aTest, aGrammar);
    ASSERT_TRUE(aContainer.getExpression().getInt().evaluate(aContext) == -23);

    Container aContainer2(aContainer.getExpression().toString(), aGrammar);
    ASSERT_EQ(aContainer.getExpression().getInt().evaluate(aContext),
              aContainer2.getExpression().getInt().evaluate(aContext));
    return 0;
  }

  int CastStringDouble()
  {
    ArenaAllocator aAlloc;
    Grammar aGrammar;
    aGrammar.registerStandardOperators(aAlloc);
    IContext aContext;
    std::string aTest("(double)'-23.'");
    FORMULA_DEBUG(aTest);
    Container aContainer(aTest, aGrammar);
    ASSERT_TRUE(aContainer.getExpression().getDouble().evaluate(aContext) == -23.);

    Container aContainer2(aContainer.getExpression().toString(), aGrammar);
    ASSERT_EQ(aContainer.getExpression().getDouble().evaluate(aContext),
              aContainer2.getExpression().getDouble().evaluate(aContext));
    return 0;
  }

  int CastString()
  {
    ArenaAllocator aAlloc;
    Grammar aGrammar;
    aGrammar.registerStandardOperators(aAlloc);
    IContext aContext;
    std::string aTest("(string)87");
    FORMULA_DEBUG(aTest);
    Container aContainer(aTest, aGrammar);
    ASSERT_TRUE(aContainer.getExpression().getString().evaluate(aContext) == "87");
    return 0;
  }

  int CastDouble()
  {
    ArenaAllocator aAlloc;
    Grammar aGrammar;
    aGrammar.registerStandardOperators(aAlloc);
    IContext aContext;
    std::string aTest("(double)87");
    FORMULA_DEBUG(aTest);
    Container aContainer(aTest, aGrammar);
    ASSERT_TRUE(aContainer.getExpression().getDouble().evaluate(aContext) == (double)87);
    return 0;
  }

  template <class ContextT>
    class Self: public TypedExpression<ContextT>
  {
  public:
    Self(const Grammar& iGrammar):
      TypedExpression<ContextT>(iGrammar)
    {}

    std::string toString() const
    {
      return "$Context";
    }

    const ContextT& evaluate(IContext& ioContext) const
    {
      return ioContext.get<ContextT>();
    }
  };

  class MyContext: public mdw::formula::IContext
  {
    double _test;
    std::string _testString;
    bool _testBool;
  public:
    MyContext(double iDouble, const std::string& iString, bool iBool):
      _test(iDouble), _testString(iString), _testBool(iBool)
    {}

    double getDouble() const
    {
      return _test;
    }

    const std::string& getString() const
    {
      return _testString;
    }

    bool getBool() const
    {
      return _testBool;
    }
  };

  class MyContextFacts: public formula::FactInstantiator
  {
    const Grammar& _grammar;
    const Self<MyContext> _contextAsExpression;
  public:
    MyContextFacts(Grammar& iGrammar):
      _grammar(iGrammar), _contextAsExpression(iGrammar)
    {}

    Expression& instantiate(ArenaAllocator& ioAllocator,
                            const Grammar& iGrammar,
                            const std::string& iName) const
    {
      if (iName == "Test")
      {
        return make_resolver(ioAllocator, _grammar, _contextAsExpression,
                             boost::mem_fn(&MyContext::getDouble), iName);
      } else if (iName == "TestString") {
        return make_resolver(ioAllocator, _grammar, _contextAsExpression,
                             boost::mem_fn(&MyContext::getString), iName);
      } else if (iName == "TestBool") {
        return make_resolver(ioAllocator, _grammar, _contextAsExpression,
                             boost::mem_fn(&MyContext::getBool), iName);
      } else {
        throw mdw::UnknownException("Unknown variable name: " + iName);
      }
    }

  };

  int MultipleMetricTest()
  {
    Grammar aGrammar;
    Factorizer aFactorizer;
    ArenaAllocator& aAlloc(aFactorizer.getAllocator());

    aGrammar.addObserver(aFactorizer);
    aGrammar.registerType<MyContext>();
    aGrammar.registerStandardOperators(aAlloc);
    MyContext aContext(5, "ThisIsATest", false);
    MyContext aContext2(20., "Haha", true);
    MyContextFacts aFacts(aGrammar);
    aGrammar.registerFactResolver("Test", kExprDouble, aFacts);
    aGrammar.registerFactResolver("TestString", kExprString, aFacts);
    aGrammar.registerFactResolver("TestBool", kExprBool, aFacts);

    std::string aTest("$TestString == \"ThisIsATest\"");
    FORMULA_DEBUG(aTest);
    Container aFormula(aTest, aGrammar);
    ASSERT_TRUE(aFormula.getExpression().getBool().evaluate(aContext));
    ASSERT_FALSE(aFormula.getExpression().getBool().evaluate(aContext2));

    std::string aTest2("$TestString == \"Haha\"");
    FORMULA_DEBUG(aTest2);
    Container aFormula2(aTest2, aGrammar);
    ASSERT_FALSE(aFormula2.getExpression().getBool().evaluate(aContext));
    ASSERT_TRUE(aFormula2.getExpression().getBool().evaluate(aContext2));

    std::string aTest3("(($TestString == \"Haha\") AND ($Test > (double)2)) OR $Test == 5.");
    FORMULA_DEBUG(aTest3);
    Container aFormula3(aTest3, aGrammar);
    ASSERT_TRUE(aFormula3.getExpression().getBool().evaluate(aContext));

    std::string aTest4("(($TestString == \"Haha\") AND ((int)$Test > 2))");
    FORMULA_DEBUG(aTest4);
    Container aFormula4(aTest4, aGrammar);
    ASSERT_FALSE(aFormula4.getExpression().getBool().evaluate(aContext));

    std::string aTest6("(($TestString == \"Haha\") OR ((int)$Test > 2)) == true");
    FORMULA_DEBUG(aTest6);
    Container aFormula6(aTest6, aGrammar);
    ASSERT_TRUE(aFormula6.getExpression().getBool().evaluate(aContext));

    std::string aTest5("(($TestString == \'Haha\') AND ($Test > 2.)) == $TestBool");
    FORMULA_DEBUG(aTest5);
    Container aFormula5(aTest5, aGrammar);
    ASSERT_TRUE(aFormula5.getExpression().getBool().evaluate(aContext));

    std::string aTest7("$Test * $Test");
    FORMULA_DEBUG(aTest7);
    Container aFormula7(aTest7, aGrammar);
    ASSERT_TRUE(aFormula7.getExpression().getDouble().evaluate(aContext) == 5.*5.);
    ASSERT_TRUE(aFormula7.getExpression().getDouble().evaluate(aContext2) == 20.*20.);

    std::string aTest8("((($Test * $Test) + 2. - (double)2) * 2.) / $Test");
    FORMULA_DEBUG(aTest8);
    Container aFormula8(aTest8, aGrammar);
    ASSERT_TRUE(aFormula8.getExpression().getDouble().evaluate(aContext) == 10);

    std::string aTest9("(((($Test * $Test) + 2. - 2.) * 2.) / $Test) == $Test * 2.");
    FORMULA_DEBUG(aTest9);
    Container aFormula9(aTest9, aGrammar);
    ASSERT_TRUE(aFormula9.getExpression().getBool().evaluate(aContext));

    std::string aTest10("\"2015-02-10\" >= \"2014-02-10\" ");
    FORMULA_DEBUG(aTest10);
    Container aFormula10(aTest10, aGrammar);
    ASSERT_TRUE(aFormula10.getExpression().getBool().evaluate(aContext));

    /*UP_Date aDate(11,2,2015);
    std::string aTest11("\"2015-02-10\" + 1");
    FORMULA_DEBUG(aTest11);
    Container aFormula11(aTest11);
    FORMULA_DEBUG("Resulting date" << aFormula11.evaluate(aMetrics).getDateValue().asString());
    ASSERT_TRUE(aFormula11.evaluate(aMetrics).getDateValue() == aDate);*/

    return 0;
  }

  class Flight
  {
    std::string _departureCountry;
    double _expectedLoadFactor;
    std::string _cabin;
  public:
    Flight(const std::string& iCountry,
           double iElf,
           const std::string& iCabin):
      _departureCountry(iCountry), _expectedLoadFactor(iElf), _cabin(iCabin)
    {}

    const std::string& getDepartureCountry() const
    {
      return _departureCountry;
    }

    double getExpectedLoadFactor() const
    {
      return _expectedLoadFactor;
    }

    bool hasExpectedLoadFactor() const
    {
      return _expectedLoadFactor != -1;
    }

    const std::string& getCabin() const
    {
      return _cabin;
    }
  };

  class FlightContext: public IContext
  {
  public:
    FlightContext(const Flight& iCurrent, const Flight& iNext):
      _currentFlight(iCurrent), _nextFlight(iNext)
    {}

    Flight _currentFlight;
    Flight _nextFlight;
  };

  class FlightValue: public TypedExpression<Flight>
  {
    std::string _name;
  public:
    FlightValue(const Grammar& ioGrammar, const std::string iName):
      TypedExpression<Flight>(ioGrammar),
      _name(iName)
    {}

    std::string toString() const
    {
      return "$" + _name;
    }

    const Flight& evaluate(IContext& ioContext) const
    {
      FlightContext& aContext = ioContext.get<FlightContext>();
      return aContext._currentFlight;
    }
  };

  class NextFlightValue: public TypedExpression<Flight>
  {
    std::string _name;
  public:
    NextFlightValue(const Grammar& ioGrammar, const std::string iName):
      TypedExpression<Flight>(ioGrammar),
      _name(iName)
    {}

    std::string toString() const
    {
      return "$" + _name;
    }

    const Flight& evaluate(IContext& ioContext) const
    {
      FlightContext& aContext = ioContext.get<FlightContext>();
      return aContext._nextFlight;
    }
  };

  class FlightFacts: public formula::FactInstantiator
  {
    Grammar& _grammar;
  public:
    FlightFacts(Grammar& iGrammar):
      _grammar(iGrammar)
    {
      iGrammar.registerType<Flight>();
    }

    Expression& instantiate(ArenaAllocator& ioAllocator,
                            const Grammar& iGrammar,
                            const std::string& iName) const
    {
      if (iName == "CurrentFlight")
      {
        return ioAllocator.create<FlightValue>(_grammar, iName);
      } else if (iName == "NextFlight") {
        return ioAllocator.create<NextFlightValue>(_grammar, iName);
      } else {
        throw mdw::UnknownException("Unknown variable name: " + iName);
      }
    }

  };

  class Service
  {
    std::string _code;
    std::string _rfic;

  public:
    Service(const std::string& iCode):
      _code(iCode)
    {}

    Service(const std::string& iCode, const std::string& iRFIC):
      _code(iCode), _rfic(iRFIC)
    {}

    const std::string& getCode() const
    {
      return _code;
    }

    const std::string& getRFIC() const
    {
      return _rfic;
    }

    bool operator==(const Service& iOther) const
    {
      return _code == iOther._code;
    }
  };

  class Customer
  {
    int _value;
    char _gender;
    std::string _name;
    std::vector<Service> _services;
    Service _preferredSvc;
  public:
    Customer(const std::string& iName, int iValue, char iGender):
      _value(iValue), _gender(iGender), _name(iName), _preferredSvc("VGML")
    {}

    void addService(const std::string& iCode,
                    const std::string& iRFIC)
    {
      _services.push_back(Service(iCode, iRFIC));
    }

    int getValue() const {return _value;}
    char getGender() const {return _gender;}
    const std::string& getName() const {return _name;}
    const std::vector<Service>& getServices() const {return _services;}
    const Service& getPreferredService() const {return _preferredSvc;}
  };

  class FactContext: public IContext
  {
  public:
    FactContext(const Flight& iFlight, const Customer& iCustomer):
      _flight(iFlight), _customer(iCustomer)
    {}

    Flight _flight;
    Customer _customer;
    const Flight& getFlight() const {return _flight;}
    const Customer& getCustomer() const {return _customer;}
  };

  int FactTest(){
    ArenaAllocator aAlloc;
    Grammar aGrammar;
    aGrammar.registerStandardOperators(aAlloc);

    Flight aFlight("FR", 0.46, "Y");
    Customer aCustomer("Bob", 350, 'M');
    aCustomer.addService("VGML", "M");
    aCustomer.addService("WIFI", "T");
    aCustomer.addService("LNGE", "T");
    aCustomer.addService("PETC", "S");

    Iterable<Service, std::vector<Service> >::RegisterMe(aAlloc, aGrammar);
    RandomAccess<Service, std::vector<Service> >::RegisterMe(aAlloc, aGrammar);

    FactContext aContext(aFlight, aCustomer);

    OwnContext<FactContext>::RegisterFact(aAlloc, aGrammar, "Flight",
                                          boost::mem_fn(&FactContext::getFlight));
    OwnContext<FactContext>::RegisterFact(aAlloc, aGrammar, "Customer",
                                          boost::mem_fn(&FactContext::getCustomer));

    RegisterAttribute(aAlloc, aGrammar, boost::mem_fn(&Flight::getDepartureCountry),
                                       "DepartureCountry");
    RegisterOptionalAttribute(aAlloc, aGrammar,
                              boost::mem_fn(&Flight::getExpectedLoadFactor),
                              boost::mem_fn(&Flight::hasExpectedLoadFactor),
                              "ExpectedLoadFactor");
    RegisterAttribute(aAlloc, aGrammar, boost::mem_fn(&Flight::getCabin), "Cabin");

    RegisterAttribute(aAlloc, aGrammar, boost::mem_fn(&Customer::getName), "Name");
    RegisterAttribute(aAlloc, aGrammar, boost::mem_fn(&Customer::getGender), "Gender");
    RegisterAttribute(aAlloc, aGrammar, boost::mem_fn(&Customer::getValue), "Value");
    RegisterAttribute(aAlloc, aGrammar, boost::mem_fn(&Customer::getServices), "Services");
    RegisterAttribute(aAlloc, aGrammar, boost::mem_fn(&Customer::getPreferredService),
                                       "Preference");

    DefaultCast<std::string, Service>::RegisterMe(aAlloc, aGrammar, "(Service)");

    RegisterAttribute(aAlloc, aGrammar, boost::mem_fn(&Service::getCode), "code");

    std::string aTest6("$Customer.Preference.code");
    FORMULA_DEBUG(aTest6);
    Container aFormula6(aTest6, aGrammar);

    ASSERT_EQ(aFormula6.getExpression().getString().evaluate(aContext), "VGML");

    std::string aTest3("$Customer.Services[2].code == 'LNGE'");
    FORMULA_DEBUG(aTest3);
    Container aFormula3(aTest3, aGrammar);

    ASSERT_TRUE(aFormula3.getExpression().getBool().evaluate(aContext));

    Container aContainer3(aFormula3.getExpression().toString(), aGrammar);
    ASSERT_EQ(aFormula3.getExpression().getBool().evaluate(aContext),
              aContainer3.getExpression().getBool().evaluate(aContext));

    std::string aTest4("$Customer.Services[2] in $Customer.Services && "
                       "(Service)'PETC' in $Customer.Services && "
                       "!((Service)'PETB' in $Customer.Services)");
    FORMULA_DEBUG(aTest4);
    Container aFormula4(aTest4, aGrammar);

    ASSERT_TRUE(aFormula4.getExpression().getBool().evaluate(aContext));

    Container aContainer4(aFormula4.getExpression().toString(), aGrammar);
    ASSERT_EQ(aFormula4.getExpression().getBool().evaluate(aContext),
              aContainer4.getExpression().getBool().evaluate(aContext));
    return 0;
  }

  int BaseFactTest(){
    ArenaAllocator aAlloc;
    Grammar aGrammar;
    aGrammar.registerStandardOperators(aAlloc);

    Flight aFlight("FR", 0.46, "Y");
    Customer aCustomer("Bob", 350, 'M');
    aCustomer.addService("VGML", "M");
    aCustomer.addService("WIFI", "T");
    aCustomer.addService("LNGE", "T");
    aCustomer.addService("PETC", "S");

    Iterable<Service, std::vector<Service> >::RegisterMe(aAlloc, aGrammar);
    RandomAccess<Service, std::vector<Service> >::RegisterMe(aAlloc, aGrammar);

    Iterable<char, std::string>::RegisterMe(aAlloc, aGrammar);
    RandomAccess<char, std::string>::RegisterMe(aAlloc, aGrammar);

    RegisterAttribute(aAlloc, aGrammar, boost::mem_fn(&Flight::getDepartureCountry),
                                       "DepartureCountry");
    RegisterOptionalAttribute(aAlloc, aGrammar,
                              boost::mem_fn(&Flight::getExpectedLoadFactor),
                              boost::mem_fn(&Flight::hasExpectedLoadFactor),
                              "ExpectedLoadFactor");
    RegisterAttribute(aAlloc, aGrammar, boost::mem_fn(&Flight::getCabin), "Cabin");

    RegisterAttribute(aAlloc, aGrammar, boost::mem_fn(&Customer::getName), "Name");
    RegisterAttribute(aAlloc, aGrammar, boost::mem_fn(&Customer::getGender), "Gender");
    RegisterAttribute(aAlloc, aGrammar, boost::mem_fn(&Customer::getValue), "Value");
    RegisterAttribute(aAlloc, aGrammar, boost::mem_fn(&Customer::getServices), "Services");
    RegisterAttribute(aAlloc, aGrammar, boost::mem_fn(&Customer::getPreferredService),
                                       "Preference");

    DefaultCast<std::string, Service>::RegisterMe(aAlloc, aGrammar, "(Service)");

    RegisterAttribute(aAlloc, aGrammar, boost::mem_fn(&Service::getCode), "code");
    RegisterAttribute(aAlloc, aGrammar, boost::mem_fn(&Service::getRFIC), "rfic");

    Fact<Flight>::RegisterMe(aAlloc, aGrammar, "Flight");
    Fact<Customer>::RegisterMe(aAlloc, aGrammar, "Customer");

    {
      IContext aContext;
      aContext.setFact(aFlight, "Flight");
      aContext.setFact(aCustomer, "Customer");

      std::string aTest6("$Customer.Preference.code");
      FORMULA_DEBUG(aTest6);
      Container aFormula6(aTest6, aGrammar);

      ASSERT_EQ(aFormula6.getExpression().getString().evaluate(aContext), "VGML");

      std::string aTest3("$Customer.Services[2].code == 'LNGE'");
      FORMULA_DEBUG(aTest3);
      Container aFormula3(aTest3, aGrammar);

      ASSERT_TRUE(aFormula3.getExpression().getBool().evaluate(aContext));

      Container aContainer3(aFormula3.getExpression().toString(), aGrammar);
      ASSERT_EQ(aFormula3.getExpression().getBool().evaluate(aContext),
                aContainer3.getExpression().getBool().evaluate(aContext));

      std::string aTest4("$Customer.Services[2] in $Customer.Services && "
                         "(Service)'PETC' in $Customer.Services && "
                         "!((Service)'PETB' in $Customer.Services)");
      FORMULA_DEBUG(aTest4);
      Container aFormula4(aTest4, aGrammar);

      ASSERT_TRUE(aFormula4.getExpression().getBool().evaluate(aContext));

      Container aContainer4(aFormula4.getExpression().toString(), aGrammar);
      ASSERT_EQ(aFormula4.getExpression().getBool().evaluate(aContext),
                aContainer4.getExpression().getBool().evaluate(aContext));

      std::string aTest5("($Customer.Services -> Svc ? $Svc.code == 'WIFI').count");
      FORMULA_DEBUG(aTest5);
      Container aFormula5(aTest5, aGrammar);

      ASSERT_EQ(aFormula5.getExpression().getInt().evaluate(aContext), 1);

      Container aContainer5(aFormula5.getExpression().toString(), aGrammar);
      ASSERT_EQ(aFormula5.getExpression().getInt().evaluate(aContext),
                aContainer5.getExpression().getInt().evaluate(aContext));

      std::string aTest7("!($Customer.Services -> Svc ? $Svc.code == 'WIFI').empty &&"
                         "($Customer.Services -> Svc ? $Svc.code == 'SCHTROUMPF').empty");
      FORMULA_DEBUG(aTest7);
      Container aFormula7(aTest7, aGrammar);

      ASSERT_TRUE(aFormula7.getExpression().getBool().evaluate(aContext));

      Container aContainer7(aFormula7.getExpression().toString(), aGrammar);
      ASSERT_EQ(aFormula7.getExpression().getBool().evaluate(aContext),
                aContainer7.getExpression().getBool().evaluate(aContext));

      std::string aTest8("($Customer.Services -> Svc ? $Svc.code == 'WIFI').count == 1 &&"
                         "($Customer.Services -> Svc ? $Svc.code == 'SCHTROUMPF').count == 0");
      FORMULA_DEBUG(aTest8);
      Container aFormula8(aTest8, aGrammar);

      ASSERT_TRUE(aFormula8.getExpression().getBool().evaluate(aContext));

      Container aContainer8(aFormula8.getExpression().toString(), aGrammar);
      ASSERT_EQ(aFormula8.getExpression().getBool().evaluate(aContext),
                aContainer8.getExpression().getBool().evaluate(aContext));

      std::string aTest9("(($Customer.Services -> Svc ? $Svc.code == 'VGML') -> v2 ? "
                         "!$v2.rfic.empty && ($v2.rfic[0] == $Customer.Gender)).count == 1");
      FORMULA_DEBUG(aTest9);
      Container aFormula9(aTest9, aGrammar);

      ASSERT_TRUE(aFormula9.getExpression().getBool().evaluate(aContext));

      Container aContainer9(aFormula9.getExpression().toString(), aGrammar);
      ASSERT_EQ(aFormula9.getExpression().getBool().evaluate(aContext),
                aContainer9.getExpression().getBool().evaluate(aContext));

    }
    return 0;
  }

  // PTR#12761056 : Make sure that the OR logical operator ignores the fact that
  // one of its operands is NaN
  int LogicalOrBoolOperatorTest(){
    ArenaAllocator aAlloc;
    Grammar aGrammar;
    aGrammar.registerStandardOperators(aAlloc);

    Flight aFlight("FR", -1, "Y");

    RegisterOptionalAttribute(aAlloc, aGrammar,
                              boost::mem_fn(&Flight::getExpectedLoadFactor),
                              boost::mem_fn(&Flight::hasExpectedLoadFactor),
                              "ExpectedLoadFactor");
    RegisterAttribute(aAlloc, aGrammar, boost::mem_fn(&Flight::getCabin), "Cabin");

    Fact<Flight>::RegisterMe(aAlloc, aGrammar, "Flight");

    {
      IContext aContext;
      aContext.setFact(aFlight, "Flight");

      std::string aTest0("$Flight.ExpectedLoadFactor <= 0.5 || $Flight.Cabin == \"Y\"");
      FORMULA_DEBUG(aTest0);
      Container aFormula0(aTest0, aGrammar);

      ASSERT_TRUE(aFormula0.getExpression().getBool().evaluate(aContext));
      ASSERT_FALSE(aContext.isNaN());

      std::string aTest1("$Flight.Cabin == \"Y\" || $Flight.ExpectedLoadFactor <= 0.5");
      FORMULA_DEBUG(aTest1);
      Container aFormula1(aTest1, aGrammar);

      ASSERT_TRUE(aFormula1.getExpression().getBool().evaluate(aContext));
      ASSERT_FALSE(aContext.isNaN());

      std::string aTest2("$Flight.ExpectedLoadFactor <= 0.5 || $Flight.Cabin != \"Y\"");
      FORMULA_DEBUG(aTest2);
      Container aFormula2(aTest2, aGrammar);

      ASSERT_FALSE(aFormula2.getExpression().getBool().evaluate(aContext));
      ASSERT_FALSE(aContext.isNaN());

      std::string aTest3("$Flight.ExpectedLoadFactor <= 0.5 || $Flight.ExpectedLoadFactor > 2.0");
      FORMULA_DEBUG(aTest3);
      Container aFormula3(aTest3, aGrammar);

      aFormula3.getExpression().getBool().evaluate(aContext);
      ASSERT_TRUE(aContext.isNaN());
    }
    return 0;
  }

  int AllParserTests() {
    int aResult = 0;
    aResult += ConstantBool();
    aResult += ConstantInt();
    aResult += ConstantDouble();
    aResult += ConstantString();
    aResult += NotBool();
    aResult += MinusInt();
    aResult += MinusDouble();
    aResult += IntTest();
    aResult += SimpleFalseGreaterOrEqualTest();
    aResult += SimpleTrueGreaterOrEqualTest();
    aResult += SimpleTrueANDCombinationTest();
    aResult += SimpleFalseANDCombinationTest();
    aResult += FalseORCombinationTest();
    aResult += TrueORCombinationTest();
    aResult += FalseORANDCombinationTest();
    aResult += TrueAndORCombinationtest();
    aResult += AndNoParenthesisTest();
    aResult += OrNoParenthesisTest();
    aResult += OrNotOperatorTest();
    aResult += NotOperatorTest();
    aResult += Choice1();
    aResult += Choice2();
    aResult += StringAt();
    aResult += CastInt();
    aResult += CastStringInt();
    aResult += CastStringDouble();
    aResult += CastString();
    aResult += CastDouble();
    aResult += MultipleMetricTest();
    aResult += FactTest();
    aResult += BaseFactTest();
    aResult += LogicalOrBoolOperatorTest();
    return aResult;
  }

}}

max_stars_repo_name: AmadeusITGroup/Formula

max_issues_repo_name: AmadeusITGroup/Formula

max_forks_repo_name: AmadeusITGroup/Formula


text:
/*=============================================================================
    Copyright (c) 2001-2014 Joel de Guzman

    Distributed under the Boost Software License, Version 1.0. (See accompanying
    file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
=============================================================================*/
#if !defined(BOOST_SPIRIT_X3_SEQUENCE_DETAIL_JAN_06_2013_1015AM)
#define BOOST_SPIRIT_X3_SEQUENCE_DETAIL_JAN_06_2013_1015AM

#include <boost/spirit/home/x3/support/traits/attribute_of.hpp>
#include <boost/spirit/home/x3/support/traits/attribute_category.hpp>
#include <boost/spirit/home/x3/support/traits/has_attribute.hpp>
#include <boost/spirit/home/x3/support/traits/is_substitute.hpp>
#include <boost/spirit/home/x3/support/traits/container_traits.hpp>
#include <boost/spirit/home/x3/support/traits/tuple_traits.hpp>
#include <boost/spirit/home/x3/core/detail/parse_into_container.hpp>

#include <boost/fusion/include/begin.hpp>
#include <boost/fusion/include/end.hpp>
#include <boost/fusion/include/advance.hpp>
#include <boost/fusion/include/deref.hpp>
#include <boost/fusion/include/empty.hpp>
#include <boost/fusion/include/front.hpp>
#include <boost/fusion/include/iterator_range.hpp>
#include <boost/fusion/include/as_deque.hpp>
#include <boost/fusion/include/mpl.hpp>

#include <boost/mpl/copy_if.hpp>
#include <boost/mpl/not.hpp>
#include <boost/mpl/if.hpp>
#include <boost/mpl/insert_range.hpp>
#include <boost/mpl/eval_if.hpp>
#include <boost/mpl/vector.hpp>
#include <boost/mpl/identity.hpp>

#include <boost/type_traits/add_reference.hpp>
#include <boost/type_traits/is_same.hpp>

namespace boost { namespace spirit { namespace x3
{
    template <typename Left, typename Right>
    struct sequence;
}}}

namespace boost { namespace spirit { namespace x3 { namespace detail
{
    template <typename Parser, typename Context, typename Enable = void>
    struct sequence_size
    {
        static int const value = traits::has_attribute<Parser, Context>::value;
    };

    template <typename Parser, typename Context>
    struct sequence_size_subject
      : sequence_size<typename Parser::subject_type, Context> {};

    template <typename Parser, typename Context>
    struct sequence_size<Parser, Context
      , typename enable_if_c<(Parser::is_pass_through_unary)>::type>
      : sequence_size_subject<Parser, Context> {};

    template <typename L, typename R, typename Context>
    struct sequence_size<sequence<L, R>, Context>
    {
        static int const value =
            sequence_size<L, Context>::value +
            sequence_size<R, Context>::value;
    };

    struct pass_sequence_attribute_unused
    {
        typedef unused_type type;

        template <typename T>
        static unused_type
        call(T&)
        {
            return unused_type();
        }
    };

    template <typename Attribute>
    struct pass_sequence_attribute_size_one_view
    {
        typedef typename fusion::result_of::deref<
            typename fusion::result_of::begin<Attribute>::type
        >::type type;

        static type call(Attribute& attr)
        {
            return fusion::deref(fusion::begin(attr));
        }
    };

    template <typename Attribute>
    struct pass_through_sequence_attribute
    {
        typedef Attribute& type;

        template <typename Attribute_>
        static Attribute_&
        call(Attribute_& attr)
        {
            return attr;
        }
    };

    template <typename Parser, typename Attribute, typename Enable = void>
    struct pass_sequence_attribute :
        mpl::if_<
            traits::is_size_one_view<Attribute>
          , pass_sequence_attribute_size_one_view<Attribute>
          , pass_through_sequence_attribute<Attribute>>::type {};

    template <typename L, typename R, typename Attribute>
    struct pass_sequence_attribute<sequence<L, R>, Attribute>
      : pass_through_sequence_attribute<Attribute> {};

    template <typename Parser, typename Attribute>
    struct pass_sequence_attribute_subject :
        pass_sequence_attribute<typename Parser::subject_type, Attribute> {};

    template <typename Parser, typename Attribute>
    struct pass_sequence_attribute<Parser, Attribute
      , typename enable_if_c<(Parser::is_pass_through_unary)>::type>
      : pass_sequence_attribute_subject<Parser, Attribute> {};

    template <typename L, typename R, typename Attribute, typename Context
      , typename Enable = void>
    struct partition_attribute
    {
        using attr_category = typename traits::attribute_category<Attribute>::type;
        static_assert(is_same<traits::tuple_attribute, attr_category>::value,
            "The parser expects tuple-like attribute type");

        static int const l_size = sequence_size<L, Context>::value;
        static int const r_size = sequence_size<R, Context>::value;

        static int constexpr actual_size = fusion::result_of::size<Attribute>::value;
        static int constexpr expected_size = l_size + r_size;

        // If you got an error here, then you are trying to pass
        // a fusion sequence with the wrong number of elements
        // as that expected by the (sequence) parser.
        static_assert(
            actual_size >= expected_size
          , "Size of the passed attribute is less than expected."
        );
        static_assert(
            actual_size <= expected_size
          , "Size of the passed attribute is bigger than expected."
        );

        typedef typename fusion::result_of::begin<Attribute>::type l_begin;
        typedef typename fusion::result_of::advance_c<l_begin, l_size>::type l_end;
        typedef typename fusion::result_of::end<Attribute>::type r_end;
        typedef fusion::iterator_range<l_begin, l_end> l_part;
        typedef fusion::iterator_range<l_end, r_end> r_part;
        typedef pass_sequence_attribute<L, l_part> l_pass;
        typedef pass_sequence_attribute<R, r_part> r_pass;

        static l_part left(Attribute& s)
        {
            auto i = fusion::begin(s);
            return l_part(i, fusion::advance_c<l_size>(i));
        }

        static r_part right(Attribute& s)
        {
            return r_part(
                fusion::advance_c<l_size>(fusion::begin(s))
              , fusion::end(s));
        }
    };

    template <typename L, typename R, typename Attribute, typename Context>
    struct partition_attribute<L, R, Attribute, Context,
        typename enable_if_c<(!traits::has_attribute<L, Context>::value &&
            traits::has_attribute<R, Context>::value)>::type>
    {
        typedef unused_type l_part;
        typedef Attribute& r_part;
        typedef pass_sequence_attribute_unused l_pass;
        typedef pass_sequence_attribute<R, Attribute> r_pass;

        static unused_type left(Attribute&)
        {
            return unused;
        }

        static Attribute& right(Attribute& s)
        {
            return s;
        }
    };

    template <typename L, typename R, typename Attribute, typename Context>
    struct partition_attribute<L, R, Attribute, Context,
        typename enable_if_c<(traits::has_attribute<L, Context>::value &&
            !traits::has_attribute<R, Context>::value)>::type>
    {
        typedef Attribute& l_part;
        typedef unused_type r_part;
        typedef pass_sequence_attribute<L, Attribute> l_pass;
        typedef pass_sequence_attribute_unused r_pass;

        static Attribute& left(Attribute& s)
        {
            return s;
        }

        static unused_type right(Attribute&)
        {
            return unused;
        }
    };

    template <typename L, typename R, typename Attribute, typename Context>
    struct partition_attribute<L, R, Attribute, Context,
        typename enable_if_c<(!traits::has_attribute<L, Context>::value &&
            !traits::has_attribute<R, Context>::value)>::type>
    {
        typedef unused_type l_part;
        typedef unused_type r_part;
        typedef pass_sequence_attribute_unused l_pass;
        typedef pass_sequence_attribute_unused r_pass;

        static unused_type left(Attribute&)
        {
            return unused;
        }

        static unused_type right(Attribute&)
        {
            return unused;
        }
    };

    template <typename L, typename R, typename C>
    struct get_sequence_types
    {
        typedef
            mpl::vector<
                typename traits::attribute_of<L, C>::type
              , typename traits::attribute_of<R, C>::type
            >
        type;
    };

    template <typename LL, typename LR, typename R, typename C>
    struct get_sequence_types<sequence<LL, LR>, R, C>
        : mpl::push_back< typename get_sequence_types<LL, LR, C>::type
                        , typename traits::attribute_of<R, C>::type> {};

    template <typename L, typename RL, typename RR, typename C>
    struct get_sequence_types<L, sequence<RL, RR>, C>
        : mpl::push_front< typename get_sequence_types<RL, RR, C>::type
                         , typename traits::attribute_of<L, C>::type> {};

    template <typename LL, typename LR, typename RL, typename RR, typename C>
    struct get_sequence_types<sequence<LL, LR>, sequence<RL, RR>, C>
    {
        typedef typename get_sequence_types<LL, LR, C>::type left;
        typedef typename get_sequence_types<RL, RR, C>::type right;
        typedef typename
            mpl::insert_range<left, typename mpl::end<left>::type, right>::type
        type;
    };

    template <typename L, typename R, typename C>
    struct attribute_of_sequence
    {
        // Get all sequence attribute types
        typedef typename get_sequence_types<L, R, C>::type all_types;

        // Filter all unused_types
        typedef typename
            mpl::copy_if<
                all_types
              , mpl::not_<is_same<mpl::_1, unused_type>>
              , mpl::back_inserter<mpl::vector<>>
            >::type
        filtered_types;

        // Build a fusion::deque if filtered_types is not empty,
        // else just return unused_type
        typedef typename
            mpl::eval_if<
                mpl::empty<filtered_types>
	    , mpl::identity<unused_type>
	    , mpl::if_<mpl::equal_to<mpl::size<filtered_types>, mpl::int_<1> >,
	    typename mpl::front<filtered_types>::type
		      , typename fusion::result_of::as_deque<filtered_types>::type >
            >::type
        type;
    };

    template <typename Parser, typename Iterator, typename Context
      , typename RContext, typename Attribute, typename AttributeCategory>
    bool parse_sequence(
        Parser const& parser, Iterator& first, Iterator const& last
      , Context const& context, RContext& rcontext, Attribute& attr
      , AttributeCategory)
    {
        typedef typename Parser::left_type Left;
        typedef typename Parser::right_type Right;
        typedef partition_attribute<Left, Right, Attribute, Context> partition;
        typedef typename partition::l_pass l_pass;
        typedef typename partition::r_pass r_pass;

        typename partition::l_part l_part = partition::left(attr);
        typename partition::r_part r_part = partition::right(attr);
        typename l_pass::type l_attr = l_pass::call(l_part);
        typename r_pass::type r_attr = r_pass::call(r_part);

        Iterator save = first;
        if (parser.left.parse(first, last, context, rcontext, l_attr)
            && parser.right.parse(first, last, context, rcontext, r_attr))
            return true;
        first = save;
        return false;
    }

    template <typename Parser, typename Context>
    constexpr bool pass_sequence_container_attribute
        = sequence_size<Parser, Context>::value > 1;

    template <typename Parser, typename Iterator, typename Context
      , typename RContext, typename Attribute>
    typename enable_if_c<pass_sequence_container_attribute<Parser, Context>, bool>::type
    parse_sequence_container(
        Parser const& parser
      , Iterator& first, Iterator const& last, Context const& context
      , RContext& rcontext, Attribute& attr)
    {
        return parser.parse(first, last, context, rcontext, attr);
    }

    template <typename Parser, typename Iterator, typename Context
      , typename RContext, typename Attribute>
    typename disable_if_c<pass_sequence_container_attribute<Parser, Context>, bool>::type
    parse_sequence_container(
        Parser const& parser
      , Iterator& first, Iterator const& last, Context const& context
      , RContext& rcontext, Attribute& attr)
    {
        return parse_into_container(parser, first, last, context, rcontext, attr);
    }

    template <typename Parser, typename Iterator, typename Context
      , typename RContext, typename Attribute>
    bool parse_sequence(
        Parser const& parser , Iterator& first, Iterator const& last
      , Context const& context, RContext& rcontext, Attribute& attr
      , traits::container_attribute)
    {
        Iterator save = first;
        if (parse_sequence_container(parser.left, first, last, context, rcontext, attr)
            && parse_sequence_container(parser.right, first, last, context, rcontext, attr))
            return true;
        first = save;
        return false;
    }

    template <typename Parser, typename Iterator, typename Context
      , typename RContext, typename Attribute>
    bool parse_sequence_assoc(
        Parser const& parser , Iterator& first, Iterator const& last
	  , Context const& context, RContext& rcontext, Attribute& attr, mpl::false_ /*should_split*/)
    {
	    return parse_into_container(parser, first, last, context, rcontext, attr);
    }

    template <typename Parser, typename Iterator, typename Context
      , typename RContext, typename Attribute>
    bool parse_sequence_assoc(
        Parser const& parser , Iterator& first, Iterator const& last
	  , Context const& context, RContext& rcontext, Attribute& attr, mpl::true_ /*should_split*/)
    {
        Iterator save = first;
        if (parser.left.parse( first, last, context, rcontext, attr)
            && parser.right.parse(first, last, context, rcontext, attr))
            return true;
        first = save;
        return false;
    }

    template <typename Parser, typename Iterator, typename Context
      , typename RContext, typename Attribute>
    bool parse_sequence(
        Parser const& parser, Iterator& first, Iterator const& last
      , Context const& context, RContext& rcontext, Attribute& attr
      , traits::associative_attribute)
    {
        // we can come here in 2 cases:
        // - when sequence is key >> value and therefore must
        // be parsed with tuple synthesized attribute and then
        // that tuple is used to save into associative attribute provided here.
        // Example:  key >> value;
        //
        // - when either this->left or this->right provides full key-value
        // pair (like in case 1) and another one provides nothing.
        // Example:  eps >> rule<class x; fusion::map<...> >
        //
        // first case must be parsed as whole, and second one should
        // be parsed separately for left and right.

        typedef typename traits::attribute_of<
            decltype(parser.left), Context>::type l_attr_type;
        typedef typename traits::attribute_of<
            decltype(parser.right), Context>::type r_attr_type;

        typedef typename
            mpl::or_<
                is_same<l_attr_type, unused_type>
              , is_same<r_attr_type, unused_type> >
        should_split;

        return parse_sequence_assoc(parser, first, last, context, rcontext, attr
          , should_split());
    }

    template <typename Left, typename Right, typename Context, typename RContext>
    struct parse_into_container_impl<sequence<Left, Right>, Context, RContext>
    {
        typedef sequence<Left, Right> parser_type;

        template <typename Iterator, typename Attribute>
        static bool call(
            parser_type const& parser
          , Iterator& first, Iterator const& last
          , Context const& context, RContext& rcontext, Attribute& attr, mpl::false_)
        {
            // inform user what went wrong if we jumped here in attempt to
            // parse incompatible sequence into fusion::map
            static_assert(!is_same< typename traits::attribute_category<Attribute>::type,
                  traits::associative_attribute>::value,
                  "To parse directly into fusion::map sequence must produce tuple attribute "
                  "where type of first element is existing key in fusion::map and second element "
                  "is value to be stored under that key");

            Attribute attr_;
            if (!parse_sequence(parser
			       , first, last, context, rcontext, attr_, traits::container_attribute()))
            {
                return false;
            }
            traits::append(attr, traits::begin(attr_), traits::end(attr_));
            return true;
        }

        template <typename Iterator, typename Attribute>
        static bool call(
            parser_type const& parser
          , Iterator& first, Iterator const& last
          , Context const& context, RContext& rcontext, Attribute& attr, mpl::true_)
        {
            return parse_into_container_base_impl<parser_type>::call(
                parser, first, last, context, rcontext, attr);
        }

        template <typename Iterator, typename Attribute>
        static bool call(
            parser_type const& parser
          , Iterator& first, Iterator const& last
          , Context const& context, RContext& rcontext, Attribute& attr)
        {
            typedef typename
                traits::attribute_of<parser_type, Context>::type
            attribute_type;

            typedef typename
                traits::container_value<Attribute>::type
            value_type;

            return call(parser, first, last, context, rcontext, attr
	        , typename traits::is_substitute<attribute_type, value_type>::type());
        }
    };

}}}}

#endif

ext: hpp


text:
/*
	This file is part of solidity.

	solidity is free software: you can redistribute it and/or modify
	it under the terms of the GNU General Public License as published by
	the Free Software Foundation, either version 3 of the License, or
	(at your option) any later version.

	solidity 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 General Public License for more details.

	You should have received a copy of the GNU General Public License
	along with solidity.  If not, see <http://www.gnu.org/licenses/>.
*/

#include <libsolutil/LazyInit.h>

#include <boost/test/unit_test.hpp>

#include <utility>

namespace solidity::util::test
{

namespace
{

template<typename T>
void assertInitCalled(LazyInit<T> lazyInit, bool target)
{
	bool initCalled = false;

	lazyInit.init([&]{
	  initCalled = true;
	  return T();
	});

	BOOST_REQUIRE_EQUAL(initCalled, target);
}

// Take ownership to ensure that it doesn't "mutate"
template<typename T>
void assertNotEmpty(LazyInit<T> _lazyInit) { assertInitCalled(std::move(_lazyInit), false); }

// Take ownership to ensure that it doesn't "mutate"
template<typename T>
void assertEmpty(LazyInit<T> _lazyInit) { assertInitCalled(std::move(_lazyInit), true); }

template<typename T>
T valueOf(LazyInit<T> _lazyInit)
{
	return _lazyInit.init([&]{
		BOOST_REQUIRE(false); // this should never be called
		return T();
	});
}

}

BOOST_AUTO_TEST_SUITE(LazyInitTests)

BOOST_AUTO_TEST_CASE(default_constructed_is_empty)
{
	assertEmpty(LazyInit<int>());
	assertEmpty(LazyInit<int const>());
}

BOOST_AUTO_TEST_CASE(initialized_is_not_empty)
{
	LazyInit<int> lazyInit;
	lazyInit.init([]{ return 12; });

	assertNotEmpty(std::move(lazyInit));
}

BOOST_AUTO_TEST_CASE(init_returns_init_value)
{
	LazyInit<int> lazyInit;

	BOOST_CHECK_EQUAL(lazyInit.init([]{ return 12; }), 12);

	// A second call to init should not change the value
	BOOST_CHECK_EQUAL(lazyInit.init([]{ return 42; }), 12);
}

BOOST_AUTO_TEST_CASE(moved_from_is_empty)
{
	{
		LazyInit<int> lazyInit;
		{ [[maybe_unused]] auto pilfered = std::move(lazyInit); }

		assertEmpty(std::move(lazyInit));
	}

	{
		LazyInit<int> lazyInit;
		lazyInit.init([]{ return 12; });

		{ [[maybe_unused]] auto pilfered = std::move(lazyInit); }

		assertEmpty(std::move(lazyInit));
	}
}

BOOST_AUTO_TEST_CASE(move_constructed_has_same_value_as_original)
{
	LazyInit<int> original;
	original.init([]{ return 12; });

	LazyInit<int> moveConstructed = std::move(original);
	BOOST_CHECK_EQUAL(valueOf(std::move(moveConstructed)), 12);
}

BOOST_AUTO_TEST_SUITE_END()

}

ext: cpp


text:
//==============================================================================
//         Copyright 2003 - 2011 LASMEA UMR 6602 CNRS/Univ. Clermont II
//         Copyright 2009 - 2011 LRI    UMR 8623 CNRS/Univ Paris Sud XI
//
//          Distributed under the Boost Software License, Version 1.0.
//                 See accompanying file LICENSE.txt or copy at
//                     http://www.boost.org/LICENSE_1_0.txt
//==============================================================================
#ifndef BOOST_SIMD_ARITHMETIC_FUNCTIONS_SIMD_COMMON_HYPOT_HPP_INCLUDED
#define BOOST_SIMD_ARITHMETIC_FUNCTIONS_SIMD_COMMON_HYPOT_HPP_INCLUDED

#include <boost/simd/arithmetic/functions/hypot.hpp>
#include <boost/simd/include/functions/simd/tofloat.hpp>
#include <boost/simd/include/functions/simd/abs.hpp>
#include <boost/simd/include/functions/simd/min.hpp>
#include <boost/simd/include/functions/simd/max.hpp>
#include <boost/simd/include/functions/simd/is_inf.hpp>
#include <boost/simd/include/functions/simd/is_nan.hpp>
#include <boost/simd/include/functions/simd/logical_and.hpp>
#include <boost/simd/include/functions/simd/logical_or.hpp>
#include <boost/simd/include/functions/simd/plus.hpp>
#include <boost/simd/include/functions/simd/minus.hpp>
#include <boost/simd/include/functions/simd/unary_minus.hpp>
#include <boost/simd/include/functions/simd/multiplies.hpp>
#include <boost/simd/include/functions/simd/bitwise_and.hpp>
#include <boost/simd/include/functions/simd/bitwise_or.hpp>
#include <boost/simd/include/functions/simd/logical_or.hpp>
#include <boost/simd/include/functions/simd/exponent.hpp>
#include <boost/simd/include/functions/simd/ldexp.hpp>
#include <boost/simd/include/functions/simd/if_else.hpp>
#include <boost/simd/include/functions/simd/is_greater.hpp>
#include <boost/simd/include/functions/simd/is_less.hpp>
#include <boost/simd/include/functions/simd/sqrt.hpp>
#include <boost/simd/include/functions/simd/bitwise_cast.hpp>
#include <boost/simd/include/constants/zero.hpp>
#include <boost/simd/include/constants/inf.hpp>
#include <boost/simd/include/functions/simd/max.hpp>
#include <boost/simd/include/constants/int_splat.hpp>
#include <boost/simd/sdk/simd/logical.hpp>
#include <boost/dispatch/meta/as_floating.hpp>
#include <boost/dispatch/meta/as_integer.hpp>

namespace boost { namespace simd { namespace ext
{
  BOOST_SIMD_FUNCTOR_IMPLEMENTATION( boost::simd::tag::hypot_, tag::cpu_
                            , (A0)(X)
                            , ((simd_<arithmetic_<A0>,X>))((simd_<arithmetic_<A0>,X>))
                            )
  {

    typedef typename dispatch::meta::as_floating<A0>::type result_type;

    BOOST_SIMD_FUNCTOR_CALL_REPEAT(2)
    {
      return boost::simd::hypot(tofloat(a0), tofloat(a1));
    }
  };

  BOOST_SIMD_FUNCTOR_IMPLEMENTATION(boost::simd::tag::hypot_, tag::cpu_,
                              (A0)(X),
                              ((simd_<floating_<A0>,X>))
                              ((simd_<floating_<A0>,X>))
                            )
  {
    template < class T, class I = typename dispatch::meta::as_integer<T, signed>::type>
    struct hypot_ctnts {};

    template <class I, class CAT>
    struct hypot_ctnts<simd::native<float, CAT>, I>
    {
      typedef I  int_type;
      static inline int_type C1(){ return boost::simd::integral_constant<int_type, 50>();};
      static inline int_type C2(){ return boost::simd::integral_constant<int_type, 60>();};
      static inline int_type MC1(){ return boost::simd::integral_constant<int_type, -50>();};
      static inline int_type MC2(){ return boost::simd::integral_constant<int_type, -60>();};
      static inline int_type C3(){ return boost::simd::integral_constant<int_type, 0x00800000>();};
      static inline int_type M1(){ return boost::simd::integral_constant<int_type, 0xfffff000>();};
    };

    template <class I, class CAT>
    struct hypot_ctnts<simd::native<double, CAT>, I>
    {
      typedef I  int_type;
      static inline int_type C1(){ return boost::simd::integral_constant<int_type, 500>();};
      static inline int_type C2(){ return boost::simd::integral_constant<int_type, 600>();};
      static inline int_type MC1(){ return boost::simd::integral_constant<int_type, -500>();};
      static inline int_type MC2(){ return boost::simd::integral_constant<int_type, -600>();};
      static inline int_type C3(){ return boost::simd::integral_constant<int_type, 0x0010000000000000ll>();}
      static inline int_type M1(){ return boost::simd::integral_constant<int_type, 0xffffffff00000000ll>();};
    };

    typedef typename dispatch::meta::as_floating<A0>::type result_type;

    BOOST_SIMD_FUNCTOR_CALL_REPEAT(2)
    {
      typedef typename dispatch::meta::as_integer<result_type>::type itype;
      result_type r =  boost::simd::abs(a0);
      result_type i =  boost::simd::abs(a1);
      itype e =  exponent(boost::simd::max(i, r));
      return  if_else( logical_or(logical_and(is_nan(a0), is_inf(a1)),
                                  logical_and(is_nan(a1), is_inf(a0))),
                       Inf<result_type>(),
                       ldexp(sqrt(sqr(ldexp(r, -e))+sqr(ldexp(i, -e))), e)
                       );
    }
  };
} } }

#endif


text:
/**
 * @file instruction.cpp
 * @brief
 *
 * @author Levi Armstrong
 * @date June 15, 2020
 * @version TODO
 * @bug No known bugs
 *
 * @copyright Copyright (c) 2020, Southwest Research Institute
 *
 * @par License
 * Software License Agreement (Apache License)
 * @par
 * 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
 * @par
 * 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.
 */

#include <tesseract_common/macros.h>
TESSERACT_COMMON_IGNORE_WARNINGS_PUSH
#include <iostream>
TESSERACT_COMMON_IGNORE_WARNINGS_POP

#include <tesseract_command_language/null_instruction.h>

namespace tesseract_planning
{
const std::string& NullInstruction::getDescription() const { return description_; }

void NullInstruction::setDescription(const std::string& description) { description_ = description; }

void NullInstruction::print(const std::string& prefix) const  // NOLINT
{
  std::cout << prefix + "Null Instruction, Description: " << getDescription() << std::endl;
}
bool NullInstruction::operator==(const NullInstruction& /*rhs*/) const { return true; }
bool NullInstruction::operator!=(const NullInstruction& /*rhs*/) const { return false; }

template <class Archive>
void NullInstruction::serialize(Archive& /*ar*/, const unsigned int /*version*/)
{
}
}  // namespace tesseract_planning

#include <boost/archive/xml_oarchive.hpp>
#include <boost/archive/xml_iarchive.hpp>
template void tesseract_planning::NullInstruction::serialize(boost::archive::xml_oarchive& ar,
                                                             const unsigned int version);
template void tesseract_planning::NullInstruction::serialize(boost::archive::xml_iarchive& ar,
                                                             const unsigned int version);

TESSERACT_INSTRUCTION_EXPORT_IMPLEMENT(tesseract_planning::NullInstruction);


text:
#include <iostream>
#include <Eigen/Dense>  // 稠密矩阵的代数运算，如求逆，特征值等

using namespace std;

int main(int argc, char** argv) {
    Eigen::MatrixXd m(2,2);  // 声明一个2x2的矩阵
    m(0, 0) = 3;  // 开始矩阵赋值
    m(1, 0) = 2.5;
    m(0, 1) = -1;
    m(1, 1) = m(1, 0) + m(0, 1);
    cout << m << endl;  // 打印矩阵
    return 0;
}

max_stars_repo_name: gkimeeq/SLAMLearning

max_issues_repo_name: gkimeeq/SLAMLearning

max_forks_repo_name: gkimeeq/SLAMLearning


text:
//
// Created by briand on 3/21/19.
//

#include "MPICalibratorDirector.h"
#include "MPICalibratorCommon.h"

#include <cmath>
#include <thread>
#include <chrono>
#include <sstream>
#include <set>

#include <boost/log/trivial.hpp>

#define USE_BOOST_KARMA

#include <bprinter/table_printer.h>

#include <armadillo>
#include <ensmallen.hpp>

#include <Engines/Internals/InternalsUtilityFunctions.h>
#include <Utilities/LogUtils.h>

#include <bprinter/table_printer.h>

#include <boost/serialization/string.hpp>
#include <boost/regex.hpp>
#include <boost/lexical_cast.hpp>
#include <boost/filesystem.hpp>

#include <boost/archive/text_oarchive.hpp>
#include <boost/archive/text_iarchive.hpp>

using boost::lexical_cast;

namespace SmolDock::Calibration {

    MPICalibratorDirector::MPICalibratorDirector(mpi::environment& env_,
                                                 mpi::communicator& world_,
                                                 Score::ScoringFunctionType scFuncType,
                                                 Heuristics::GlobalHeuristicType heurType,
                                                 Optimizer::LocalOptimizerType localOptimizerType_,
                                                 unsigned int maxLearningSteps,
                                                 double stepSize_,
                                                 unsigned int rngSeed,
                                                 unsigned int conformerNumber,
                                                 unsigned int retryNumber,
                                                 unsigned int batchSize_,
                                                 Heuristics::HeuristicParameters hParams,
                                                 const std::string& restoreArchivePrefix_)
            :
            Calibrator(scFuncType,
                       heurType,
                       localOptimizerType_,
                       maxLearningSteps,
                       stepSize_,
                       rngSeed, conformerNumber,
                       retryNumber,
                       batchSize_,
                       hParams),
            env(env_),
            world(world_),
            restoreArchivePrefix(restoreArchivePrefix_) {
        this->numProcess = this->world.size();

    }

    bool MPICalibratorDirector::setupCalibration() {

        for (unsigned int j = 1; j < this->numProcess; ++j) {
            RegisterMessage rmsg;
            this->world.recv(j, MTags::RegisterNode, rmsg);
            this->nodeInfo.push_back(rmsg);
            this->numTotalCPU += rmsg.numThread;

            BOOST_LOG_TRIVIAL(info) << "Registed node " << j << " with " << rmsg.numThread << " threads.";
        }

        // Determining optimal allocation of workItem depending on available CPU on each node

        int remainingWorkItemToAllocate = this->batchSize;
        for (unsigned int j = 0; j < this->nodeInfo.size(); ++j) {
            double fractionOfWorkload = static_cast<double>(this->nodeInfo.at(j).numThread) / static_cast<double>(numTotalCPU);
            unsigned int numWorkItem = static_cast<unsigned int>(this->batchSize * fractionOfWorkload);
            this->numWorkItemPerNode.push_back(numWorkItem);
            remainingWorkItemToAllocate -= numWorkItem;
        }

        if(remainingWorkItemToAllocate >= 0)
        {
            // Spread out the remaining work items
            unsigned int currRank = 1;
            while(remainingWorkItemToAllocate > 0) {
                this->numWorkItemPerNode.at(currRank) += 1;
                remainingWorkItemToAllocate--;
                if(currRank == this->nodeInfo.size() - 1)
                    currRank = 1;
                else
                    currRank++;
            }
        }else {
            BOOST_LOG_TRIVIAL(error) << "Unexpected oversubsciption of work item per batch.";
            BOOST_LOG_TRIVIAL(error) << "   Batch size : " << this->batchSize;
            for (unsigned int j = 0; j < this->numWorkItemPerNode.size(); ++j) {
                BOOST_LOG_TRIVIAL(error) << "   - Node " << j+1 << " : " << this->numWorkItemPerNode.at(j) << " work items/batch";
            }
            BOOST_LOG_TRIVIAL(error) << "   Remaining work item : " << remainingWorkItemToAllocate;
            std::terminate();
        }

        // Rebalancing slightly to avoid node with 0 work items
        // NB : This may not be optimal if the nodes are very imbalanced
        //      but it is expected that one would prefer to have all nodes
        //      do at least some work ? To be discussed if problem arises.

        // Find nodes with max workload
        unsigned int maxWorkItem = 0;
        std::vector<unsigned int> idxMaxWorkItem;
        for (unsigned int j = 0; j < this->nodeInfo.size(); ++j) {
            unsigned int numWorkItemForNode = this->numWorkItemPerNode.at(j);
            if(numWorkItemForNode > maxWorkItem) {
                maxWorkItem = numWorkItemForNode;
                idxMaxWorkItem.push_back(j);
            }
        }

        // Find nodes with 0 workload
        std::vector<unsigned int> idxZeroItem;
        for (unsigned int j = 0; j < this->nodeInfo.size(); ++j) {
            unsigned int numWorkItemForNode = this->numWorkItemPerNode.at(j);
            if(numWorkItemForNode == 0) {
                idxZeroItem.push_back(j);
            }
        }

        auto it_maxLoadedNodeIdx = idxMaxWorkItem.begin();
        for(auto zeroWorkNodeIdx : idxZeroItem) {
            if(this->numWorkItemPerNode.at(std::distance(idxMaxWorkItem.begin(), it_maxLoadedNodeIdx)) > 2) {
                this->numWorkItemPerNode.at(zeroWorkNodeIdx) += 1;
                this->numWorkItemPerNode.at(std::distance(idxMaxWorkItem.begin(), it_maxLoadedNodeIdx)) -= 1;
            }
            if((it_maxLoadedNodeIdx + 1) == idxMaxWorkItem.end()) {
                    // No more max loaded node to rebalance
                    // We continue to unload this one
                    continue;
            } else {
                it_maxLoadedNodeIdx++;
            }
        }

        // Final consistency check
        unsigned int sumWorkItem = 0;
        for (unsigned int j = 0; j < this->nodeInfo.size(); ++j) {
            unsigned int numWorkItemForNode = this->numWorkItemPerNode.at(j);
            sumWorkItem += numWorkItemForNode;
        }

        if(sumWorkItem != this->batchSize) {
            BOOST_LOG_TRIVIAL(error) << "Work load balancing unexpectedly failed ??";
            BOOST_LOG_TRIVIAL(error) << "   Batch size : " << this->batchSize;
            for (unsigned int j = 0; j < this->numWorkItemPerNode.size(); ++j) {
                BOOST_LOG_TRIVIAL(error) << "   - Node " << j+1 << " : " << this->numWorkItemPerNode.at(j) << " work items/batch";
            }
            std::terminate();
        }

        BOOST_LOG_TRIVIAL(info) << "Batch mapping information :";
        BOOST_LOG_TRIVIAL(info) << "   Batch size : " << this->batchSize;
        for (unsigned int j = 0; j < this->numWorkItemPerNode.size(); ++j) {
            BOOST_LOG_TRIVIAL(info) << "   - Node " << j+1 <<
            " : " << this->nodeInfo.at(j).numThread <<
            " CPU for " << this->numWorkItemPerNode.at(j) << " work items/batch";
        }

        //this->numWorkItemPerNode

        std::uniform_int_distribution<int> dis_int(0, std::numeric_limits<int>::max());

        this->workStructure.numReceptor = this->pdbBlockStrings.size();
        this->workStructure.conformerPerLigand = this->conformerNumber;
        this->workStructure.retryPerConformer = this->retryNumber;
        this->workStructure.numRegisteredVariant = this->variantsForAllLigands.size();
        this->workStructure.totalNumLigand = this->totalNumLigand;
        this->workStructure.numAnchorLigand = this->numAnchorLigand;
        this->workStructure.seed = dis_int(this->rndGenerator);
        this->workStructure.numCoeffToCalibrate = this->idxOfCoeffsToCalibrate.size();
        this->workStructure.idxOfCoeffsToCalibrate = this->idxOfCoeffsToCalibrate;
        this->workStructure.scoringFunctionType =this->scoringFunctionType;
        this->workStructure.heuristicType =this->heuristicType;
        this->workStructure.localOptimizerType =this->localOptimizerType;
        this->workStructure.differentialEpsilon = 0.5e-7;

        mpi::broadcast(world, this->workStructure, 0);

        for (unsigned int k = 0; k < this->workStructure.numReceptor; ++k) {
            ReceptorRecord rr;
            rr.PDBBlock = this->pdbBlockStrings[k];
            rr.dbsetting = this->dbSettings[k];
            rr.specialResTypes = this->specialResidueTypings[k];
            mpi::broadcast(world, rr, 0);
        }

        for (unsigned int k = 0; k < this->workStructure.numRegisteredVariant; ++k) {
            mpi::broadcast(world, this->variantsForAllLigands[k], 0);
        }

        for (unsigned int k = 0; k < this->current_max_ReceptorID; ++k) {
            for (unsigned int j = 0; j < this->ligandSmilesRefScore[k].size(); ++j) {
                LigandRecord lr;
                lr.receptorID = k;
                lr.smiles = std::get<std::string>(this->ligandSmilesRefScore[k][j]);
                lr.deltaG = std::get<double>(this->ligandSmilesRefScore[k][j]);
                lr.isAnchor = false;
                lr.molblock = "";
                mpi::broadcast(world, lr, 0);
            }
            for (unsigned int j = 0; j < this->anchorLigands[k].size(); ++j) {
                LigandRecord lr;
                lr.receptorID = k;
                lr.smiles = this->anchorLigands[k][j]->writeToSMILES();
                lr.deltaG = 0.0;
                lr.isAnchor = true;
                lr.molblock = this->anchorLigands[k][j]->writeToMolBlock();
                mpi::broadcast(world, lr, 0);
            }
            this->numLigandPerReceptor.push_back(this->ligandSmilesRefScore[k].size());
            this->numAnchorLigandPerReceptor.push_back(this->anchorLigands[k].size());
        }

        for (unsigned int l = 0; l < this->totalNumLigand; ++l) {
            this->indexShuffler.push_back(l);
        }

        for (unsigned int j = 1; j < this->numProcess; ++j) {
            int status;
            this->world.recv(j, MTags::ReadyForWork, status);
            BOOST_LOG_TRIVIAL(info) << "Node " << j << " ready. (status = " << status <<")";
        }

        return true;
    }

    bool MPICalibratorDirector::runCalibration() {

        calibrationStillRunning = true;
        std::thread statusPrinter(&MPICalibratorDirector::updateAndPrintStatus, this);

        arma::mat coeffs_internalRepr = arma::mat(this->idxOfCoeffsToCalibrate.size(), 1);
        for (unsigned int k = 0; k < coeffs_internalRepr.n_rows; ++k) {
            coeffs_internalRepr[k] = this->currentCoeffs[this->idxOfCoeffsToCalibrate[k]];
        }

        ens::Adam optimizer(this->stepSize, this->batchSize, 0.9, 0.999, 1e-8, this->maxLearningSteps, 1e-6, true);
        optimizer.Optimize(*this, coeffs_internalRepr);

        this->optResultMat = coeffs_internalRepr;

        std::vector<double> updateCoeffsVector = this->currentCoeffs;

        for (unsigned int j = 0; j < this->idxOfCoeffsToCalibrate.size(); ++j) {
            unsigned int idxCoeff = this->idxOfCoeffsToCalibrate[j];
            std::string coeffName = this->nameOfAllCoeffs[idxCoeff];
            double nonUpdatedCoeff = this->currentCoeffs[idxCoeff];

            updateCoeffsVector[idxCoeff] = coeffs_internalRepr[j];

            BOOST_LOG_TRIVIAL(info) << "COEFFICIENT " << coeffName << " ---- ";
            BOOST_LOG_TRIVIAL(info) << "   Old coeff        : " << nonUpdatedCoeff;
            BOOST_LOG_TRIVIAL(info) << "   New coeff        : " << coeffs_internalRepr[j];
            BOOST_LOG_TRIVIAL(info) << " ----------------------------- \n";
        }

        for (unsigned int j = 1; j < this->numProcess; ++j) {
            Task t;
            t.endOfTasks = true;
            this->world.send(j, MTags::TaskRequest, t);

            int status;
            this->world.recv(j, MTags::NodeTerminating, status);
            BOOST_LOG_TRIVIAL(info) << "Node " << j << " terminated. (status = " << status <<")";
        }

        calibrationStillRunning = false;
        statusPrinter.join();

        return true;
    }

    bool MPICalibratorDirector::addReferenceLigand_SMILES_Ki(Calibrator::ReceptorID recID, const std::string& smiles,
                                                             double Ki) {

        const double R = 8.3144598;
        const double T = 310.15; // 37 degree celsius
        double deltaG = R * T * std::log(Ki) / 1000; // kcal/mol aka same as other docking software

        this->addReferenceLigand_SMILES_deltaG(recID,smiles,deltaG);
        return true;
    }

    bool MPICalibratorDirector::addReferenceLigand_SMILES_deltaG(Calibrator::ReceptorID recID,
                                                             const std::string& smiles,
                                                             double deltaG) {
        this->ligandSmilesRefScore[recID].emplace_back(std::make_tuple(smiles,deltaG));
        this->totalNumLigand++;
        return true;
    }

    bool MPICalibratorDirector::addReferenceLigand_Mol_Ki(Calibrator::ReceptorID recID, const Molecule& mol, double Ki) {

        BOOST_LOG_TRIVIAL(error) << "Cannot add ligand from Molecule class in MPICalibrator.";
        std::terminate();
        return Calibrator::addReferenceLigand_Mol_Ki(recID, mol, Ki);
    }

    Calibrator::ReceptorID MPICalibratorDirector::addReceptorFromFile(const std::string& filename,
                                                                      Engine::AbstractDockingEngine::DockingBoxSetting dbsettings) {
        std::ifstream input(filename);
        std::stringstream sstr;
        sstr << input.rdbuf();

        this->pdbBlockStrings.push_back(sstr.str());
        this->dbSettings.push_back(dbsettings);
        this->specialResidueTypings.push_back(std::vector<MPISpecialResidueTyping>());

        this->current_max_ReceptorID++;
        return this->current_max_ReceptorID - 1;
    }

    Calibrator::ReceptorID MPICalibratorDirector::addReceptor(const Protein& prot,
                                                              Engine::AbstractDockingEngine::DockingBoxSetting dbsettings) {

        BOOST_LOG_TRIVIAL(error) << "Cannot add receptor from Protein class in MPICalibrator.";
        std::terminate();

        return Calibrator::addReceptor(prot, dbsettings);
    }

    bool MPICalibratorDirector::applyVariantToAllLigands(const std::string& SMARTSPattern, Atom::AtomVariant variant) {
        RegisteredVariant r;
        r.smarts = SMARTSPattern;
        r.atomVariant = static_cast<unsigned int>(variant);
        this->variantsForAllLigands.push_back(r);
        return true;
    }

    double MPICalibratorDirector::EvaluateWithGradient(const arma::mat& x,
                                                       const size_t i,
                                                       arma::mat& g,
                                                       const size_t batchSize) {

        // Basically this is an allocation mecanism to have an amount of work item per node
        // roughly proportional to the number of cpu on each node
        // (We have collected the CPU #/node when initializing.)
        // (We use intel TBB to spread the work on all CPU available per node, so this allow
        // us to have around the same runtime for each node, so we dont wait for the weakest node)
        // TODO : we need to handle slurm-type job manager, where we wont necessarily be able to just
        // use all the CPUs of the node.
        unsigned int currentSendRank = 1; // Careful : this is (rightfully) off-by-one from our array access index
        std::vector<unsigned int> remainingWorkItemCapacity = this->numWorkItemPerNode;

        std::vector<mpi::request> taskRequests;
        std::vector<Task> tasks;

        std::vector<double> currCoeffsUpdated = this->currentCoeffs;
        for (unsigned int k = 0; k < this->idxOfCoeffsToCalibrate.size(); ++k) {
            currCoeffsUpdated[this->idxOfCoeffsToCalibrate[k]] = x(k);
        }
        coefficientHistory.push_back(currCoeffsUpdated);

        for (unsigned int k = i; k < (i + batchSize); ++k) {

            if(remainingWorkItemCapacity[currentSendRank - 1] == 0) {
                // The current rank has no more cpu for us to run
                if(currentSendRank == remainingWorkItemCapacity.size()) {
                    // We have consumed every available cpu for this cycle, we start a new one
                    currentSendRank = 1;
                    remainingWorkItemCapacity = this->numWorkItemPerNode;
                }else{
                    // We use the next node
                    currentSendRank++;
                }
            }
            // In any cases, we will consume one cpu for the current item
            remainingWorkItemCapacity[currentSendRank - 1]--;

            unsigned int realIdx = this->indexShuffler[k];
            std::tuple<unsigned int, unsigned int> rdlidx = RecLigIdxFromGlobalIdx(realIdx);

            auto& t = tasks.emplace_back((Task()));
            t.receptorID = std::get<0>(rdlidx);
            t.ligandIdx = std::get<1>(rdlidx);

            t.coefficients = currCoeffsUpdated;

            if(realIdx < (totalNumLigand - numAnchorLigand)) {
                // it a normal (non-anchor) ligand
                t.anchorLigandTask = false;
            } else {
                // its an anchor ligand
                t.anchorLigandTask = true;
            }

            taskRequests.push_back(this->world.isend(currentSendRank, MTags::TaskRequest, t));

        }

        BOOST_LOG_TRIVIAL(info) << "[Epoch " << this->batchCount << "] Task request queued.";

        std::chrono::time_point<std::chrono::system_clock> start, end;
        start = std::chrono::system_clock::now();

        currentSendRank = 1;
        remainingWorkItemCapacity = this->numWorkItemPerNode;

        std::vector<Result> resultList;
        for (unsigned int k = i; k < (i + batchSize); ++k) {
            resultList.push_back((Result()));
            Result& r = resultList.back();
            this->world.recv(boost::mpi::any_source, MTags::ResultMessage, r);
            BOOST_LOG_TRIVIAL(debug) << "Received " << (k - i + 1)  << " of " << batchSize << " results.";
            BOOST_LOG_TRIVIAL(debug) << "  Result  ";
            BOOST_LOG_TRIVIAL(debug) << "     |   loss          :  " << r.loss;
            BOOST_LOG_TRIVIAL(debug) << "     |   loss gradient :  " << vectorToString(r.lossGradient);
        }

        end = std::chrono::system_clock::now();
        int elapsed_minutes = std::chrono::duration_cast<std::chrono::minutes>
                (end-start).count();
        BOOST_LOG_TRIVIAL(info) << "[Epoch " << this->batchCount << "] All results received.";
        this->durationHistory.push_back(elapsed_minutes);

        const unsigned int numItems = resultList.size();
        const unsigned int numCoefficients = x.n_rows;
        double totalLoss = 0.0;
        std::vector<double> totalGradientLoss(static_cast<size_t>(numCoefficients)); // this constructor will initialize to 0.0
        for(const Result& result : resultList) {
            totalLoss += result.loss;
            for (unsigned int j = 0; j < numCoefficients; ++j) {
                totalGradientLoss.at(j) += result.lossGradient.at(j);
            }
        }

        const double meanLoss = totalLoss / numItems;
        this->gradientHistory.push_back(std::vector<double>());
        for (unsigned int j = 0; j < numCoefficients; ++j) {
            const double meanGradComponentValue = totalGradientLoss.at(j) / numItems;
            g(j) = meanGradComponentValue;
            this->gradientHistory.back().push_back(meanGradComponentValue);
        }

        this->lossHistory.push_back(meanLoss);

        BOOST_LOG_TRIVIAL(info) << "[Epoch " << this->batchCount << "] Mean loss : " << meanLoss;
        BOOST_LOG_TRIVIAL(info) << "   Duration : " << elapsed_minutes << " minutes";
        BOOST_LOG_TRIVIAL(info) << "   History : ";

        bprinter::TablePrinter tp_lossDuration(&std::cout);
        tp_lossDuration.AddColumn("Epoch", 8);
        tp_lossDuration.AddColumn("Mean loss", 20);
        tp_lossDuration.AddColumn("Duration (min)", 20);

        tp_lossDuration.PrintHeader();
        for (unsigned int l = 0; l < this->lossHistory.size(); ++l) {
            tp_lossDuration << l << this->lossHistory.at(l) << this->durationHistory.at(l);

        }
        tp_lossDuration.PrintFooter();

        bprinter::TablePrinter tp_coeffsGradients(&std::cout);
        tp_coeffsGradients.AddColumn("Epoch", 8);
        tp_coeffsGradients.AddColumn("Metric", 12);
        tp_coeffsGradients.AddColumn("Value", 60);

        tp_coeffsGradients.PrintHeader();
        for (unsigned int l = 0; l < this->lossHistory.size(); ++l) {
            tp_lossDuration << l << "Loss" <<  this->lossHistory.at(l);
            tp_lossDuration << l << "Coeffs" <<  vectorToString(this->coefficientHistory.at(l));
            tp_lossDuration << l << "Gradient" <<  vectorToString(this->gradientHistory.at(l));
        }
        tp_coeffsGradients.PrintFooter();

        this->batchCount++;

        const boost::regex my_filter(this->restoreArchivePrefix + std::string("([0-9]+)\\.restore-state") );

        int max_num = -1;
        boost::filesystem::directory_iterator end_itr; // Default ctor yields past-the-end
        for( boost::filesystem::directory_iterator i("./"); i != end_itr; ++i )
        {
            // Skip if not a file
            if( !boost::filesystem::is_regular_file( i->status() ) ) continue;

            boost::smatch what;

            // Skip if no match for V2:
            //if( !boost::regex_match( i->leaf(), what, my_filter ) ) continue;
            // For V3:
            std::string path_as_string = i->path().filename().string();
            bool res = boost::regex_match( path_as_string, what, my_filter, boost::match_extra) ;
            if(!res) continue;
            int numFile = lexical_cast<int>(what[1]);
            if(numFile > max_num) {
                max_num = numFile;
            }
        }

        std::string filename;
        if(max_num != -1) {
            filename = this->restoreArchivePrefix + std::to_string(max_num + 1) + std::string(".restore-state");
        } else {
            filename = this->restoreArchivePrefix + std::to_string(1) + std::string(".restore-state");
        }
        BOOST_LOG_TRIVIAL(info) << "Saving to " << filename;

        std::ofstream ofs(filename);
        {
            boost::archive::text_oarchive oa(ofs);
            MPICalibratorDirector_ResumeObject resumeObject =  this->createResumeState();
            oa << resumeObject;
        }
        BOOST_LOG_TRIVIAL(info) << "Saved.";

        BOOST_LOG_TRIVIAL(info) << "\n\n    ------\n\n";

        return meanLoss;
    }

    void MPICalibratorDirector::Shuffle() {
        std::shuffle(this->indexShuffler.begin(), this->indexShuffler.end(), this->rndGenerator);
    }

    size_t MPICalibratorDirector::NumFunctions() {
        return this->totalNumLigand;
    }

    std::tuple<unsigned int, unsigned int> MPICalibratorDirector::RecLigIdxFromGlobalIdx(unsigned int idx) {
        /**
         * We have N receptor with M_n ligands each
         * The global index goes ligand 0 of receptor 0, ligand 1 of receptor 0 ... ligand M_1 of receptor 0
         * then ligand 0 of receptor 1, etc etc
         * So we use the numLigandPerReceptor to get back to the local index of the ligand for a given receptor
         *
         * Additionally, after the end of the normal (non-anchor) ligand, we have the same system for the anchor ligands
         *
         * NB: Code is duplicated for ease of comprehension
         * */
         if(idx < (this->totalNumLigand - this->numAnchorLigand)) {
             unsigned int currRecId = 0;
             for(unsigned int& numLigForRec : this->numLigandPerReceptor)
             {
                 if(static_cast<long int>(idx) - static_cast<long int>(numLigForRec) < 0)
                 {
                     return std::make_tuple(currRecId, idx);
                 }
                 idx = idx - numLigForRec;
                 currRecId++;
             }
         } else  {
             unsigned int anchor_idx = idx - (this->totalNumLigand - this->numAnchorLigand);
             unsigned int currRecId = 0;
             for(unsigned int& numAnchorLigForRec : this->numAnchorLigandPerReceptor)
             {
                 if(static_cast<long int>(anchor_idx) - static_cast<long int>(numAnchorLigForRec) < 0)
                 {
                     return std::make_tuple(currRecId, anchor_idx);
                 }
                 anchor_idx = anchor_idx - numAnchorLigForRec;
                 currRecId++;
             }
         }

        BOOST_LOG_TRIVIAL(error) << "Unexpected indexing error : unable to translate global index " << idx;
        BOOST_LOG_TRIVIAL(error) << "   Total num ligand : " << this->totalNumLigand;
        BOOST_LOG_TRIVIAL(error) << "   Anchor ligand : " << this->numAnchorLigand;
        BOOST_LOG_TRIVIAL(error) << "   Non-anchor (deduced) : " << (this->totalNumLigand - this->numAnchorLigand);
        BOOST_LOG_TRIVIAL(error) << "Internal state not sound, terminating.";
        std::terminate();
        return std::make_tuple(0, idx);
    }

    bool MPICalibratorDirector::applySpecialResidueTypingFromRecID(Calibrator::ReceptorID recID,
                                                                   const AminoAcid::AAType resType,
                                                                   const unsigned int serialNumber,
                                                                   const SpecialResidueTyping specialType) {
        MPISpecialResidueTyping srt;
        srt.aaType = static_cast<unsigned int>(resType);
        srt.serialNumber = serialNumber;
        srt.specialTyping = static_cast<unsigned int>(specialType);
        this->specialResidueTypings[static_cast<unsigned int>(recID)].push_back(srt);
        return false;
    }

    void MPICalibratorDirector::updateAndPrintStatus() {
        while(calibrationStillRunning == true)
        {
            using namespace std::chrono_literals;
            std::this_thread::sleep_for(10s);
        }

    }

    bool MPICalibratorDirector::addAnchorLigandFromMol2File(ReceptorID recID, std::string& filename) {
        auto aLig = std::make_shared<Molecule>();
        aLig->populateFromMol2File(filename);

        this->anchorLigands[recID].push_back(aLig);
        this->numAnchorLigand++;
        this->totalNumLigand++;
        return true;
    }

    MPICalibratorDirector_ResumeObject MPICalibratorDirector::createResumeState() {
        MPICalibratorDirector_ResumeObject ro;
        ro.lossHistory = this->lossHistory;
        ro.durationHistory = this->durationHistory;
        ro.coefficientHistory = this->coefficientHistory;
        ro.gradientHistory = this->gradientHistory;

        ro.currentCoeffs = this->currentCoeffs;

        ro.coeffsToCalibrate = this->coeffsToCalibrate;
        ro.nameOfAllCoeffs = this->nameOfAllCoeffs;
        ro.idxOfCoeffsToCalibrate = this->idxOfCoeffsToCalibrate;

        ro.scoringFunctionType = this->scoringFunctionType;
        ro.heuristicType = this->heuristicType;
        ro.localOptimizerType = this->localOptimizerType;
        return ro;
    }

    bool MPICalibratorDirector::restoreResumeState(const MPICalibratorDirector_ResumeObject& state) {
        this->lossHistory = state.lossHistory;
        this->durationHistory = state.durationHistory;
        this->coefficientHistory = state.coefficientHistory;
        this->gradientHistory = state.gradientHistory;

        this->currentCoeffs = state.currentCoeffs;

        this->coeffsToCalibrate = state.coeffsToCalibrate;
        this->nameOfAllCoeffs = state.nameOfAllCoeffs;
        this->idxOfCoeffsToCalibrate = state.idxOfCoeffsToCalibrate;

        this->scoringFunctionType = state.scoringFunctionType;
        this->heuristicType = state.heuristicType;
        this->localOptimizerType = state.localOptimizerType;

        // Duplicate removal
        {
            std::set<int> s_idx;
            unsigned size = this->idxOfCoeffsToCalibrate.size();
            for( unsigned i = 0; i < size; ++i ) s_idx.insert( this->idxOfCoeffsToCalibrate[i] );
            this->idxOfCoeffsToCalibrate.assign( s_idx.begin(), s_idx.end() );
        }

        {
            std::set<std::string> s_allCoeffsName;
            unsigned size = this->nameOfAllCoeffs.size();
            for( unsigned i = 0; i < size; ++i ) s_allCoeffsName.insert( this->nameOfAllCoeffs[i] );
            this->nameOfAllCoeffs.assign( s_allCoeffsName.begin(), s_allCoeffsName.end() );
        }

        {
            std::set<std::string> s_coeffsToCalibrate;
            unsigned size = this->nameOfAllCoeffs.size();
            for( unsigned i = 0; i < size; ++i ) s_coeffsToCalibrate.insert( this->coeffsToCalibrate[i] );
            this->coeffsToCalibrate.assign( s_coeffsToCalibrate.begin(), s_coeffsToCalibrate.end() );
        }

        // FIX for currentCoeffs containing the first coeffs actually
        this->currentCoeffs = this->coefficientHistory.back();

        {
            iConformer dummy_cf;
            dummy_cf.num_rotatable_bond = 0;
            iProtein dummy_prot;
            iTransform dummy_tr = iTransformIdentityInit(0);
            auto dummy_sf = scoringFunctionFactory(this->scoringFunctionType,
                                                    dummy_cf,
                                                    dummy_prot,
                                                    dummy_tr,
                                                    1e-3,
                                                    true);
            std::vector<std::string> names = dummy_sf->getCoefficientsNames();
            unsigned int num_coeffs = names.size();
            this->currentCoeffs.erase(this->currentCoeffs.begin() + num_coeffs, this->currentCoeffs.end());
        }

        this->batchCount = this->coefficientHistory.size();

        return true;
    }

}

max_stars_repo_name: ElianeBriand/SMolDock

max_issues_repo_name: ElianeBriand/SMolDock

max_forks_repo_name: ElianeBriand/SMolDock


text:
// Boost.Geometry (aka GGL, Generic Geometry Library)
// Unit Test

// Copyright (c) 2010-2011 Barend Gehrels, Amsterdam, the Netherlands.

// Use, modification and distribution is subject to the Boost Software License,
// Version 1.0. (See accompanying file LICENSE_1_0.txt or copy at
// http://www.boost.org/LICENSE_1_0.txt)

#ifndef GEOMETRY_TEST_TEST_GEOMETRIES_CUSTOM_SEGMENT_HPP
#define GEOMETRY_TEST_TEST_GEOMETRIES_CUSTOM_SEGMENT_HPP

#include <boost/geometry/geometries/register/point.hpp>
#include <boost/geometry/geometries/register/segment.hpp>

#include <boost/geometry/core/tag.hpp>
#include <boost/geometry/core/tags.hpp>

namespace test
{

struct custom_point_for_segment
{
    double x, y;
};

struct custom_segment
{
    custom_point_for_segment one, two;
};

template <typename P>
struct custom_segment_of
{
    P p1, p2;
};

struct custom_segment_4
{
    double a, b, c, d;
};

} // namespace test

BOOST_GEOMETRY_REGISTER_POINT_2D(test::custom_point_for_segment, double, cs::cartesian, x, y)

BOOST_GEOMETRY_REGISTER_SEGMENT(test::custom_segment, test::custom_point_for_segment, one, two)
BOOST_GEOMETRY_REGISTER_SEGMENT_TEMPLATIZED(test::custom_segment_of, p1, p2)
BOOST_GEOMETRY_REGISTER_SEGMENT_2D_4VALUES(test::custom_segment_4, test::custom_point_for_segment, a, b, c, d)

#endif // GEOMETRY_TEST_TEST_GEOMETRIES_CUSTOM_SEGMENT_HPP


text:
//==================================================================================================
/**
  Copyright 2016 NumScale SAS

  Distributed under the Boost Software License, Version 1.0.
  (See accompanying file LICENSE.md or copy at http://boost.org/LICENSE_1_0.txt)
**/
//==================================================================================================
#ifndef BOOST_SIMD_ARCH_X86_SSE1_SCALAR_FUNCTION_REC_HPP_INCLUDED
#define BOOST_SIMD_ARCH_X86_SSE1_SCALAR_FUNCTION_REC_HPP_INCLUDED

#include <boost/simd/detail/overload.hpp>
#include <boost/simd/function/refine_rec.hpp>
#include <boost/simd/function/raw.hpp>

namespace boost { namespace simd { namespace ext
{
  namespace bd = boost::dispatch;
  namespace bs = boost::simd;

  BOOST_DISPATCH_OVERLOAD ( rec_
                          , (typename T)
                          , bs::sse_
                          , bs::raw_tag
                          , bd::scalar_<bd::single_<T>>
                          )
  {
    BOOST_FORCEINLINE T operator()(bs::raw_tag const&, T a0) const BOOST_NOEXCEPT
    {
      float inv;
      _mm_store_ss( &inv, _mm_rcp_ss( _mm_load_ss( &a0 ) ) );

      return inv;
    }
  };

  BOOST_DISPATCH_OVERLOAD ( rec_
                          , (typename T)
                          , bs::sse_
                          , bs::fast_tag
                          , bd::scalar_<bd::single_<T>>
                          )
  {
    BOOST_FORCEINLINE T operator()(bs::fast_tag const&, T a0) const BOOST_NOEXCEPT
    {
      return refine_rec(a0, raw_(rec)(a0));
    }
  };

  BOOST_DISPATCH_OVERLOAD ( rec_
                          , (typename T)
                          , bs::sse_
                          , bs::fast_tag
                          , bd::scalar_<bd::double_<T>>
                          )
  {
    BOOST_FORCEINLINE T operator()(bs::fast_tag const&, T a0) const BOOST_NOEXCEPT
    {
      float x  = a0;
      double e = static_cast<float>( raw_(rec)(x) );
             e = refine_rec(a0, e);

      return refine_rec(a0, e);
    }
  };
} } }

#endif

max_stars_repo_name: xmar/pythran

max_issues_repo_name: xmar/pythran

max_forks_repo_name: xmar/pythran