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

   Defines general objective functions for optimization.

   \author Markus Dreyer
 */

#ifndef SDL_OPTIMIZATION_OBJECTIVEFUNCTION_HPP
#define SDL_OPTIMIZATION_OBJECTIVEFUNCTION_HPP
#pragma once

#include <sdl/Hypergraph/Types.hpp>
#include <sdl/Optimization/IOriginalFeatureIds.hpp>
#include <sdl/Optimization/Types.hpp>
#include <sdl/Util/Delete.hpp>
#include <sdl/Util/Equal.hpp>
#include <sdl/Util/IsDebugBuild.hpp>
#include <sdl/Util/Sleep.hpp>
#include <sdl/Util/Unordered.hpp>
#include <sdl/Exception.hpp>
#include <sdl/SharedPtr.hpp>
#include <boost/bind.hpp>
#include <boost/lockfree/queue.hpp>
#include <boost/ptr_container/ptr_vector.hpp>
#include <graehl/shared/thread_group.hpp>
#include <algorithm>
#include <atomic>
#include <cassert>
#include <functional>
#include <functional>
#include <iomanip>
#include <iostream>
#include <list>
#include <mutex>
#include <thread>
#include <utility>
#include <vector>

namespace sdl {
namespace Optimization {

// fwd decl:
template <class FloatT>
class IObjectiveFunctionVisitor;

template <class X, class Y>
struct PodPair {
  X first;
  Y second;
};

template <class X, class Y>
PodPair<X, Y> makePodPair(X x, Y y) {
  PodPair<X, Y> p;
  p.first = x;
  p.second = y;
  return p;
}

/*
Adds regularization gradient to gradients and return delta for objective
 */
template <class FloatT>
struct IRegularizeFct {
  virtual FloatT operator()(FloatT const* params, FloatT* gradients, FeatureId numParams) const = 0;
  virtual ~IRegularizeFct(){};
};

/*
Adds L2 regularizer to gradients and function value.
 */
template <class FloatT>
class L2RegularizeFct : public IRegularizeFct<FloatT> {
 public:
  explicit L2RegularizeFct(FloatT v) : inverseVariance_(1 / (double)v) {}

  FloatT operator()(FloatT const* params, FloatT* gradients, FeatureId numParams) const override {
    FloatT norm(0.0);
    for (FeatureId i = 0; i < numParams; ++i) {
      FloatT const x = params[i];
      norm += x * x;
      gradients[i] += x * inverseVariance_;
    }
    norm /= 2;
    norm *= inverseVariance_;
    return norm;
  }

 private:
  FloatT const inverseVariance_;
};

/**
   API for an objective function, which can be optimized using
   L-BFGS, (stochastic) gradient descent or other methods. Objective
   functions have a function value and gradients (or alternatively,
   just updates resembling gradients).

   Examples for objective functions: A CRF objective function uses as
   (gradient) updates the difference A-B, where A=(feature
   expectations of the observed input-output pair) and B=(feature
   expectations of all possible outputs given the observed input). A
   perceptron is similar but B=(feature expectations of the current
   one-best output).

   Objective functions can also compute updates based on a loss
   function like 1-BLEU, mean squared error, etc.
 */
template <class FloatT>
class IObjectiveFunction {
 protected:
  shared_ptr<IRegularizeFct<FloatT>> regularize_;

 public:
  virtual void setRegularizeFct(IRegularizeFct<FloatT>* f) { regularize_.reset(f); }

  IRegularizeFct<FloatT>* getRegularizeFct() { return regularize_.get(); }

  /// \return part of objective fn due to params
  FloatT regularize(FloatT const* params, FloatT* gradients, FeatureId numParams) {
    return regularize_ ? (*regularize_)(params, gradients, numParams) : 0;
  }

  virtual ~IObjectiveFunction() {}

  /**
      Takes new parameters and updates the gradients and
      function value accordingly.
     *

      \param newParams The new parameters based on which the gradients
      and the function value are recomputed. (The type is FloatT*
      instead of std::vector<FloatT> because the L-BFGS uses FloatT*.)
     *

      \param resultingGradients Array must be of same size as the
      parameters and allocated outside.
   */
  virtual FloatT update(FloatT const* newParams, FloatT* resultingGradients, FeatureId numParams) = 0;

  /**
      Returns current function value.
   */
  virtual FloatT getFunctionValue() const = 0;

  /**
      accepts visitor. Good for printing current parameter
      values, etc.
   */
  virtual void accept(IObjectiveFunctionVisitor<FloatT>*) = 0;
};

/**
   visitor for IObjectiveFunction.
 */
template <class FloatT>
class IObjectiveFunctionVisitor {
 public:
  virtual ~IObjectiveFunctionVisitor() {}
  virtual void visit(IObjectiveFunction<FloatT>*) = 0;
};

template <class FloatT>
struct IUpdate {
  virtual ~IUpdate() {}
  virtual void update(FeatureId index, FloatT value) = 0;
};

/// Queue is typically boost::lockfree::queue<T>
template <class FloatT, class Queue>
struct GradientUpdate_Queue : public IUpdate<FloatT> {
  GradientUpdate_Queue(Queue& queue) : queue_(queue) {}

  void update(FeatureId index, FloatT value) override {
    while (!queue_.bounded_push(makePodPair(index, value)))
      ;
  }

  Queue& queue_;
};

template <class FloatT>
struct GradientUpdate : public IUpdate<FloatT> {
  GradientUpdate(FloatT* gradients) : gradients_(gradients) {}

  void update(FeatureId index, FloatT value) override { gradients_[index] += value; }

  FloatT* gradients_;
};

template <class FloatT>
struct ScaledGradientUpdate : public IUpdate<FloatT> {
  ScaledGradientUpdate(FloatT* gradients, FloatT scale = (FloatT)1.0)
      : gradients_(gradients), scaleTimes_(1 / scale) {}

  void update(FeatureId index, FloatT value) override { gradients_[index] += value * scaleTimes_; }

  FloatT* gradients_;
  FloatT scaleTimes_;
};

/**
   Consume updates of the form (index, gradient_delta) from the
   producer threads that compute feature expectations
   (gradients). Forward them to the IUpdate that adds them to the one
   gradient vector.
 */
template <class Queue, class FloatT>
struct ConsumeUpdates {

  ConsumeUpdates(IUpdate<FloatT>& updates, Queue& queue, std::atomic<bool>& areProducersDone)
      : updates_(updates), queue_(queue), areProducersDone_(areProducersDone) {}

  typedef PodPair<FeatureId, FloatT> Pair;

  void update(Pair p) { updates_.update(p.first, p.second); }

  enum { kSleepAfterFails = 1000 };  // avoid burning CPU when producers aren't keeping up
  enum { kSleepForMicroSeconds = 500 };
  void operator()() {
    unsigned fails = 0;
    Pair p;
    while (!areProducersDone_) {
      while (queue_.pop(p)) {
        update(p);
        fails = 0;
      }
      if (fails >= kSleepAfterFails)
        Util::usSleep(kSleepForMicroSeconds);
      else
        ++fails;
    }
    while (queue_.pop(p)) update(p);
  }

#if SDL_DEBUG
  std::size_t n_;
#endif
  IUpdate<FloatT>& updates_;
  Queue& queue_;
  std::atomic<bool>& areProducersDone_;
};

/**
   An objective function that's based on (training)
   data. Applies to most objective functions in NLP and machine
   learning.

   \tparam Updates The type for a list of updates to the parameters
   and/or gradients.
 */
template <class FloatT>
class DataObjectiveFunction : public IObjectiveFunction<FloatT> {

 public:
  DataObjectiveFunction() : numThreads_(1), doScale_(false) {}

  virtual void setNumThreads(std::size_t n) {
    SDL_INFO(Optimization, "Number of threads: " << n);
    numThreads_ = n;
  }

  virtual void doScale(bool b) {
    SDL_INFO(Optimization.DataObjectiveFunction, "Scale: " << (b ? "Y" : "N"));
    doScale_ = b;
  }

  virtual ~DataObjectiveFunction() {}

  virtual FloatT update(FloatT const* newParams, FloatT* resultingGradients, FeatureId numParams) {
    SDL_TRACE(Optimization.DataObjectiveFunction, "Updating " << numParams << " parameters on "
                                                              << getNumExamples() << " examples.");
    setFeatureWeights(newParams, numParams);
    zeroGradients(resultingGradients, numParams);
    initFunctionValue();

    // Add regularization terms to function value and gradients
    fctVal_ += this->regularize(newParams, resultingGradients, numParams);

    typedef IUpdate<FloatT> Update;
    unique_ptr<Update> update(
        doScale_ ? (Update*)new ScaledGradientUpdate<FloatT>(resultingGradients, (FloatT)getNumExamples())
                 : (Update*)new GradientUpdate<FloatT>(resultingGradients));

    // Get updates from all training examples:
    FloatT fctValUpdate = (FloatT)0.0;
    if (numThreads_ == 1)
      fctValUpdate = getUpdates(0, getNumExamples(), *update);
    else
      fctValUpdate = getUpdatesParallel(0, getNumExamples(), *update);

    if (doScale_) fctValUpdate /= getNumExamples();

    fctVal_ += fctValUpdate;

    if (Util::isDebugBuild()) {
      for (FeatureId i = 0; i < numParams; ++i)
        SDL_TRACE(Optimization.DataObjectiveFunction, "x[" << i << "] = " << std::setprecision(8)
                                                           << newParams[i]);
      for (FeatureId i = 0; i < numParams; ++i)
        SDL_TRACE(Optimization.DataObjectiveFunction, "g[" << i << "] = " << std::setprecision(8)
                                                           << resultingGradients[i]);
    }
    SDL_TRACE(Optimization.DataObjectiveFunction, "f = " << std::setprecision(8) << fctVal_);

    return fctVal_;
  }

  /**
      Computes the gradient updates for the specified training data range [begin, end)
   */
  virtual FloatT getUpdates(TrainingDataIndex begin, TrainingDataIndex end, IUpdate<FloatT>& updates) = 0;

  virtual FloatT getUpdate(TrainingDataIndex i, IUpdate<FloatT>& updates) const {
    SDL_THROW_LOG(Optimization, UnimplementedException, "unimplemented");
  }

  struct CallGetUpdates {
    CallGetUpdates(CallGetUpdates const&) = delete;
    CallGetUpdates(DataObjectiveFunction<FloatT>* obj, TrainingDataIndex begin, TrainingDataIndex end,
                   IUpdate<FloatT>& updates)
        : obj_(obj), begin_(begin), end_(end), updates_(updates) {}

    void operator()() {
      SDL_DEBUG(Optimization, "Computing updates " << begin_ << " to " << end_);
      result_ = obj_->getUpdates(begin_, end_, updates_);
      SDL_DEBUG(Optimization, "Computing updates " << begin_ << " to " << end_ << " result: " << result_);
    }

    DataObjectiveFunction<FloatT>* obj_;
    TrainingDataIndex begin_, end_;
    IUpdate<FloatT>& updates_;
    FloatT result_;
  };

  /**
      Multithreading implemented after:
      http://www.boost.org/doc/libs/1_55_0/doc/html/lockfree/examples.html
   */
  virtual FloatT getUpdatesParallel(TrainingDataIndex begin, TrainingDataIndex end, IUpdate<FloatT>& updates) {
    SDL_DEBUG(Optimization, "getUpdatesParallel from " << begin << " to " << end);
    assert(end > begin);

    typedef PodPair<FeatureId, FloatT> Pair;  // Windows compiler didn't like lockfree::queue<std::pair>
    typedef boost::lockfree::queue<Pair> Queue;
    assert(numThreads_ > 1);
    TrainingDataIndex numProducers = numThreads_ - 1;  // one of the threads is the consumer
    Queue queue(50 * numProducers);

    graehl::thread_group producerThreads, consumerThreads;

    TrainingDataIndex size = end - begin;
    TrainingDataIndex blockSize = size / numProducers;
    TrainingDataIndex rest = size % numProducers;

    typedef Util::AutoDeleteAll<CallGetUpdates> Producers;
    Producers producers;
    producers.reserve(numProducers);
    GradientUpdate_Queue<FloatT, Queue> updateQueue(queue);
    CallGetUpdates* update;
    TrainingDataIndex prevBlockEnd = begin;
    for (TrainingDataIndex i = 0;;) {
      TrainingDataIndex const blockEnd = prevBlockEnd + blockSize + (i < rest);
      // process one more in the first 'rest' threads so no training examples are left out
      producers.push_back(update = new CallGetUpdates(this, prevBlockEnd, blockEnd, updateQueue));
      prevBlockEnd = blockEnd;
      producerThreads.create_thread(std::ref(*update));
      if (++i >= numProducers) {
        assert(blockEnd == size);
        break;
      }
    }

    std::atomic<bool> areProducersDone(false);

    // just one consumer; consumes gradient updates from queue and
    // writes them into gradient array
    ConsumeUpdates<Queue, FloatT> consumer(updates, queue, areProducersDone);
    consumerThreads.create_thread(consumer);

    producerThreads.join_all();
    areProducersDone = true;
    consumerThreads.join_all();

    FloatT delta = 0.f;
    for (CallGetUpdates* producer : producers) delta += producer->result_;
    return delta;
  }

  virtual FloatT getFunctionValue() const { return fctVal_; }

  virtual void setFunctionValue(FloatT const& f) { fctVal_ = f; }

  virtual void initFunctionValue() { fctVal_ = (FloatT)0.0; }

  virtual void increaseFunctionValue(FloatT const& f) { fctVal_ += f; }

  void zeroGradients(FloatT* gradients, FeatureId size) { std::fill_n(gradients, size, (FloatT)0.0); }

  /**
      Returns the number of training examples.
   */
  virtual std::size_t getNumExamples() = 0;

  /**
      Inserts feature weights into all training examples
   */
  virtual void setFeatureWeights(FloatT const* params, FeatureId numParams) = 0;

  /**
      Inserts feature weights into training examples [begin,
      end).
   */
  virtual void setFeatureWeights(TrainingDataIndex begin, TrainingDataIndex end, FloatT const* params,
                                 FeatureId numParams)
      = 0;

  FloatT fctVal_;
  TrainingDataIndex numThreads_;
  bool doScale_;
};

}}

#endif


#include <boost/geometry/strategies/geographic/side_andoyer.hpp>


//#define BOOST_TEST_MODULE sample
//#define BOOST_TEST_DYN_LINK

#include <ql/quantlib.hpp>
#include <ql/time/timeunit.hpp>
#include <ql/time/frequency.hpp>
#include <test-suite/piecewiseyieldcurve.hpp>
#include <test-suite/utilities.hpp>
#include <ql/indexes/ibor/euribor.hpp>

//#include <boost/test/unit_test.hpp>
//#include <ql/time/date.hpp>
//#include <ql/time/calendar.hpp>
//#include <boost/move/detail/meta_utils.hpp>

// sample.cpp - Simple example of using AddIn.
#include <cmath>
#include "../xll/xll.h"
#include "../xll/shfb/entities.h"

#include <iostream>
#include <algorithm>
using namespace xll;
using namespace QuantLib;

AddIn xai_sample(
	Document(L"sample") // top level documentation
	.Documentation(LR"(
This object will generate a Sandcastle Helpfile Builder project file.
)"));

AddIn xal_sample_category(
	Document(L"Example")
	.Documentation(LR"(
This object will generate documentation for the Example category.
)")
);

// Information Excel needs to register add-in.
AddIn xai_function(
	// Function returning a pointer to an OPER with C++ name xll_function and Excel name XLL.FUNCTION.
	// Don't forget prepend a question mark to the C++ name.
	//                     |
	//                     v
	Function(XLL_LPOPER, L"?depositDataTest", L"XLL.depositDataTest")
	// First argument is a double called x with an argument description and default value of 2
	.Arg(XLL_LPOPER, L"depositData1", L"is the first double argument.", L"2")
    .Arg(XLL_LPOPER, L"fraData1", L"is the first double argument.", L"2")
    .Arg(XLL_LPOPER, L"immFutData1", L"is the first double argument.", L"2")
    .Arg(XLL_LPOPER, L"asxFutData1", L"is the first double argument.", L"2")
    .Arg(XLL_LPOPER, L"swapData1", L"is the first double argument.", L"2")
    .Arg(XLL_LPOPER, L"bondData1", L"is the first double argument.", L"2")
    .Arg(XLL_LPOPER, L"bmaData1", L"is the first double argument.", L"2")
    /*
    .Arg(XLL_DOUBLE, L"n", L"is the first n argument.", L"2")
    .Arg(XLL_LPOPER, L"units", L"is the second unit argument.", L"2")
    .Arg(XLL_DOUBLE, L"rate", L"is the third rate argument.", L"2")
    */
    /*
    .Arg(XLL_DOUBLE, L"x", L"is the first double argument.", L"2")
    */
    // Paste function category.
	.Category(L"Example")
	// Insert Function description.
	.FunctionHelp(L"Help on XLL.FUNCTION goes here.")
	// Create entry for this function in Sandcastle Help File Builder project file.
	.Alias(L"XLL.FUNCTION.ALIAS") // alternate name
	.Documentation(
		PARA_(
			L"Free-form documentation for " C_(L"XLL.FUNCTION") L" goes here."
		)
		PARA_(L"But you can include MAML directives.")
		PARA_(L"This is " B_(L"bold") " and so is " B_("this"))
		PARA_(L"Math: " MATH_(int_ SUB_(minus_ infin_) SUP_(infin_) L"e" SUP_(L"x" sup2_ L"/2") L" dx"))
	)
	.Remarks(
		L"This is a remark. "
		L"This is " B_(L"bold") L" and this is " I_(L"italic")
		PARA_(L"This is a paragraph.")
	)
	.Examples(LR"(
This is an example.
</para><para>
It has two paragraphs.
)")
);
// Calling convention *must* be WINAPI (aka __stdcall) for Excel.
/*
LPOPER WINAPI xll_function(double x)
{
	// Be sure to export your function.
#pragma XLLEXPORT
	static OPER result;

	try {
		ensure(x >= 0);
		result = sqrt(x); // OPER's act like Excel cells.
	}
	catch (const std::exception & ex) {
		XLL_ERROR(ex.what());

		result = OPER(xlerr::Num);
	}

	return &result;
}
*/

namespace piecewise_yield_curve_test {

    struct Datum {
        Integer n;
        TimeUnit units;
        Rate rate;
    };

    struct BondDatum {
        Integer n;
        TimeUnit units;
        Integer length;
        Frequency frequency;
        Rate coupon;
        Real price;
    };
    struct CommonVars {
        // global variables
        Calendar calendar;
        Natural settlementDays;
        Date today, settlement;
        BusinessDayConvention fixedLegConvention;
        Frequency fixedLegFrequency;
        DayCounter fixedLegDayCounter;
        Natural bondSettlementDays;
        DayCounter bondDayCounter;
        BusinessDayConvention bondConvention;
        Real bondRedemption;
        Frequency bmaFrequency;
        BusinessDayConvention bmaConvention;
        DayCounter bmaDayCounter;

        Size deposits, fras, immFuts, asxFuts, swaps, bonds, bmas;
        std::vector<ext::shared_ptr<SimpleQuote> > rates, fraRates,
            immFutPrices, asxFutPrices,
            prices, fractions;
        std::vector<ext::shared_ptr<RateHelper> > instruments, fraHelpers,
            immFutHelpers, asxFutHelpers,
            bondHelpers, bmaHelpers;
        std::vector<Schedule> schedules;
        ext::shared_ptr<YieldTermStructure> termStructure;

        // cleanup
        SavedSettings backup;
        //QuantLib::IndexHistoryCleaner cleaner;

        // setup
        CommonVars(std::vector<Datum>& depositData, std::vector<Datum>& fraData, std::vector<Datum>& immFutData,
            std::vector<Datum>& asxFutData, std::vector<Datum>& swapData, std::vector<BondDatum>& bondData,
            std::vector<Datum>& bmaData) {
            // data
            calendar = TARGET();
            settlementDays = 2;
            today = calendar.adjust(Date::todaysDate());
            Settings::instance().evaluationDate() = today;
            settlement = calendar.advance(today, settlementDays, Days);
            fixedLegConvention = Unadjusted;
            fixedLegFrequency = Annual;
            fixedLegDayCounter = Thirty360();
            bondSettlementDays = 3;
            bondDayCounter = ActualActual();
            bondConvention = Following;
            bondRedemption = 100.0;
            bmaFrequency = Quarterly;
            bmaConvention = Following;
            bmaDayCounter = ActualActual();

            deposits = (int)depositData.size();
            fras = (int)fraData.size();
            immFuts = (int)immFutData.size();
            asxFuts = (int)asxFutData.size();
            swaps = (int)swapData.size();
            bonds = (int)bondData.size();
            bmas = (int)bmaData.size();

            // market elements
            rates =
                std::vector<ext::shared_ptr<SimpleQuote> >(deposits + swaps);
            fraRates = std::vector<ext::shared_ptr<SimpleQuote> >(fras);
            immFutPrices = std::vector<ext::shared_ptr<SimpleQuote> >(immFuts);
            asxFutPrices = std::vector<ext::shared_ptr<SimpleQuote> >(asxFuts);
            prices = std::vector<ext::shared_ptr<SimpleQuote> >(bonds);
            fractions = std::vector<ext::shared_ptr<SimpleQuote> >(bmas);
            for (Size i = 0; i < deposits; i++) {
                rates[i] = ext::make_shared<SimpleQuote>(
                    depositData[i].rate / 100);
            }
            for (Size i = 0; i < swaps; i++) {
                rates[i + deposits] = ext::make_shared<SimpleQuote>(
                    swapData[i].rate / 100);
            }
            for (Size i = 0; i < fras; i++) {
                fraRates[i] = ext::make_shared<SimpleQuote>(
                    fraData[i].rate / 100);
            }
            for (Size i = 0; i < bonds; i++) {
                prices[i] = ext::make_shared<SimpleQuote>(
                    bondData[i].price);
            }
            for (Size i = 0; i < immFuts; i++) {
                immFutPrices[i] = ext::make_shared<SimpleQuote>(
                    100.0 - immFutData[i].rate);
            }
            for (Size i = 0; i < asxFuts; i++) {
                asxFutPrices[i] = ext::make_shared<SimpleQuote>(
                    100.0 - asxFutData[i].rate);
            }
            for (Size i = 0; i < bmas; i++) {
                fractions[i] = ext::make_shared<SimpleQuote>(
                    bmaData[i].rate / 100);
            }

            // rate helpers
            instruments =
                std::vector<ext::shared_ptr<RateHelper> >(deposits + swaps);
            fraHelpers = std::vector<ext::shared_ptr<RateHelper> >(fras);
            immFutHelpers = std::vector<ext::shared_ptr<RateHelper> >(immFuts);
            asxFutHelpers = std::vector<ext::shared_ptr<RateHelper> >();
            bondHelpers = std::vector<ext::shared_ptr<RateHelper> >(bonds);
            schedules = std::vector<Schedule>(bonds);
            bmaHelpers = std::vector<ext::shared_ptr<RateHelper> >(bmas);

            ext::shared_ptr<IborIndex> euribor6m(new Euribor6M);
            for (Size i = 0; i < deposits; i++) {
                Handle<Quote> r(rates[i]);
                instruments[i] = ext::shared_ptr<RateHelper>(new
                    DepositRateHelper(r,
                        ext::make_shared<Euribor>(
                            depositData[i].n * depositData[i].units)));
            }
            for (Size i = 0; i < swaps; i++) {
                Handle<Quote> r(rates[i + deposits]);
                instruments[i + deposits] = ext::shared_ptr<RateHelper>(new
                    SwapRateHelper(r, swapData[i].n * swapData[i].units,
                        calendar,
                        fixedLegFrequency, fixedLegConvention,
                        fixedLegDayCounter, euribor6m));
            }

#ifdef QL_USE_INDEXED_COUPON
            bool useIndexedFra = false;
#else
            bool useIndexedFra = true;
#endif

            ext::shared_ptr<IborIndex> euribor3m(new Euribor3M());
            for (Size i = 0; i < fras; i++) {
                Handle<Quote> r(fraRates[i]);
                fraHelpers[i] = ext::shared_ptr<RateHelper>(new
                    FraRateHelper(r, fraData[i].n, fraData[i].n + 3,
                        euribor3m->fixingDays(),
                        euribor3m->fixingCalendar(),
                        euribor3m->businessDayConvention(),
                        euribor3m->endOfMonth(),
                        euribor3m->dayCounter(),
                        Pillar::LastRelevantDate,
                        Date(),
                        useIndexedFra));
            }
            Date immDate = Date();
            for (Size i = 0; i < immFuts; i++) {
                Handle<Quote> r(immFutPrices[i]);
                immDate = IMM::nextDate(immDate, false);
                // if the fixing is before the evaluation date, we
                // just jump forward by one future maturity
                if (euribor3m->fixingDate(immDate) <
                    Settings::instance().evaluationDate())
                    immDate = IMM::nextDate(immDate, false);
                immFutHelpers[i] = ext::shared_ptr<RateHelper>(new
                    FuturesRateHelper(r, immDate, euribor3m, Handle<Quote>(),
                        Futures::IMM));
            }
            Date asxDate = Date();
            for (Size i = 0; i < asxFuts; i++) {
                Handle<Quote> r(asxFutPrices[i]);
                asxDate = ASX::nextDate(asxDate, false);
                // if the fixing is before the evaluation date, we
                // just jump forward by one future maturity
                if (euribor3m->fixingDate(asxDate) <
                    Settings::instance().evaluationDate())
                    asxDate = ASX::nextDate(asxDate, false);
                if (euribor3m->fixingCalendar().isBusinessDay(asxDate))
                    asxFutHelpers.push_back(ext::shared_ptr<RateHelper>(new
                        FuturesRateHelper(r, asxDate, euribor3m,
                            Handle<Quote>(), Futures::ASX)));
            }

            for (Size i = 0; i < bonds; i++) {
                Handle<Quote> p(prices[i]);
                Date maturity =
                    calendar.advance(today, bondData[i].n, bondData[i].units);
                Date issue =
                    calendar.advance(maturity, -bondData[i].length, Years);
                std::vector<Rate> coupons(1, bondData[i].coupon / 100.0);
                schedules[i] = Schedule(issue, maturity,
                    Period(bondData[i].frequency),
                    calendar,
                    bondConvention, bondConvention,
                    DateGeneration::Backward, false);
                bondHelpers[i] = ext::shared_ptr<RateHelper>(new
                    FixedRateBondHelper(p,
                        bondSettlementDays,
                        bondRedemption, schedules[i],
                        coupons, bondDayCounter,
                        bondConvention,
                        bondRedemption, issue));
            }
        }
    };
}

std::string wtoa(const std::wstring& Text) {

    std::string s(WideCharToMultiByte(CP_UTF8, 0, Text.c_str(), Text.size(), NULL, NULL, NULL, NULL), '\0');
    s.resize(WideCharToMultiByte(CP_UTF8, 0, Text.c_str(), Text.size(), &s[0], s.size(), NULL, NULL));
    return s;
};

TimeUnit convertTime(std::string x) {
    int xsize = x.length();
    if (x.find("Months")<xsize) {
        return Months;
    }
    else if (x.find("Years") < xsize) {
        return Years;
    }
    else if (x.find("Days") < xsize) {
        return Days;
    }
    else if (x.find("Weeks") < xsize) {
        return Weeks;
    }
    else if (x.find("Hours") < xsize) {
        return Hours;
    }
    else if (x.find("Minutes") < xsize) {
        return Minutes;
    }
    else if (x.find("Seconds") < xsize) {
        return Seconds;
    }
    else if (x.find("Milliseconds") < xsize) {
        return Milliseconds;
    }
    else if (x.find("Microseconds") < xsize) {
        return Microseconds;
    }
    else {
        std::cout << "error with TimeUnit input" << std::endl;
        return Microseconds;
    }

};
Frequency convertFreq(std::string x) {
    int xsize = x.length();
    if (x.find("NoFrequency") < xsize) {
        return NoFrequency;
    }
    else if (x.find("Once") < xsize) {
        return Once;
    }
    else if (x.find("Annual") < xsize) {
        return Annual;
    }
    else if (x.find("Semiannual") < xsize) {
        return Semiannual;
    }
    else if (x.find("EveryFourthMonth") < xsize) {
        return EveryFourthMonth;
    }
    else if (x.find("Quarterly") < xsize) {
        return Quarterly;
    }
    else if (x.find("Bimonthly") < xsize) {
        return Bimonthly;
    }
    else if (x.find("Monthly") < xsize) {
        return Monthly;
    }
    else if (x.find("EveryFourthWeek") < xsize) {
        return EveryFourthWeek;
    }
    else if (x.find("Biweekly") < xsize) {
        return Biweekly;
    }
    else if (x.find("Weekly") < xsize) {
        return Weekly;
    }
    else if (x.find("Daily") < xsize) {
        return Daily;
    }
    else {
        return OtherFrequency;
    }

};
LPOPER WINAPI depositDataTest(XLOPER12* depositData1,
    XLOPER12* fraData1,
    XLOPER12* immFutData1,
    XLOPER12* asxFutData1,
    XLOPER12* swapData1,
    XLOPER12* bondData1,
    XLOPER12* bmaData1) {
#pragma XLLEXPORT
    static OPER result;

    using namespace piecewise_yield_curve_test;

    Real tolerance = 1.0e-9;
    int sizeDepositData = (int)depositData1->val.array.rows;
    int count = 0;
    std::vector<Datum> depositData;
    for (int i = 0; i < sizeDepositData; i++) {
        Integer a = (int)depositData1->val.array.lparray[count].val.num;
        count++;
        std::string bb = wtoa(depositData1->val.array.lparray[count].val.str);
        TimeUnit b = convertTime(bb);
        count++;
        Rate c = depositData1->val.array.lparray[count].val.num;
        count++;
        Datum sub = { a, b, c };
        depositData.push_back(sub);
    }
    count = 0;
    int sizefraData = (int)fraData1->val.array.rows;
    std::vector<Datum> fraData;
    for (int i = 0; i < sizefraData; i++) {
        Integer a = (int)fraData1->val.array.lparray[count].val.num;
        count++;
        std::string bb = wtoa(fraData1->val.array.lparray[count].val.str);
        TimeUnit b = convertTime(bb);
        count++;
        Rate c = fraData1->val.array.lparray[count].val.num;
        count++;
        Datum sub = { a, b, c };
        fraData.push_back(sub);
    }
    count = 0;
    int sizeimmFutData = (int)immFutData1->val.array.rows;
    std::vector<Datum> immFutData;
    for (int i = 0; i < sizeimmFutData; i++) {
        Integer a = (int)immFutData1->val.array.lparray[count].val.num;
        count++;
        std::string bb = wtoa(immFutData1->val.array.lparray[count].val.str);
        TimeUnit b = convertTime(bb);
        count++;
        Rate c = immFutData1->val.array.lparray[count].val.num;
        count++;
        Datum sub = { a, b, c };
        immFutData.push_back(sub);
    }
    count = 0;
    int sizeasxFutData = (int)asxFutData1->val.array.rows;
    std::vector<Datum> asxFutData;
    for (int i = 0; i < sizeasxFutData; i++) {
        Integer a = (int)asxFutData1->val.array.lparray[count].val.num;
        count++;
        std::string bb = wtoa(asxFutData1->val.array.lparray[count].val.str);
        TimeUnit b = convertTime(bb);
        count++;
        Rate c = asxFutData1->val.array.lparray[count].val.num;
        count++;
        Datum sub = { a, b, c };
        asxFutData.push_back(sub);
    }
    count = 0;
    int sizeswapData = (int)swapData1->val.array.rows;
    std::vector<Datum> swapData;
    for (int i = 0; i < sizeswapData; i++) {
        Integer a = (int)swapData1->val.array.lparray[count].val.num;
        count++;
        std::string bb = wtoa(swapData1->val.array.lparray[count].val.str);
        TimeUnit b = convertTime(bb);
        count++;
        Rate c = swapData1->val.array.lparray[count].val.num;
        count++;
        Datum sub = { a, b, c };
        swapData.push_back(sub);
    }
    count = 0;
    int sizebondData = (int)bondData1->val.array.rows;
    std::vector<BondDatum> bondData;
    for (int i = 0; i < sizebondData; i++) {
        Integer a = (int)bondData1->val.array.lparray[count].val.num;
        count++;
        std::string bb = wtoa(bondData1->val.array.lparray[count].val.str);
        TimeUnit b = convertTime(bb);
        count++;
        Integer c = (int)bondData1->val.array.lparray[count].val.num;
        count++;
        std::string dd = wtoa(bondData1->val.array.lparray[count].val.str);
        Frequency d = convertFreq(dd);
        count++;
        Rate e = bondData1->val.array.lparray[count].val.num;
        count++;
        Real f = bondData1->val.array.lparray[count].val.num;
        count++;
        BondDatum sub = { a, b, c, d, e, f };
        bondData.push_back(sub);
    }

    count = 0;
    int sizebmaData = (int)bmaData1->val.array.rows;
    std::vector<Datum> bmaData(sizebmaData);
    for (int i = 0; i < sizebmaData; i++) {
        Integer a = (int)bmaData1->val.array.lparray[count].val.num;
        count++;
        std::string bb = wtoa(bmaData1->val.array.lparray[count].val.str);
        TimeUnit b = convertTime(bb);
        count++;
        Rate c = bmaData1->val.array.lparray[count].val.num;
        count++;
        Datum sub = { a, b, c };
        bmaData.push_back(sub);
    }
    CommonVars vars(depositData, fraData, immFutData, asxFutData, swapData, bondData, bmaData);

    QuantLib::Linear interpolator = Linear();
    RelinkableHandle<YieldTermStructure> curveHandle;

    curveHandle.linkTo(ext::shared_ptr<YieldTermStructure>(new
        PiecewiseYieldCurve<ZeroYield, Linear, IterativeBootstrap>(vars.settlement, vars.instruments,
            Actual360(),
            interpolator)));

    sizeDepositData = (int)depositData.size();
 //   std::vector<Rate> expectedRate(sizeDepositData);
    std::vector<Rate> estimatedRate(sizeDepositData);
    for (Size i = 0; i < sizeDepositData; i++) {
        Euribor index(depositData[i].n * depositData[i].units, curveHandle);
 //       expectedRate[i] = depositData[i].rate / 100;
            estimatedRate[i] = index.fixing(vars.today);
 /*       if (std::fabs(expectedRate[i] - estimatedRate[i]) > tolerance) {
            BOOST_ERROR(
                depositData[i].n << " "
                << (depositData[i].units == Weeks ? "week(s)" : "month(s)")
                << " deposit:"
                //<< std::setprecision(8)
                << "\n    estimated rate: " << io::rate(estimatedRate[i])
                << "\n    expected rate:  " << io::rate(expectedRate[i]));
        }
*/
    }
    //set up in comments can return the expected rate, estimated rate and whether exceed tolerance
    // changed sub[j] = estimatedRate... to sub[count] = estimated Rate
    //count = 0;
    OPER sub(sizeDepositData,1);
    for (int j = 0; j < sizeDepositData; j++) {
        //sub[count] = expectedRate[j];
        //count++;
        sub[j] = estimatedRate[j];
        //count++;
        //sub[count] = std::fabs(expectedRate[j] - estimatedRate[j]) < tolerance ? true : false;
        //count++;
    }

    result = sub;
    return &result;
}

AddIn xai_function1(
    // Function returning a pointer to an OPER with C++ name xll_function and Excel name XLL.FUNCTION.
    // Don't forget prepend a question mark to the C++ name.
    Function(XLL_LPOPER, L"?swapDataTest", L"XLL.swapDataTest")
    // First argument is a double called x with an argument description and default value of 2
    .Arg(XLL_LPOPER, L"depositData1", L"is the first double argument.", L"2")
    .Arg(XLL_LPOPER, L"fraData1", L"is the first double argument.", L"2")
    .Arg(XLL_LPOPER, L"immFutData1", L"is the first double argument.", L"2")
    .Arg(XLL_LPOPER, L"asxFutData1", L"is the first double argument.", L"2")
    .Arg(XLL_LPOPER, L"swapData1", L"is the first double argument.", L"2")
    .Arg(XLL_LPOPER, L"bondData1", L"is the first double argument.", L"2")
    .Arg(XLL_LPOPER, L"bmaData1", L"is the first double argument.", L"2")
    // Paste function category.
    .Category(L"Example")
    // Insert Function description.
    .FunctionHelp(L"Help on XLL.FUNCTION goes here.")
    // Create entry for this function in Sandcastle Help File Builder project file.
    .Alias(L"XLL.FUNCTION.ALIAS") // alternate name
    .Documentation(
        PARA_(
            L"Free-form documentation for " C_(L"XLL.FUNCTION") L" goes here."
        )
        PARA_(L"But you can include MAML directives.")
        PARA_(L"This is " B_(L"bold") " and so is " B_("this"))
        PARA_(L"Math: " MATH_(int_ SUB_(minus_ infin_) SUP_(infin_) L"e" SUP_(L"x" sup2_ L"/2") L" dx"))
    )
);
LPOPER WINAPI swapDataTest(XLOPER12* depositData1,
    XLOPER12* fraData1,
    XLOPER12* immFutData1,
    XLOPER12* asxFutData1,
    XLOPER12* swapData1,
    XLOPER12* bondData1,
    XLOPER12* bmaData1) {
#pragma XLLEXPORT
    static OPER result;

    using namespace piecewise_yield_curve_test;
    Real tolerance = 1.0e-9;
    int sizeDepositData = (int)depositData1->val.array.rows;
    int count = 0;
    std::vector<Datum> depositData;
    for (int i = 0; i < sizeDepositData; i++) {
        Integer a = (int)depositData1->val.array.lparray[count].val.num;
        count++;
        std::string bb = wtoa(depositData1->val.array.lparray[count].val.str);
        TimeUnit b = convertTime(bb);
        count++;
        Rate c = depositData1->val.array.lparray[count].val.num;
        count++;
        Datum sub = { a, b, c };
        depositData.push_back(sub);
    }
    count = 0;
    int sizefraData = (int)fraData1->val.array.rows;
    std::vector<Datum> fraData;
    for (int i = 0; i < sizefraData; i++) {
        Integer a = (int)fraData1->val.array.lparray[count].val.num;
        count++;
        std::string bb = wtoa(fraData1->val.array.lparray[count].val.str);
        TimeUnit b = convertTime(bb);
        count++;
        Rate c = fraData1->val.array.lparray[count].val.num;
        count++;
        Datum sub = { a, b, c };
        fraData.push_back(sub);
    }
    count = 0;
    int sizeimmFutData = (int)immFutData1->val.array.rows;
    std::vector<Datum> immFutData;
    for (int i = 0; i < sizeimmFutData; i++) {
        Integer a = (int)immFutData1->val.array.lparray[count].val.num;
        count++;
        std::string bb = wtoa(immFutData1->val.array.lparray[count].val.str);
        TimeUnit b = convertTime(bb);
        count++;
        Rate c = immFutData1->val.array.lparray[count].val.num;
        count++;
        Datum sub = { a, b, c };
        immFutData.push_back(sub);
    }
    count = 0;
    int sizeasxFutData = (int)asxFutData1->val.array.rows;
    std::vector<Datum> asxFutData;
    for (int i = 0; i < sizeasxFutData; i++) {
        Integer a = (int)asxFutData1->val.array.lparray[count].val.num;
        count++;
        std::string bb = wtoa(asxFutData1->val.array.lparray[count].val.str);
        TimeUnit b = convertTime(bb);
        count++;
        Rate c = asxFutData1->val.array.lparray[count].val.num;
        count++;
        Datum sub = { a, b, c };
        asxFutData.push_back(sub);
    }
    count = 0;
    int sizeswapData = (int)swapData1->val.array.rows;
    std::vector<Datum> swapData;
    for (int i = 0; i < sizeswapData; i++) {
        Integer a = (int)swapData1->val.array.lparray[count].val.num;
        count++;
        std::string bb = wtoa(swapData1->val.array.lparray[count].val.str);
        TimeUnit b = convertTime(bb);
        count++;
        Rate c = swapData1->val.array.lparray[count].val.num;
        count++;
        Datum sub = { a, b, c };
        swapData.push_back(sub);
    }
    count = 0;
    int sizebondData = (int)bondData1->val.array.rows;
    std::vector<BondDatum> bondData;
    for (int i = 0; i < sizebondData; i++) {
        Integer a = (int)bondData1->val.array.lparray[count].val.num;
        count++;
        std::string bb = wtoa(bondData1->val.array.lparray[count].val.str);
        TimeUnit b = convertTime(bb);
        count++;
        Integer c = (int)bondData1->val.array.lparray[count].val.num;
        count++;
        std::string dd = wtoa(bondData1->val.array.lparray[count].val.str);
        Frequency d = convertFreq(dd);
        count++;
        Rate e = bondData1->val.array.lparray[count].val.num;
        count++;
        Real f = bondData1->val.array.lparray[count].val.num;
        count++;
        BondDatum sub = { a, b, c, d, e, f };
        bondData.push_back(sub);
    }

    count = 0;
    int sizebmaData = (int)bmaData1->val.array.rows;
    std::vector<Datum> bmaData(sizebmaData);
    for (int i = 0; i < sizebmaData; i++) {
        Integer a = (int)bmaData1->val.array.lparray[count].val.num;
        count++;
        std::string bb = wtoa(bmaData1->val.array.lparray[count].val.str);
        TimeUnit b = convertTime(bb);
        count++;
        Rate c = bmaData1->val.array.lparray[count].val.num;
        count++;
        Datum sub = { a, b, c };
        bmaData.push_back(sub);
    }
    CommonVars vars(depositData, fraData, immFutData, asxFutData, swapData, bondData, bmaData);

    QuantLib::Linear interpolator = Linear();
    RelinkableHandle<YieldTermStructure> curveHandle;

    curveHandle.linkTo(ext::shared_ptr<YieldTermStructure>(new
        PiecewiseYieldCurve<ZeroYield, Linear, IterativeBootstrap>(vars.settlement, vars.instruments,
            Actual360(),
            interpolator)));

    std::vector<Rate> expectedRate(vars.swaps);
    std::vector<Rate> estimatedRate(vars.swaps);

    ext::shared_ptr<IborIndex> euribor6m(new Euribor6M(curveHandle));
    for (Size i = 0; i < vars.swaps; i++) {
        Period tenor = swapData[i].n * swapData[i].units;

        VanillaSwap swap = MakeVanillaSwap(tenor, euribor6m, 0.0)
            .withEffectiveDate(vars.settlement)
            .withFixedLegDayCount(vars.fixedLegDayCounter)
            .withFixedLegTenor(Period(vars.fixedLegFrequency))
            .withFixedLegConvention(vars.fixedLegConvention)
            .withFixedLegTerminationDateConvention(vars.fixedLegConvention);

//        expectedRate[i] = swapData[i].rate / 100;
            estimatedRate[i] = swap.fairRate();
/*        Spread error = std::fabs(expectedRate[i] - estimatedRate[i]);
        if (error > tolerance) {
            BOOST_ERROR(
                swapData[i].n << " year(s) swap:\n"
                << std::setprecision(8)
                << "\n estimated rate: " << io::rate(estimatedRate[i])
                << "\n expected rate:  " << io::rate(expectedRate[i])
                << "\n error:          " << io::rate(error)
                << "\n tolerance:      " << io::rate(tolerance));
        }
*/
    }

//    count = 0;
    OPER sub(vars.swaps, 1);
    for (int j = 0; j < vars.swaps; j++) {
 //       sub[count] = expectedRate[j];
 //       count++;
        sub[j] = estimatedRate[j];
 //       count++;
 //       sub[count] = std::fabs(expectedRate[j] - estimatedRate[j]) < tolerance ? true : false;
 //       count++;
    }

    result = sub;
    return &result;
};

AddIn xai_function2(
    // Function returning a pointer to an OPER with C++ name xll_function and Excel name XLL.FUNCTION.
    // Don't forget prepend a question mark to the C++ name.
    Function(XLL_LPOPER, L"?bondDataTest", L"XLL.bondDataTest")
    // First argument is a double called x with an argument description and default value of 2
    .Arg(XLL_LPOPER, L"depositData1", L"is the first double argument.", L"2")
    .Arg(XLL_LPOPER, L"fraData1", L"is the first double argument.", L"2")
    .Arg(XLL_LPOPER, L"immFutData1", L"is the first double argument.", L"2")
    .Arg(XLL_LPOPER, L"asxFutData1", L"is the first double argument.", L"2")
    .Arg(XLL_LPOPER, L"swapData1", L"is the first double argument.", L"2")
    .Arg(XLL_LPOPER, L"bondData1", L"is the first double argument.", L"2")
    .Arg(XLL_LPOPER, L"bmaData1", L"is the first double argument.", L"2")
    // Paste function category.
    .Category(L"Example")
    // Insert Function description.
    .FunctionHelp(L"Help on XLL.FUNCTION goes here.")
    // Create entry for this function in Sandcastle Help File Builder project file.
    .Alias(L"XLL.FUNCTION.ALIAS") // alternate name
    .Documentation(
        PARA_(
            L"Free-form documentation for " C_(L"XLL.FUNCTION") L" goes here."
        )
        PARA_(L"But you can include MAML directives.")
        PARA_(L"This is " B_(L"bold") " and so is " B_("this"))
        PARA_(L"Math: " MATH_(int_ SUB_(minus_ infin_) SUP_(infin_) L"e" SUP_(L"x" sup2_ L"/2") L" dx"))
    )
);

LPOPER WINAPI bondDataTest(XLOPER12* depositData1,
    XLOPER12* fraData1,
    XLOPER12* immFutData1,
    XLOPER12* asxFutData1,
    XLOPER12* swapData1,
    XLOPER12* bondData1,
    XLOPER12* bmaData1) {
#pragma XLLEXPORT
    static OPER result;

    using namespace piecewise_yield_curve_test;
    Real tolerance = 1.0e-9;
    int sizeDepositData = (int)depositData1->val.array.rows;
    int count = 0;
    std::vector<Datum> depositData;
    for (int i = 0; i < sizeDepositData; i++) {
        Integer a = (int)depositData1->val.array.lparray[count].val.num;
        count++;
        std::string bb = wtoa(depositData1->val.array.lparray[count].val.str);
        TimeUnit b = convertTime(bb);
        count++;
        Rate c = depositData1->val.array.lparray[count].val.num;
        count++;
        Datum sub = { a, b, c };
        depositData.push_back(sub);
    }
    count = 0;
    int sizefraData = (int)fraData1->val.array.rows;
    std::vector<Datum> fraData;
    for (int i = 0; i < sizefraData; i++) {
        Integer a = (int)fraData1->val.array.lparray[count].val.num;
        count++;
        std::string bb = wtoa(fraData1->val.array.lparray[count].val.str);
        TimeUnit b = convertTime(bb);
        count++;
        Rate c = fraData1->val.array.lparray[count].val.num;
        count++;
        Datum sub = { a, b, c };
        fraData.push_back(sub);
    }
    count = 0;
    int sizeimmFutData = (int)immFutData1->val.array.rows;
    std::vector<Datum> immFutData;
    for (int i = 0; i < sizeimmFutData; i++) {
        Integer a = (int)immFutData1->val.array.lparray[count].val.num;
        count++;
        std::string bb = wtoa(immFutData1->val.array.lparray[count].val.str);
        TimeUnit b = convertTime(bb);
        count++;
        Rate c = immFutData1->val.array.lparray[count].val.num;
        count++;
        Datum sub = { a, b, c };
        immFutData.push_back(sub);
    }
    count = 0;
    int sizeasxFutData = (int)asxFutData1->val.array.rows;
    std::vector<Datum> asxFutData;
    for (int i = 0; i < sizeasxFutData; i++) {
        Integer a = (int)asxFutData1->val.array.lparray[count].val.num;
        count++;
        std::string bb = wtoa(asxFutData1->val.array.lparray[count].val.str);
        TimeUnit b = convertTime(bb);
        count++;
        Rate c = asxFutData1->val.array.lparray[count].val.num;
        count++;
        Datum sub = { a, b, c };
        asxFutData.push_back(sub);
    }
    count = 0;
    int sizeswapData = (int)swapData1->val.array.rows;
    std::vector<Datum> swapData;
    for (int i = 0; i < sizeswapData; i++) {
        Integer a = (int)swapData1->val.array.lparray[count].val.num;
        count++;
        std::string bb = wtoa(swapData1->val.array.lparray[count].val.str);
        TimeUnit b = convertTime(bb);
        count++;
        Rate c = swapData1->val.array.lparray[count].val.num;
        count++;
        Datum sub = { a, b, c };
        swapData.push_back(sub);
    }
    count = 0;
    int sizebondData = (int)bondData1->val.array.rows;
    std::vector<BondDatum> bondData;
    for (int i = 0; i < sizebondData; i++) {
        Integer a = (int)bondData1->val.array.lparray[count].val.num;
        count++;
        std::string bb = wtoa(bondData1->val.array.lparray[count].val.str);
        TimeUnit b = convertTime(bb);
        count++;
        Integer c = (int)bondData1->val.array.lparray[count].val.num;
        count++;
        std::string dd = wtoa(bondData1->val.array.lparray[count].val.str);
        Frequency d = convertFreq(dd);
        count++;
        Rate e = bondData1->val.array.lparray[count].val.num;
        count++;
        Real f = bondData1->val.array.lparray[count].val.num;
        count++;
        BondDatum sub = { a, b, c, d, e, f };
        bondData.push_back(sub);
    }

    count = 0;
    int sizebmaData = (int)bmaData1->val.array.rows;
    std::vector<Datum> bmaData(sizebmaData);
    for (int i = 0; i < sizebmaData; i++) {
        Integer a = (int)bmaData1->val.array.lparray[count].val.num;
        count++;
        std::string bb = wtoa(bmaData1->val.array.lparray[count].val.str);
        TimeUnit b = convertTime(bb);
        count++;
        Rate c = bmaData1->val.array.lparray[count].val.num;
        count++;
        Datum sub = { a, b, c };
        bmaData.push_back(sub);
    }
    CommonVars vars(depositData, fraData, immFutData, asxFutData, swapData, bondData, bmaData);
    QuantLib::Linear interpolator = Linear();
    RelinkableHandle<YieldTermStructure> curveHandle;

    // check bonds
    vars.termStructure = ext::shared_ptr<YieldTermStructure>(new
        PiecewiseYieldCurve<ZeroYield, Linear, IterativeBootstrap>(vars.settlement, vars.bondHelpers,
            Actual360(),
            interpolator));
    curveHandle.linkTo(vars.termStructure);

  //  std::vector<Real> expectedPrice(vars.bonds);
    std::vector<Real> estimatedPrice(vars.bonds);

    for (Size i = 0; i < vars.bonds; i++) {
        Date maturity = vars.calendar.advance(vars.today,
            bondData[i].n,
            bondData[i].units);
        Date issue = vars.calendar.advance(maturity,
            -bondData[i].length,
            Years);
        std::vector<Rate> coupons(1, bondData[i].coupon / 100.0);

        FixedRateBond bond(vars.bondSettlementDays, 100.0,
            vars.schedules[i], coupons,
            vars.bondDayCounter, vars.bondConvention,
            vars.bondRedemption, issue);

        ext::shared_ptr<PricingEngine> bondEngine(
            new DiscountingBondEngine(curveHandle));
        bond.setPricingEngine(bondEngine);

 //       expectedPrice[i] = bondData[i].price;
            estimatedPrice[i] = bond.cleanPrice();
/*        Real error = std::fabs(expectedPrice[i] - estimatedPrice[i]);
        if (error > tolerance) {
            BOOST_ERROR(io::ordinal(i + 1) << " bond failure:" <<
                std::setprecision(8) <<
                "\n  estimated price: " << estimatedPrice[i] <<
                "\n  expected price:  " << expectedPrice[i] <<
                "\n  error:           " << error);
        }
*/
    }

//    count = 0;
    OPER sub(vars.bonds, 1);
    for (int j = 0; j < vars.bonds; j++) {
 //       sub[count] = expectedPrice[j];
 //       count++;
        sub[j] = estimatedPrice[j];
 //       count++;
 //       sub[count] = std::fabs(expectedPrice[j] - estimatedPrice[j]) < tolerance ? true : false;
 //       count++;
    }

    result = sub;
    return &result;
};

AddIn xai_function3(
    // Function returning a pointer to an OPER with C++ name xll_function and Excel name XLL.FUNCTION.
    // Don't forget prepend a question mark to the C++ name.
    Function(XLL_LPOPER, L"?fraDataTest", L"XLL.fraDataTest")
    // First argument is a double called x with an argument description and default value of 2
    .Arg(XLL_LPOPER, L"depositData1", L"is the first double argument.", L"2")
    .Arg(XLL_LPOPER, L"fraData1", L"is the first double argument.", L"2")
    .Arg(XLL_LPOPER, L"immFutData1", L"is the first double argument.", L"2")
    .Arg(XLL_LPOPER, L"asxFutData1", L"is the first double argument.", L"2")
    .Arg(XLL_LPOPER, L"swapData1", L"is the first double argument.", L"2")
    .Arg(XLL_LPOPER, L"bondData1", L"is the first double argument.", L"2")
    .Arg(XLL_LPOPER, L"bmaData1", L"is the first double argument.", L"2")
    // Paste function category.
    .Category(L"Example")
    // Insert Function description.
    .FunctionHelp(L"Help on XLL.FUNCTION goes here.")
    // Create entry for this function in Sandcastle Help File Builder project file.
    .Alias(L"XLL.FUNCTION.ALIAS") // alternate name
    .Documentation(
        PARA_(
            L"Free-form documentation for " C_(L"XLL.FUNCTION") L" goes here."
        )
        PARA_(L"But you can include MAML directives.")
        PARA_(L"This is " B_(L"bold") " and so is " B_("this"))
        PARA_(L"Math: " MATH_(int_ SUB_(minus_ infin_) SUP_(infin_) L"e" SUP_(L"x" sup2_ L"/2") L" dx"))
    )
);

LPOPER WINAPI fraDataTest(XLOPER12* depositData1,
    XLOPER12* fraData1,
    XLOPER12* immFutData1,
    XLOPER12* asxFutData1,
    XLOPER12* swapData1,
    XLOPER12* bondData1,
    XLOPER12* bmaData1) {
#pragma XLLEXPORT
    static OPER result;

    using namespace piecewise_yield_curve_test;
    Real tolerance = 1.0e-9;
    int sizeDepositData = (int)depositData1->val.array.rows;
    int count = 0;
    std::vector<Datum> depositData;
    for (int i = 0; i < sizeDepositData; i++) {
        Integer a = (int)depositData1->val.array.lparray[count].val.num;
        count++;
        std::string bb = wtoa(depositData1->val.array.lparray[count].val.str);
        TimeUnit b = convertTime(bb);
        count++;
        Rate c = depositData1->val.array.lparray[count].val.num;
        count++;
        Datum sub = { a, b, c };
        depositData.push_back(sub);
    }
    count = 0;
    int sizefraData = (int)fraData1->val.array.rows;
    std::vector<Datum> fraData;
    for (int i = 0; i < sizefraData; i++) {
        Integer a = (int)fraData1->val.array.lparray[count].val.num;
        count++;
        std::string bb = wtoa(fraData1->val.array.lparray[count].val.str);
        TimeUnit b = convertTime(bb);
        count++;
        Rate c = fraData1->val.array.lparray[count].val.num;
        count++;
        Datum sub = { a, b, c };
        fraData.push_back(sub);
    }
    count = 0;
    int sizeimmFutData = (int)immFutData1->val.array.rows;
    std::vector<Datum> immFutData;
    for (int i = 0; i < sizeimmFutData; i++) {
        Integer a = (int)immFutData1->val.array.lparray[count].val.num;
        count++;
        std::string bb = wtoa(immFutData1->val.array.lparray[count].val.str);
        TimeUnit b = convertTime(bb);
        count++;
        Rate c = immFutData1->val.array.lparray[count].val.num;
        count++;
        Datum sub = { a, b, c };
        immFutData.push_back(sub);
    }
    count = 0;
    int sizeasxFutData = (int)asxFutData1->val.array.rows;
    std::vector<Datum> asxFutData;
    for (int i = 0; i < sizeasxFutData; i++) {
        Integer a = (int)asxFutData1->val.array.lparray[count].val.num;
        count++;
        std::string bb = wtoa(asxFutData1->val.array.lparray[count].val.str);
        TimeUnit b = convertTime(bb);
        count++;
        Rate c = asxFutData1->val.array.lparray[count].val.num;
        count++;
        Datum sub = { a, b, c };
        asxFutData.push_back(sub);
    }
    count = 0;
    int sizeswapData = (int)swapData1->val.array.rows;
    std::vector<Datum> swapData;
    for (int i = 0; i < sizeswapData; i++) {
        Integer a = (int)swapData1->val.array.lparray[count].val.num;
        count++;
        std::string bb = wtoa(swapData1->val.array.lparray[count].val.str);
        TimeUnit b = convertTime(bb);
        count++;
        Rate c = swapData1->val.array.lparray[count].val.num;
        count++;
        Datum sub = { a, b, c };
        swapData.push_back(sub);
    }
    count = 0;
    int sizebondData = (int)bondData1->val.array.rows;
    std::vector<BondDatum> bondData;
    for (int i = 0; i < sizebondData; i++) {
        Integer a = (int)bondData1->val.array.lparray[count].val.num;
        count++;
        std::string bb = wtoa(bondData1->val.array.lparray[count].val.str);
        TimeUnit b = convertTime(bb);
        count++;
        Integer c = (int)bondData1->val.array.lparray[count].val.num;
        count++;
        std::string dd = wtoa(bondData1->val.array.lparray[count].val.str);
        Frequency d = convertFreq(dd);
        count++;
        Rate e = bondData1->val.array.lparray[count].val.num;
        count++;
        Real f = bondData1->val.array.lparray[count].val.num;
        count++;
        BondDatum sub = { a, b, c, d, e, f };
        bondData.push_back(sub);
    }

    count = 0;
    int sizebmaData = (int)bmaData1->val.array.rows;
    std::vector<Datum> bmaData(sizebmaData);
    for (int i = 0; i < sizebmaData; i++) {
        Integer a = (int)bmaData1->val.array.lparray[count].val.num;
        count++;
        std::string bb = wtoa(bmaData1->val.array.lparray[count].val.str);
        TimeUnit b = convertTime(bb);
        count++;
        Rate c = bmaData1->val.array.lparray[count].val.num;
        count++;
        Datum sub = { a, b, c };
        bmaData.push_back(sub);
    }
    CommonVars vars(depositData, fraData, immFutData, asxFutData, swapData, bondData, bmaData);
    QuantLib::Linear interpolator = Linear();
    RelinkableHandle<YieldTermStructure> curveHandle;

    vars.termStructure = ext::shared_ptr<YieldTermStructure>(new
        PiecewiseYieldCurve<ZeroYield, Linear>(vars.settlement, vars.fraHelpers,
            Actual360(),
            interpolator));
    curveHandle.linkTo(vars.termStructure);

#ifdef QL_USE_INDEXED_COUPON
    bool useIndexedFra = false;
#else
    bool useIndexedFra = true;
#endif
 //   std::vector<Rate> expectedRate(vars.fras);
    std::vector<Rate> estimatedRate(vars.fras);
    ext::shared_ptr<IborIndex> euribor3m(new Euribor3M(curveHandle));
    for (Size i = 0; i < vars.fras; i++) {
        Date start =
            vars.calendar.advance(vars.settlement,
                fraData[i].n,
                fraData[i].units,
                euribor3m->businessDayConvention(),
                euribor3m->endOfMonth());
        BOOST_REQUIRE(fraData[i].units == Months);
        Date end = vars.calendar.advance(vars.settlement, 3 + fraData[i].n, Months,
            euribor3m->businessDayConvention(),
            euribor3m->endOfMonth());

        ForwardRateAgreement fra(start, end, Position::Long,
            fraData[i].rate / 100, 100.0,
            euribor3m, curveHandle,
            useIndexedFra);
 //       expectedRate[i] = fraData[i].rate / 100;
        estimatedRate[i] = fra.forwardRate();
/*        if (std::fabs(expectedRate[i] - estimatedRate[i]) > tolerance) {
            BOOST_ERROR(io::ordinal(i + 1) << " FRA failure:" <<
                std::setprecision(8) <<
                "\n  estimated rate: " << io::rate(estimatedRate[i]) <<
                "\n  expected rate:  " << io::rate(expectedRate[i]));
        }
*/
    }

 //   count = 0;
    OPER sub(vars.fras, 1);
    for (int j = 0; j < vars.fras; j++) {
//        sub[count] = expectedRate[j];
//        count++;
        sub[j] = estimatedRate[j];
 //       count++;
 //       sub[count] = std::fabs(expectedRate[j] - estimatedRate[j]) < tolerance ? true : false;
 //       count++;
    }

    result = sub;
    return &result;
}

AddIn xai_function4(
    // Function returning a pointer to an OPER with C++ name xll_function and Excel name XLL.FUNCTION.
    // Don't forget prepend a question mark to the C++ name.
    Function(XLL_LPOPER, L"?immFutsDataTest", L"XLL.immFutsDataTest")
    // First argument is a double called x with an argument description and default value of 2
    .Arg(XLL_LPOPER, L"depositData1", L"is the first double argument.", L"2")
    .Arg(XLL_LPOPER, L"fraData1", L"is the first double argument.", L"2")
    .Arg(XLL_LPOPER, L"immFutData1", L"is the first double argument.", L"2")
    .Arg(XLL_LPOPER, L"asxFutData1", L"is the first double argument.", L"2")
    .Arg(XLL_LPOPER, L"swapData1", L"is the first double argument.", L"2")
    .Arg(XLL_LPOPER, L"bondData1", L"is the first double argument.", L"2")
    .Arg(XLL_LPOPER, L"bmaData1", L"is the first double argument.", L"2")
    // Paste function category.
    .Category(L"Example")
    // Insert Function description.
    .FunctionHelp(L"Help on XLL.FUNCTION goes here.")
    // Create entry for this function in Sandcastle Help File Builder project file.
    .Alias(L"XLL.FUNCTION.ALIAS") // alternate name
    .Documentation(
        PARA_(
            L"Free-form documentation for " C_(L"XLL.FUNCTION") L" goes here."
        )
        PARA_(L"But you can include MAML directives.")
        PARA_(L"This is " B_(L"bold") " and so is " B_("this"))
        PARA_(L"Math: " MATH_(int_ SUB_(minus_ infin_) SUP_(infin_) L"e" SUP_(L"x" sup2_ L"/2") L" dx"))
    )
);

LPOPER WINAPI immFutsDataTest(XLOPER12* depositData1,
    XLOPER12* fraData1,
    XLOPER12* immFutData1,
    XLOPER12* asxFutData1,
    XLOPER12* swapData1,
    XLOPER12* bondData1,
    XLOPER12* bmaData1) {
#pragma XLLEXPORT
    static OPER result;

    using namespace piecewise_yield_curve_test;
    Real tolerance = 1.0e-9;
    int sizeDepositData = (int)depositData1->val.array.rows;
    int count = 0;
    std::vector<Datum> depositData;
    for (int i = 0; i < sizeDepositData; i++) {
        Integer a = (int)depositData1->val.array.lparray[count].val.num;
        count++;
        std::string bb = wtoa(depositData1->val.array.lparray[count].val.str);
        TimeUnit b = convertTime(bb);
        count++;
        Rate c = depositData1->val.array.lparray[count].val.num;
        count++;
        Datum sub = { a, b, c };
        depositData.push_back(sub);
    }
    count = 0;
    int sizefraData = (int)fraData1->val.array.rows;
    std::vector<Datum> fraData;
    for (int i = 0; i < sizefraData; i++) {
        Integer a = (int)fraData1->val.array.lparray[count].val.num;
        count++;
        std::string bb = wtoa(fraData1->val.array.lparray[count].val.str);
        TimeUnit b = convertTime(bb);
        count++;
        Rate c = fraData1->val.array.lparray[count].val.num;
        count++;
        Datum sub = { a, b, c };
        fraData.push_back(sub);
    }
    count = 0;
    int sizeimmFutData = (int)immFutData1->val.array.rows;
    std::vector<Datum> immFutData;
    for (int i = 0; i < sizeimmFutData; i++) {
        Integer a = (int)immFutData1->val.array.lparray[count].val.num;
        count++;
        std::string bb = wtoa(immFutData1->val.array.lparray[count].val.str);
        TimeUnit b = convertTime(bb);
        count++;
        Rate c = immFutData1->val.array.lparray[count].val.num;
        count++;
        Datum sub = { a, b, c };
        immFutData.push_back(sub);
    }
    count = 0;
    int sizeasxFutData = (int)asxFutData1->val.array.rows;
    std::vector<Datum> asxFutData;
    for (int i = 0; i < sizeasxFutData; i++) {
        Integer a = (int)asxFutData1->val.array.lparray[count].val.num;
        count++;
        std::string bb = wtoa(asxFutData1->val.array.lparray[count].val.str);
        TimeUnit b = convertTime(bb);
        count++;
        Rate c = asxFutData1->val.array.lparray[count].val.num;
        count++;
        Datum sub = { a, b, c };
        asxFutData.push_back(sub);
    }
    count = 0;
    int sizeswapData = (int)swapData1->val.array.rows;
    std::vector<Datum> swapData;
    for (int i = 0; i < sizeswapData; i++) {
        Integer a = (int)swapData1->val.array.lparray[count].val.num;
        count++;
        std::string bb = wtoa(swapData1->val.array.lparray[count].val.str);
        TimeUnit b = convertTime(bb);
        count++;
        Rate c = swapData1->val.array.lparray[count].val.num;
        count++;
        Datum sub = { a, b, c };
        swapData.push_back(sub);
    }
    count = 0;
    int sizebondData = (int)bondData1->val.array.rows;
    std::vector<BondDatum> bondData;
    for (int i = 0; i < sizebondData; i++) {
        Integer a = (int)bondData1->val.array.lparray[count].val.num;
        count++;
        std::string bb = wtoa(bondData1->val.array.lparray[count].val.str);
        TimeUnit b = convertTime(bb);
        count++;
        Integer c = (int)bondData1->val.array.lparray[count].val.num;
        count++;
        std::string dd = wtoa(bondData1->val.array.lparray[count].val.str);
        Frequency d = convertFreq(dd);
        count++;
        Rate e = bondData1->val.array.lparray[count].val.num;
        count++;
        Real f = bondData1->val.array.lparray[count].val.num;
        count++;
        BondDatum sub = { a, b, c, d, e, f };
        bondData.push_back(sub);
    }

    count = 0;
    int sizebmaData = (int)bmaData1->val.array.rows;
    std::vector<Datum> bmaData(sizebmaData);
    for (int i = 0; i < sizebmaData; i++) {
        Integer a = (int)bmaData1->val.array.lparray[count].val.num;
        count++;
        std::string bb = wtoa(bmaData1->val.array.lparray[count].val.str);
        TimeUnit b = convertTime(bb);
        count++;
        Rate c = bmaData1->val.array.lparray[count].val.num;
        count++;
        Datum sub = { a, b, c };
        bmaData.push_back(sub);
    }
    CommonVars vars(depositData, fraData, immFutData, asxFutData, swapData, bondData, bmaData);

    QuantLib::Linear interpolator = Linear();
    RelinkableHandle<YieldTermStructure> curveHandle;
    vars.termStructure = ext::shared_ptr<YieldTermStructure>(new
        PiecewiseYieldCurve<ZeroYield, Linear>(vars.settlement, vars.immFutHelpers,
            Actual360(),
            interpolator));
    curveHandle.linkTo(vars.termStructure);

    ext::shared_ptr<IborIndex> euribor3m(new Euribor3M(curveHandle));

//    std::vector<Rate> expectedRate(vars.immFuts);
    std::vector<Rate> estimatedRate(vars.immFuts);
    Date immStart = Date();
    for (Size i = 0; i < vars.immFuts; i++) {
        immStart = IMM::nextDate(immStart, false);
        // if the fixing is before the evaluation date, we
        // just jump forward by one future maturity
        if (euribor3m->fixingDate(immStart) <
            Settings::instance().evaluationDate())
            immStart = IMM::nextDate(immStart, false);
        Date end = vars.calendar.advance(immStart, 3, Months,
            euribor3m->businessDayConvention(),
            euribor3m->endOfMonth());

        ForwardRateAgreement immFut(immStart, end, Position::Long,
            immFutData[i].rate / 100, 100.0,
            euribor3m, curveHandle);
//        expectedRate[i] = immFutData[i].rate / 100;
            estimatedRate[i] = immFut.forwardRate();
/*        if (std::fabs(expectedRate[i] - estimatedRate[i]) > tolerance) {
            BOOST_ERROR(io::ordinal(i + 1) << " IMM futures failure:" <<
                std::setprecision(8) <<
                "\n  estimated rate: " << io::rate(estimatedRate[i]) <<
                "\n  expected rate:  " << io::rate(expectedRate[i]));
        }
*/
    }

//    count = 0;
    OPER sub(vars.immFuts, 1);
    for (int j = 0; j < vars.immFuts; j++) {
//        sub[count] = expectedRate[j];
//        count++;
        sub[j] = estimatedRate[j];
//        count++;
//        sub[count] = std::fabs(expectedRate[j] - estimatedRate[j]) < tolerance ? true : false;
//        count++;
    }

    result = sub;
    return &result;
}

AddIn xai_function5(
    // Function returning a pointer to an OPER with C++ name xll_function and Excel name XLL.FUNCTION.
    // Don't forget prepend a question mark to the C++ name.
    Function(XLL_LPOPER, L"?asxFutsDataTest", L"XLL.asxFutsDataTest")
    // First argument is a double called x with an argument description and default value of 2
    .Arg(XLL_LPOPER, L"depositData1", L"is the first double argument.", L"2")
    .Arg(XLL_LPOPER, L"fraData1", L"is the first double argument.", L"2")
    .Arg(XLL_LPOPER, L"immFutData1", L"is the first double argument.", L"2")
    .Arg(XLL_LPOPER, L"asxFutData1", L"is the first double argument.", L"2")
    .Arg(XLL_LPOPER, L"swapData1", L"is the first double argument.", L"2")
    .Arg(XLL_LPOPER, L"bondData1", L"is the first double argument.", L"2")
    .Arg(XLL_LPOPER, L"bmaData1", L"is the first double argument.", L"2")
    // Paste function category.
    .Category(L"Example")
    // Insert Function description.
    .FunctionHelp(L"Help on XLL.FUNCTION goes here.")
    // Create entry for this function in Sandcastle Help File Builder project file.
    .Alias(L"XLL.FUNCTION.ALIAS") // alternate name
    .Documentation(
        PARA_(
            L"Free-form documentation for " C_(L"XLL.FUNCTION") L" goes here."
        )
        PARA_(L"But you can include MAML directives.")
        PARA_(L"This is " B_(L"bold") " and so is " B_("this"))
        PARA_(L"Math: " MATH_(int_ SUB_(minus_ infin_) SUP_(infin_) L"e" SUP_(L"x" sup2_ L"/2") L" dx"))
    )
);

LPOPER WINAPI asxFutsDataTest(XLOPER12* depositData1,
    XLOPER12* fraData1,
    XLOPER12* immFutData1,
    XLOPER12* asxFutData1,
    XLOPER12* swapData1,
    XLOPER12* bondData1,
    XLOPER12* bmaData1) {
#pragma XLLEXPORT
    static OPER result;

    using namespace piecewise_yield_curve_test;
    Real tolerance = 1.0e-9;
    int sizeDepositData = (int)depositData1->val.array.rows;
    int count = 0;
    std::vector<Datum> depositData;
    for (int i = 0; i < sizeDepositData; i++) {
        Integer a = (int)depositData1->val.array.lparray[count].val.num;
        count++;
        std::string bb = wtoa(depositData1->val.array.lparray[count].val.str);
        TimeUnit b = convertTime(bb);
        count++;
        Rate c = depositData1->val.array.lparray[count].val.num;
        count++;
        Datum sub = { a, b, c };
        depositData.push_back(sub);
    }
    count = 0;
    int sizefraData = (int)fraData1->val.array.rows;
    std::vector<Datum> fraData;
    for (int i = 0; i < sizefraData; i++) {
        Integer a = (int)fraData1->val.array.lparray[count].val.num;
        count++;
        std::string bb = wtoa(fraData1->val.array.lparray[count].val.str);
        TimeUnit b = convertTime(bb);
        count++;
        Rate c = fraData1->val.array.lparray[count].val.num;
        count++;
        Datum sub = { a, b, c };
        fraData.push_back(sub);
    }
    count = 0;
    int sizeimmFutData = (int)immFutData1->val.array.rows;
    std::vector<Datum> immFutData;
    for (int i = 0; i < sizeimmFutData; i++) {
        Integer a = (int)immFutData1->val.array.lparray[count].val.num;
        count++;
        std::string bb = wtoa(immFutData1->val.array.lparray[count].val.str);
        TimeUnit b = convertTime(bb);
        count++;
        Rate c = immFutData1->val.array.lparray[count].val.num;
        count++;
        Datum sub = { a, b, c };
        immFutData.push_back(sub);
    }
    count = 0;
    int sizeasxFutData = (int)asxFutData1->val.array.rows;
    std::vector<Datum> asxFutData;
    for (int i = 0; i < sizeasxFutData; i++) {
        Integer a = (int)asxFutData1->val.array.lparray[count].val.num;
        count++;
        std::string bb = wtoa(asxFutData1->val.array.lparray[count].val.str);
        TimeUnit b = convertTime(bb);
        count++;
        Rate c = asxFutData1->val.array.lparray[count].val.num;
        count++;
        Datum sub = { a, b, c };
        asxFutData.push_back(sub);
    }
    count = 0;
    int sizeswapData = (int)swapData1->val.array.rows;
    std::vector<Datum> swapData;
    for (int i = 0; i < sizeswapData; i++) {
        Integer a = (int)swapData1->val.array.lparray[count].val.num;
        count++;
        std::string bb = wtoa(swapData1->val.array.lparray[count].val.str);
        TimeUnit b = convertTime(bb);
        count++;
        Rate c = swapData1->val.array.lparray[count].val.num;
        count++;
        Datum sub = { a, b, c };
        swapData.push_back(sub);
    }
    count = 0;
    int sizebondData = (int)bondData1->val.array.rows;
    std::vector<BondDatum> bondData;
    for (int i = 0; i < sizebondData; i++) {
        Integer a = (int)bondData1->val.array.lparray[count].val.num;
        count++;
        std::string bb = wtoa(bondData1->val.array.lparray[count].val.str);
        TimeUnit b = convertTime(bb);
        count++;
        Integer c = (int)bondData1->val.array.lparray[count].val.num;
        count++;
        std::string dd = wtoa(bondData1->val.array.lparray[count].val.str);
        Frequency d = convertFreq(dd);
        count++;
        Rate e = bondData1->val.array.lparray[count].val.num;
        count++;
        Real f = bondData1->val.array.lparray[count].val.num;
        count++;
        BondDatum sub = { a, b, c, d, e, f };
        bondData.push_back(sub);
    }

    count = 0;
    int sizebmaData = (int)bmaData1->val.array.rows;
    std::vector<Datum> bmaData(sizebmaData);
    for (int i = 0; i < sizebmaData; i++) {
        Integer a = (int)bmaData1->val.array.lparray[count].val.num;
        count++;
        std::string bb = wtoa(bmaData1->val.array.lparray[count].val.str);
        TimeUnit b = convertTime(bb);
        count++;
        Rate c = bmaData1->val.array.lparray[count].val.num;
        count++;
        Datum sub = { a, b, c };
        bmaData.push_back(sub);
    }
    CommonVars vars(depositData, fraData, immFutData, asxFutData, swapData, bondData, bmaData);
    QuantLib::Linear interpolator = Linear();
    RelinkableHandle<YieldTermStructure> curveHandle;

    vars.termStructure = ext::shared_ptr<YieldTermStructure>(new
        PiecewiseYieldCurve<ZeroYield, Linear>(vars.settlement, vars.asxFutHelpers,
            Actual360(),
            interpolator));
    curveHandle.linkTo(vars.termStructure);

    ext::shared_ptr<IborIndex> euribor3m(new Euribor3M(curveHandle));

//    std::vector<Rate> expectedRate(vars.immFuts);
    std::vector<Rate> estimatedRate(vars.immFuts);

    Date asxStart = Date();
    for (Size i = 0; i < vars.asxFuts; i++) {
        asxStart = ASX::nextDate(asxStart, false);
        // if the fixing is before the evaluation date, we
        // just jump forward by one future maturity
        if (euribor3m->fixingDate(asxStart) <
            Settings::instance().evaluationDate())
            asxStart = ASX::nextDate(asxStart, false);
        if (euribor3m->fixingCalendar().isHoliday(asxStart))
            continue;
        Date end = vars.calendar.advance(asxStart, 3, Months,
            euribor3m->businessDayConvention(),
            euribor3m->endOfMonth());

        ForwardRateAgreement asxFut(asxStart, end, Position::Long,
            asxFutData[i].rate / 100, 100.0,
            euribor3m, curveHandle);
//        expectedRate[i] = asxFutData[i].rate / 100;
            estimatedRate[i] = asxFut.forwardRate();
/*        if (std::fabs(expectedRate[i] - estimatedRate[i]) > tolerance) {
            BOOST_ERROR(io::ordinal(i + 1) << " ASX futures failure:" <<
                std::setprecision(8) <<
                "\n  estimated rate: " << io::rate(estimatedRate[i]) <<
                "\n  expected rate:  " << io::rate(expectedRate[i]));
        }
*/
    }
//    count = 0;
    OPER sub(vars.asxFuts,1);
    for (int j = 0; j < vars.asxFuts; j++) {
//        sub[count] = expectedRate[j];
//        count++;
        sub[j] = estimatedRate[j];
//        count++;
//        sub[count] = std::fabs(expectedRate[j] - estimatedRate[j]) < tolerance ? true : false;
//        count++;
    }

    result = sub;
    return &result;
}

AddIn xai_functionbma(
    // Function returning a pointer to an OPER with C++ name xll_function and Excel name XLL.FUNCTION.
    // Don't forget prepend a question mark to the C++ name.
    Function(XLL_LPOPER, L"?bmaTest", L"XLL.bmaTest")
    // First argument is a double called x with an argument description and default value of 2
    .Arg(XLL_LPOPER, L"depositData1", L"is the first double argument.", L"2")
    .Arg(XLL_LPOPER, L"fraData1", L"is the first double argument.", L"2")
    .Arg(XLL_LPOPER, L"immFutData1", L"is the first double argument.", L"2")
    .Arg(XLL_LPOPER, L"asxFutData1", L"is the first double argument.", L"2")
    .Arg(XLL_LPOPER, L"swapData1", L"is the first double argument.", L"2")
    .Arg(XLL_LPOPER, L"bondData1", L"is the first double argument.", L"2")
    .Arg(XLL_LPOPER, L"bmaData1", L"is the first double argument.", L"2")
    // Paste function category.
    .Category(L"Example")
    // Insert Function description.
    .FunctionHelp(L"Help on XLL.FUNCTION goes here.")
    // Create entry for this function in Sandcastle Help File Builder project file.
    .Alias(L"XLL.FUNCTION.ALIAS") // alternate name
    .Documentation(
        PARA_(
            L"Free-form documentation for " C_(L"XLL.FUNCTION") L" goes here."
        )
        PARA_(L"But you can include MAML directives.")
        PARA_(L"This is " B_(L"bold") " and so is " B_("this"))
        PARA_(L"Math: " MATH_(int_ SUB_(minus_ infin_) SUP_(infin_) L"e" SUP_(L"x" sup2_ L"/2") L" dx"))
    )
);

LPOPER WINAPI bmaTest(XLOPER12* depositData1,
    XLOPER12* fraData1,
    XLOPER12* immFutData1,
    XLOPER12* asxFutData1,
    XLOPER12* swapData1,
    XLOPER12* bondData1,
    XLOPER12* bmaData1) {
#pragma XLLEXPORT
    static OPER result;

    using namespace piecewise_yield_curve_test;
    Real tolerance = 1.0e-9;

    int sizeDepositData = (int)depositData1->val.array.rows;
    int count = 0;
    std::vector<Datum> depositData;
    for (int i = 0; i < sizeDepositData; i++) {
        Integer a = (int)depositData1->val.array.lparray[count].val.num;
        count++;
        std::string bb = wtoa(depositData1->val.array.lparray[count].val.str);
        TimeUnit b = convertTime(bb);
        count++;
        Rate c = depositData1->val.array.lparray[count].val.num;
        count++;
        Datum sub = { a, b, c };
        depositData.push_back(sub);
    }
    count = 0;
    int sizefraData = (int)fraData1->val.array.rows;
    std::vector<Datum> fraData;
    for (int i = 0; i < sizefraData; i++) {
        Integer a = (int)fraData1->val.array.lparray[count].val.num;
        count++;
        std::string bb = wtoa(fraData1->val.array.lparray[count].val.str);
        TimeUnit b = convertTime(bb);
        count++;
        Rate c = fraData1->val.array.lparray[count].val.num;
        count++;
        Datum sub = { a, b, c };
        fraData.push_back(sub);
    }
    count = 0;
    int sizeimmFutData = (int)immFutData1->val.array.rows;
    std::vector<Datum> immFutData;
    for (int i = 0; i < sizeimmFutData; i++) {
        Integer a = (int)immFutData1->val.array.lparray[count].val.num;
        count++;
        std::string bb = wtoa(immFutData1->val.array.lparray[count].val.str);
        TimeUnit b = convertTime(bb);
        count++;
        Rate c = immFutData1->val.array.lparray[count].val.num;
        count++;
        Datum sub = { a, b, c };
        immFutData.push_back(sub);
    }
    count = 0;
    int sizeasxFutData = (int)asxFutData1->val.array.rows;
    std::vector<Datum> asxFutData;
    for (int i = 0; i < sizeasxFutData; i++) {
        Integer a = (int)asxFutData1->val.array.lparray[count].val.num;
        count++;
        std::string bb = wtoa(asxFutData1->val.array.lparray[count].val.str);
        TimeUnit b = convertTime(bb);
        count++;
        Rate c = asxFutData1->val.array.lparray[count].val.num;
        count++;
        Datum sub = { a, b, c };
        asxFutData.push_back(sub);
    }
    count = 0;
    int sizeswapData = (int)swapData1->val.array.rows;
    std::vector<Datum> swapData;
    for (int i = 0; i < sizeswapData; i++) {
        Integer a = (int)swapData1->val.array.lparray[count].val.num;
        count++;
        std::string bb = wtoa(swapData1->val.array.lparray[count].val.str);
        TimeUnit b = convertTime(bb);
        count++;
        Rate c = swapData1->val.array.lparray[count].val.num;
        count++;
        Datum sub = { a, b, c };
        swapData.push_back(sub);
    }
    count = 0;
    int sizebondData = (int)bondData1->val.array.rows;
    std::vector<BondDatum> bondData;
    for (int i = 0; i < sizebondData; i++) {
        Integer a = (int)bondData1->val.array.lparray[count].val.num;
        count++;
        std::string bb = wtoa(bondData1->val.array.lparray[count].val.str);
        TimeUnit b = convertTime(bb);
        count++;
        Integer c = (int)bondData1->val.array.lparray[count].val.num;
        count++;
        std::string dd = wtoa(bondData1->val.array.lparray[count].val.str);
        Frequency d = convertFreq(dd);
        count++;
        Rate e = bondData1->val.array.lparray[count].val.num;
        count++;
        Real f = bondData1->val.array.lparray[count].val.num;
        count++;
        BondDatum sub = { a, b, c, d, e, f };
        bondData.push_back(sub);
    }

    count = 0;
    int sizebmaData = (int)bmaData1->val.array.rows;
    std::vector<Datum> bmaData;
    for (int i = 0; i < sizebmaData; i++) {
        Integer a = (int)bmaData1->val.array.lparray[count].val.num;
        count++;
        std::string bb = wtoa(bmaData1->val.array.lparray[count].val.str);
        TimeUnit b = convertTime(bb);
        count++;
        Rate c = bmaData1->val.array.lparray[count].val.num;
        count++;
        Datum sub = { a, b, c };
        bmaData.push_back(sub);
    }
    CommonVars vars(depositData, fraData, immFutData, asxFutData, swapData, bondData, bmaData);

    // re-adjust settlement
    vars.calendar = JointCalendar(BMAIndex().fixingCalendar(),
        USDLibor(3 * Months).fixingCalendar(),
        JoinHolidays);
    vars.today = vars.calendar.adjust(Date::todaysDate());
    Settings::instance().evaluationDate() = vars.today;
    vars.settlement =
        vars.calendar.advance(vars.today, vars.settlementDays, Days);

    Handle<YieldTermStructure> riskFreeCurve(
        ext::shared_ptr<YieldTermStructure>(
            new FlatForward(vars.settlement, 0.04, Actual360())));

    ext::shared_ptr<BMAIndex> bmaIndex(new BMAIndex);
    ext::shared_ptr<IborIndex> liborIndex(
        new USDLibor(3 * Months, riskFreeCurve));
    for (Size i = 0; i < vars.bmas; ++i) {
        Handle<Quote> f(vars.fractions[i]);
        vars.bmaHelpers[i] = ext::shared_ptr<RateHelper>(
            new BMASwapRateHelper(f, bmaData[i].n * bmaData[i].units,
                vars.settlementDays,
                vars.calendar,
                Period(vars.bmaFrequency),
                vars.bmaConvention,
                vars.bmaDayCounter,
                bmaIndex,
                liborIndex));
    }

    Weekday w = vars.today.weekday();
    Date lastWednesday =
        (w >= 4) ? vars.today - (w - 4) : vars.today + (4 - w - 7);
    Date lastFixing = bmaIndex->fixingCalendar().adjust(lastWednesday);
    bmaIndex->addFixing(lastFixing, 0.03);

    QuantLib::Linear interpolator = Linear();

    vars.termStructure = ext::shared_ptr<YieldTermStructure>(new
        PiecewiseYieldCurve<ZeroYield, Linear, IterativeBootstrap>(vars.today, vars.bmaHelpers,
            Actual360(),
            interpolator));

    RelinkableHandle<YieldTermStructure> curveHandle;
    curveHandle.linkTo(vars.termStructure);

    // check BMA swaps
//    std::vector<Real> expectedFraction(vars.bmas);
    std::vector<Real> estimatedFraction(vars.bmas);

    ext::shared_ptr<BMAIndex> bma(new BMAIndex(curveHandle));
    ext::shared_ptr<IborIndex> libor3m(new USDLibor(3 * Months,
        riskFreeCurve));
    for (Size i = 0; i < vars.bmas; i++) {
        Period tenor = bmaData[i].n * bmaData[i].units;

        Schedule bmaSchedule =
            MakeSchedule().from(vars.settlement)
            .to(vars.settlement + tenor)
            .withFrequency(vars.bmaFrequency)
            .withCalendar(bma->fixingCalendar())
            .withConvention(vars.bmaConvention)
            .backwards();
        Schedule liborSchedule =
            MakeSchedule().from(vars.settlement)
            .to(vars.settlement + tenor)
            .withTenor(libor3m->tenor())
            .withCalendar(libor3m->fixingCalendar())
            .withConvention(libor3m->businessDayConvention())
            .endOfMonth(libor3m->endOfMonth())
            .backwards();

        BMASwap swap(BMASwap::Payer, 100.0,
            liborSchedule, 0.75, 0.0,
            libor3m, libor3m->dayCounter(),
            bmaSchedule, bma, vars.bmaDayCounter);
        swap.setPricingEngine(ext::shared_ptr<PricingEngine>(
            new DiscountingSwapEngine(libor3m->forwardingTermStructure())));

//        expectedFraction[i] = bmaData[i].rate / 100;
            estimatedFraction[i] = swap.fairLiborFraction();
/*        Real error = std::fabs(expectedFraction[i] - estimatedFraction[i]);
        if (error > tolerance) {
            BOOST_ERROR(bmaData[i].n << " year(s) BMA swap:\n"
                << std::setprecision(8)
                << "\n estimated libor fraction: " << estimatedFraction[i]
                << "\n expected libor fraction:  " << expectedFraction[i]
                << "\n error:          " << error
                << "\n tolerance:      " << tolerance);
        }
*/
    }

//    count = 0;
    OPER sub(vars.bmas, 1);
    for (int j = 0; j < vars.bmas; j++) {
//        sub[count] = expectedFraction[j];
//        count++;
        sub[j] = estimatedFraction[j];
//        count++;
//        sub[count] = std::fabs(expectedFraction[j] - estimatedFraction[j]) < tolerance ? true : false;
//        count++;
    }

    result = sub;
    return &result;
}


#include <iostream>
#include <NTL/ZZ.h>
#include <memory>

#include <boost/program_options.hpp>

#include "Lenstra.h"
#include "Options.h"
#include "EdwardsModel.h"
#include "WeierstrassModel.h"

namespace po = boost::program_options;

int main(int argc, char **argv) {
    std::shared_ptr<Options> options = std::make_shared<Options>();

    po::options_description desc("OPTIONS");
    po::variables_map vm;
    desc.add_options()
            ("help,h", "produce help message")
            ("weierstrass_model,w", po::bool_switch(&options->weierstrass), "set Weierstrass model")
            ("edwards_model,e", po::bool_switch(&options->edwards), "set Edwards model")
            ("timer,t", po::bool_switch(&options->timer), "time measurement")
            ("parallel,p", po::bool_switch(&options->parallel), "start parallel")
            ("bound,b", po::value<NTL::ZZ>(options->bound.get()), "Maximal bound for iterations (Default square root of composite number)")
            ("composite-number,n", po::value<NTL::ZZ>(options->composite_number.get())->required(), "Positive integer bigger than 1 to factorize");
    try {
        po::store(po::parse_command_line(argc, argv, desc), vm);
        if (vm.count("help")) {
            std::cout << argv[0] << " [OPTIONS] --composite-number/-n COMPOSITE NUMBER\n";
            std::cout << desc << "\n";
            return 1;
        }
        po::notify(vm);
    } catch (std::exception &exception) {
        std::cout << exception.what() << "\n";
        return 1;
    }

    if (options->weierstrass && options->edwards) {
        std::cerr << "Only one model can be specified!\n";
        return 2;
    }

    options->weierstrass = !options->edwards;

    if (*options->composite_number < 2) {
        std::cerr << "Composite number must be positive integer bigger than 1!\n";
        return 3;
    }

    std::cout << "Factorizing number: " << *options->composite_number << '\n';
    std::cout << "Using model: " << (options->edwards ? "Edwards" : "Weierstrass") << '\n';
    std::cout << "Using timer: " << (options->timer ? "yes" : "no") << '\n';
    double start_time = 0.0, end_time;
    std::shared_ptr<AbstractModel> model;
    if (options->weierstrass) {
        model = std::make_shared<WeierstrassModel>(options);
    } else {
        model = std::make_shared<EdwardsModel>(options);
    }
    Lenstra ecm(options, model);
    if (options->timer) {
        start_time = NTL::GetTime();
    }
    NTL::ZZ factor;
    if (!options->parallel) {
        factor = ecm.factorize();
    } else {
        factor = ecm.factorize_parallel(argc, argv);
    }

    end_time = NTL::GetTime();
    if (options->timer && !options->parallel) {
        std::cout << "time = " << end_time - start_time << " s\n";
    }

    if (factor != 0)
        std::cout << "Factor = " << factor << "\n";

    return 0;
}


#include <iostream>
#include <fstream>
using namespace std;
#include <opencv2/core/core.hpp>
#include <opencv2/highgui/highgui.hpp>
#include <Eigen/Geometry>
#include <boost/format.hpp>  // for formating strings
#include <pcl/point_types.h>
#include <pcl/io/pcd_io.h>
#include <pcl/visualization/pcl_visualizer.h>

int main( int argc, char** argv )
{
    vector<cv::Mat> colorImgs, depthImgs;    // 彩色图和深度图
    vector<Eigen::Isometry3d, Eigen::aligned_allocator<Eigen::Isometry3d>> poses;         // 相机位姿

    ifstream fin("/home/fsdh/zyhtest_ws/src/votest/src/pose.txt");
    if (!fin)
    {
        cerr<<"请在有pose.txt的目录下运行此程序"<<endl;
        return 1;
    }

    for ( int i=0; i<5; i++ )
    {
        boost::format fmt( "%s/%d.%s" ); //图像文件格式
        colorImgs.push_back( cv::imread( (fmt%"/home/fsdh/zyhtest_ws/src/votest/src/color"%(i+1)%"png").str() ));
        depthImgs.push_back( cv::imread( (fmt%"/home/fsdh/zyhtest_ws/src/votest/src/depth"%(i+1)%"pgm").str(), -1 )); // 使用-1读取原始图像

        double data[7] = {0};
        for ( auto& d:data )
            fin>>d;
        Eigen::Quaterniond q( data[6], data[3], data[4], data[5] );
        Eigen::Isometry3d T(q);
        T.pretranslate( Eigen::Vector3d( data[0], data[1], data[2] ));
        poses.push_back( T );
    }

    // 计算点云并拼接
    // 相机内参
    double cx = 325.5;
    double cy = 253.5;
    double fx = 518.0;
    double fy = 519.0;
    double depthScale = 1000.0;

    cout<<"正在将图像转换为点云..."<<endl;

    // 定义点云使用的格式：这里用的是XYZRGB
    typedef pcl::PointXYZRGB PointT;
    typedef pcl::PointCloud<PointT> PointCloud;

    // 新建一个点云
    PointCloud::Ptr pointCloud( new PointCloud );
    for ( int i=0; i<5; i++ )
    {
        cout<<"转换图像中: "<<i+1<<endl;
        cv::Mat color = colorImgs[i];
        cv::Mat depth = depthImgs[i];
        Eigen::Isometry3d T = poses[i];
        for ( int v=0; v<color.rows; v++ )
            for ( int u=0; u<color.cols; u++ )
            {
                unsigned int d = depth.ptr<unsigned short> ( v )[u]; // 深度值
                if ( d==0 ) continue; // 为0表示没有测量到
                Eigen::Vector3d point;
                point[2] = double(d)/depthScale;
                point[0] = (u-cx)*point[2]/fx;
                point[1] = (v-cy)*point[2]/fy;
                Eigen::Vector3d pointWorld = T*point;

                PointT p ;
                p.x = pointWorld[0];
                p.y = pointWorld[1];
                p.z = pointWorld[2];
                p.b = color.data[ v*color.step+u*color.channels() ];
                p.g = color.data[ v*color.step+u*color.channels()+1 ];
                p.r = color.data[ v*color.step+u*color.channels()+2 ];
                pointCloud->points.push_back( p );
            }
    }

    pointCloud->is_dense = false;
    cout<<"点云共有"<<pointCloud->size()<<"个点."<<endl;
    pcl::io::savePCDFileBinary("map.pcd", *pointCloud );
    return 0;
}


#include <ros/package.h>
#include <pcl/io/pcd_io.h>
#include <boost/filesystem.hpp>
#include <camera_calibration_parsers/parse_ini.h>
#include <Eigen/Core>
#include <pcl/common/common.h>
#include <pcl/common/transforms.h>
#include <tf_conversions/tf_eigen.h>
#include <boost/algorithm/string/split.hpp>
#include <string>
#include <pcl/filters/conditional_removal.h>
#include <apc_capture/apc_tote_features.h>

#include <pcl/features/integral_image_normal.h>

namespace fs = boost::filesystem;
typedef pcl::PointCloud<pcl::PointXYZ> pointCloundXYZ;
typedef pcl::PointCloud<pcl::PointXYZRGB> pointCloundXYZRGB;

int main(int argc, char** argv) {
    if (argc != 2) {
        fprintf(stderr, "Usage: apc_tote_features_exe <path to dataset>\n");
        return 1;
    }

    // for now using just one pcd file, later will be chaged to run over entire dataset
    std::string dataPath = argv[1];
    std::string rosPackagePath = ros::package::getPath("apc_capture");

    fs::path dataDir (dataPath);
    if(!fs::is_directory(dataDir) || !fs::is_directory(dataDir))
    {
        fprintf(stderr, "Could not open the data directory.\n");
        return 0;
    }
    std::string iniFileName, pcdFileName, rgbFileName ;

    // load tote mesh
    pointCloundXYZ::Ptr m_cloudfromMesh(new pointCloundXYZ);
    pcl::PointXYZRGB min, max;
    pcl::PointXYZ minXYZ, maxXYZ;
    std::string MeshPath = rosPackagePath + "/resource/pcd/tote_face_removed.pcd";
    if (pcl::io::loadPCDFile(MeshPath, *m_cloudfromMesh) < 0)
    {
        fprintf(stderr, "Could not load tote mesh\n");
        return 1;
    }
    pcl::getMinMax3D(*m_cloudfromMesh, minXYZ, maxXYZ);

    std::cout << " Mesh Min/Max " << minXYZ << " " << maxXYZ << std::endl;

    fs::directory_iterator itr(dataDir);
    fs::directory_iterator end_itr;

    for(;itr != end_itr;itr++) {
        printf("\n\nProcessing frame %s\n", itr->path().c_str());

        iniFileName = itr->path().string() + "/camera.ini";
        pcdFileName = itr->path().string() + "/frame.pcd";
        rgbFileName = itr->path().string() + "/rgb.png";

        std::cout << pcdFileName << std::endl;

        pointCloundXYZ::Ptr m_cloudFromSensorXYZ(new pointCloundXYZ);  //for registration
        pointCloundXYZRGB::Ptr m_cloudFromSensorXYZRGB(new pointCloundXYZRGB);; //for feature computation

        //load rgb image
        cv::Mat rgbImage ;
        rgbImage = cv::imread(rgbFileName);

        // load pcd from file
        std::cout << " trying to load" << std::endl;
        if (pcl::io::loadPCDFile(pcdFileName, *m_cloudFromSensorXYZRGB) < 0) {
            fprintf(stderr, "Could not load PCD file 'frame.pcd' ");
            return 1;
        }
        std::cout << " pcd loaded" << std::endl;
        pcl::copyPointCloud(*m_cloudFromSensorXYZRGB, *m_cloudFromSensorXYZ);

        apc_object_perception::ApcToteFeatures features;

        features.setMeshCloud(m_cloudfromMesh);
        features.setRGBImage(rgbImage);
        std::cout << " Mesh cloud set" << std::endl;
        Eigen::Vector3f cameraGuess;
        cameraGuess.x() = 0;//0.07;
        cameraGuess.y() = 0;//0;
        cameraGuess.z() = 0.7;//0.7;
        std::cout << "camera guess: " << cameraGuess.transpose() << std::endl;

        Eigen::Affine3f translationCaminWorld;
        translationCaminWorld = Eigen::Translation3f(cameraGuess);
        Eigen::Affine3f transformCaminWorld =  translationCaminWorld  * Eigen::AngleAxisf(M_PI,Eigen::Vector3f::UnitX())  /*  ; Eigen::AngleAxisf(M_PI ,Eigen::Vector3f::UnitZ()) */ ;

        printf("Running ICP...\n");
        Eigen::Affine3f camPoints2Tote = features.doRegistration(m_cloudFromSensorXYZ, transformCaminWorld);
        printf("done.\n");

        std::cout << " camPoints2Tote " << camPoints2Tote.matrix() << std::endl;
        // transform the points in box frame

        pcl::PointCloud<pcl::PointXYZRGB>::Ptr cloudInBoxFrame(new pcl::PointCloud<pcl::PointXYZRGB>);
        pcl::transformPointCloud(*m_cloudFromSensorXYZRGB, *cloudInBoxFrame, camPoints2Tote);

        // Filter out some outliers
        pcl::ConditionAnd<pcl::PointXYZRGB>::Ptr range_cond(new pcl::ConditionAnd<pcl::PointXYZRGB>());
        range_cond->addComparison(pcl::FieldComparison<pcl::PointXYZRGB>::ConstPtr(
                new pcl::FieldComparison<pcl::PointXYZRGB>("x", pcl::ComparisonOps::GT, -0.31)));
        range_cond->addComparison(pcl::FieldComparison<pcl::PointXYZRGB>::ConstPtr(
                new pcl::FieldComparison<pcl::PointXYZRGB>("x", pcl::ComparisonOps::LT, 0.31)));
        range_cond->addComparison(pcl::FieldComparison<pcl::PointXYZRGB>::ConstPtr(
                new pcl::FieldComparison<pcl::PointXYZRGB>("y", pcl::ComparisonOps::GT, -0.19)));
        range_cond->addComparison(pcl::FieldComparison<pcl::PointXYZRGB>::ConstPtr(
                new pcl::FieldComparison<pcl::PointXYZRGB>("y", pcl::ComparisonOps::LT, 0.19)));
        range_cond->addComparison(pcl::FieldComparison<pcl::PointXYZRGB>::ConstPtr(
                new pcl::FieldComparison<pcl::PointXYZRGB>("z", pcl::ComparisonOps::GT, 0)));
        range_cond->addComparison(pcl::FieldComparison<pcl::PointXYZRGB>::ConstPtr(
                new pcl::FieldComparison<pcl::PointXYZRGB>("z", pcl::ComparisonOps::LT, 0.4)));

        pcl::ConditionalRemoval<pcl::PointXYZRGB> removal(range_cond);
        removal.setInputCloud(cloudInBoxFrame);
        removal.setKeepOrganized(true);
        pcl::PointCloud<pcl::PointXYZRGB>::Ptr cloudT(new pcl::PointCloud<pcl::PointXYZRGB>);
        removal.filter(*cloudT);
        cloudInBoxFrame = cloudT;

        std::string cameraName;
        sensor_msgs::CameraInfoPtr camInfo(new sensor_msgs::CameraInfo);
        camera_calibration_parsers::readCalibrationIni(iniFileName,cameraName,*camInfo);

        pcl::getMinMax3D(*cloudInBoxFrame, min, max);

        std::cout << " Min/Max " << min << " " << max << std::endl;

          // compute the features
        cv::Mat_<float> height3D, depth, dist2wall, relativeMin;
        cv::Mat isValidHeight;
        cv::Mat edgeFeature;
        features.setPointCloud(cloudInBoxFrame);
        features.setCameraModel(camInfo);
        features.computeHeightFeatures(height3D, isValidHeight, depth);
        features.computeEdgeFeature(edgeFeature);
        features.computeDistance2WallFeature(dist2wall);
        features.computeRelativeMeanDiffFeature(relativeMin);
        cv::Mat toteMask ;

        Eigen::Affine3f toteToCameraFrame = camPoints2Tote.inverse();
        features.createToteMask(toteToCameraFrame,toteMask);

		pcl::PointCloud<pcl::Normal>::Ptr normalCloud(new pcl::PointCloud<pcl::Normal>);
		{
			pcl::IntegralImageNormalEstimation<pcl::PointXYZRGB, pcl::Normal> ne;

			ne.setNormalEstimationMethod(ne.COVARIANCE_MATRIX);
			ne.setMaxDepthChangeFactor(0.8f);
			ne.setNormalSmoothingSize(30.0f);

			ne.setInputCloud(m_cloudFromSensorXYZRGB);
			ne.compute(*normalCloud);
		}

        cv::Mat hha = features.computeHHA(camPoints2Tote, m_cloudFromSensorXYZRGB, normalCloud) ;

        // For visualizing
        cv::Mat height3DViz(height3D.rows, height3D.cols, CV_8UC1);
        cv::Mat dist2wallViz(dist2wall.rows, dist2wall.cols, CV_8UC1);
        cv::Mat relativeMinViz(relativeMin.rows, relativeMin.cols, CV_8UC1);

        float height3DMax = 0.4f;
        float dist2wallMax = 0.2f;

/*      double height3DMin, height3DMax;
        cv::minMaxLoc(height3D, &height3DMin, &height3DMax);
        std::cout << "Height 3D Min/Max: " << height3DMin << height3DMax << "\n";*/

        for (int y = 0; y < height3D.rows; y++) {
            for (int x = 0; x < height3D.cols; x++) {
                height3DViz.at<uchar>(y, x) = cv::saturate_cast<uint8_t>( ( ( height3D(y, x)  ) / height3DMax  ) * 255);
                dist2wallViz.at<uint8_t>(y,x) = cv::saturate_cast<uint8_t>( ( ( dist2wall(y, x)  ) / dist2wallMax  ) * 255);
                relativeMinViz.at<uint8_t>(y,x) = cv::saturate_cast<uint8_t>( (  relativeMin(y, x)    ) * 255);
            }
        }

        cv::flip(height3DViz, height3DViz, -1);

      double min, max;
        cv::minMaxLoc(height3D, &min, &max);
        std::cout << "Height 3D Min/Max: " << min << " " << max << "\n";

        isValidHeight = 255 * isValidHeight;
        cv::imwrite(itr->path().string() + "/feature_height3D.png", height3DViz);
        cv::imwrite(itr->path().string() + "/feature_isValidHeight.png", isValidHeight);
        cv::imwrite(itr->path().string() + "/feature_edge.png", edgeFeature);
        cv::imwrite(itr->path().string() + "/feature_dist2wall.png", dist2wallViz);
        cv::imwrite(itr->path().string() + "/feature_relativeMeanDiff.png", relativeMinViz);
        cv::imwrite((itr->path() / "bin_mask_estimated.png").c_str(),toteMask);
        cv::imwrite((itr->path() / "feature_hha.png").c_str(), hha);

        FILE *file = fopen((itr->path().string() + "/feature_height3D.raw").c_str(), "w");
        fwrite(height3D.data, sizeof(float), height3D.rows * height3D.cols, file);
        fclose(file);

        file = fopen((itr->path().string() + "/feature_depth.raw").c_str(), "w");
        fwrite(depth.data, sizeof(float), depth.rows * depth.cols, file);
        fclose(file);

        file = fopen((itr->path().string() + "/feature_dist2wall.raw").c_str(), "w");
        fwrite(dist2wall.data, sizeof(float), dist2wall.rows * dist2wall.cols, file);
        fclose(file);

        file = fopen((itr->path().string() + "/feature_relativeMeanDiff.raw").c_str(), "w");
        fwrite(relativeMin.data, sizeof(float), relativeMin.rows * relativeMin.cols, file);
        fclose(file);

    }

    std::cout<<" Done "<<std::endl;
    return 0;
}