Skip to content
Snippets Groups Projects
problem.cpp 53.50 KiB
#include "problem.h"
#include "constraint_base.h"
#include "state_block.h"
#include "state_quaternion.h"
#include "hardware_base.h"
#include "trajectory_base.h"
#include "map_base.h"
#include "processor_motion.h"
#include "processor_tracker.h"
#include "sensor_base.h"
#include "sensor_gps.h"
#include "factory.h"
#include "sensor_factory.h"
#include "processor_factory.h"

#include <algorithm>
#include "capture_pose.h"

namespace wolf
{

// unnamed namespace used for helper functions local to this file.
namespace
{
std::string uppercase(std::string s) {for (auto & c: s) c = std::toupper(c); return s;}
}


Problem::Problem(const std::string& _frame_structure) :
        hardware_ptr_(std::make_shared<HardwareBase>()),
        trajectory_ptr_(std::make_shared<TrajectoryBase>(_frame_structure)),
        map_ptr_(std::make_shared<MapBase>()),
        processor_motion_ptr_(),
        prior_is_set_(false),
        state_size_(0),
        state_cov_size_(0)
{
    if (_frame_structure == "PO 2D")
    {
        state_size_ = 3;
        state_cov_size_ = 3;
    }

    else if (_frame_structure == "PO 3D")
    {
        state_size_ = 7;
        state_cov_size_ = 6;
    }
    else if (_frame_structure == "POV 3D")
    {
        state_size_ = 10;
        state_cov_size_ = 9;
    }
    else std::runtime_error(
            "Problem::Problem(): Unknown frame structure. Add appropriate frame structure to the switch statement.");

}

void Problem::setup()
{
    hardware_ptr_->setProblem(shared_from_this());
    trajectory_ptr_->setProblem(shared_from_this());
    map_ptr_->setProblem(shared_from_this());
}

ProblemPtr Problem::create(const std::string& _frame_structure)
{
    ProblemPtr p(new Problem(_frame_structure)); // We use `new` and not `make_shared` since the Problem constructor is private and cannot be passed to `make_shared`.
    p->setup();
    return p->shared_from_this();
}

Problem::~Problem()
{
    //    WOLF_DEBUG("destructed -P");
}

void Problem::addSensor(SensorBasePtr _sen_ptr)
{
    getHardwarePtr()->addSensor(_sen_ptr);
}

SensorBasePtr Problem::installSensor(const std::string& _sen_type, //
                                     const std::string& _unique_sensor_name, //
                                     const Eigen::VectorXs& _extrinsics, //
                                     IntrinsicsBasePtr _intrinsics)
{
    SensorBasePtr sen_ptr = SensorFactory::get().create(uppercase(_sen_type), _unique_sensor_name, _extrinsics, _intrinsics);
    addSensor(sen_ptr);
    return sen_ptr;
}

SensorBasePtr Problem::installSensor(const std::string& _sen_type, //
                                     const std::string& _unique_sensor_name, //
                                     const Eigen::VectorXs& _extrinsics, //
                                     const std::string& _intrinsics_filename)
{
    if (_intrinsics_filename != "")
    {
        IntrinsicsBasePtr intr_ptr = IntrinsicsFactory::get().create(_sen_type, _intrinsics_filename);
        return installSensor(_sen_type, _unique_sensor_name, _extrinsics, intr_ptr);
    }
    else
        return installSensor(_sen_type, _unique_sensor_name, _extrinsics, IntrinsicsBasePtr());

}

ProcessorBasePtr Problem::installProcessor(const std::string& _prc_type, //
                                           const std::string& _unique_processor_name, //
                                           SensorBasePtr _corresponding_sensor_ptr, //
                                           ProcessorParamsBasePtr _prc_params)
{
    if (_corresponding_sensor_ptr == nullptr)
    {
      WOLF_ERROR("Cannot install processor '", _unique_processor_name,
                 "' since the associated sensor does not exist !");
      return ProcessorBasePtr();
    }

    ProcessorBasePtr prc_ptr = ProcessorFactory::get().create(uppercase(_prc_type), _unique_processor_name, _prc_params, _corresponding_sensor_ptr);
    _corresponding_sensor_ptr->addProcessor(prc_ptr);

    // setting the origin in all processor motion if origin already setted
    if (prc_ptr->isMotion() && prior_is_set_)
        (std::static_pointer_cast<ProcessorMotion>(prc_ptr))->setOrigin(getLastKeyFramePtr());

    // setting the main processor motion
    if (prc_ptr->isMotion() && processor_motion_ptr_ == nullptr)
        processor_motion_ptr_ = std::static_pointer_cast<ProcessorMotion>(prc_ptr);

    return prc_ptr;
}

ProcessorBasePtr Problem::installProcessor(const std::string& _prc_type, //
                                           const std::string& _unique_processor_name, //
                                           const std::string& _corresponding_sensor_name, //
                                           const std::string& _params_filename)
{
    SensorBasePtr sen_ptr = getSensorPtr(_corresponding_sensor_name);
    if (sen_ptr == nullptr)
        throw std::runtime_error("Sensor not found. Cannot bind Processor.");
    if (_params_filename == "")
        return installProcessor(_prc_type, _unique_processor_name, sen_ptr, nullptr);
    else
    {
        ProcessorParamsBasePtr prc_params = ProcessorParamsFactory::get().create(_prc_type, _params_filename);
        return installProcessor(_prc_type, _unique_processor_name, sen_ptr, prc_params);
    }
}

wolf::SensorBasePtr Problem::getSensorPtr(const std::string& _sensor_name)
{
    auto sen_it = std::find_if(getHardwarePtr()->getSensorList().begin(),
                               getHardwarePtr()->getSensorList().end(),
                               [&](SensorBasePtr sb)
                               {
                                   return sb->getName() == _sensor_name;
                               }); // lambda function for the find_if

    if (sen_it == getHardwarePtr()->getSensorList().end())
        return nullptr;

    return (*sen_it);
}

ProcessorMotionPtr Problem::setProcessorMotion(const std::string& _processor_name)
{
    for (auto sen : getHardwarePtr()->getSensorList()) // loop all sensors
    {
        auto prc_it = std::find_if(sen->getProcessorList().begin(), // find processor by its name
                                   sen->getProcessorList().end(),
                                   [&](ProcessorBasePtr prc)
                                   {
                                       return prc->getName() == _processor_name;
                                   }); // lambda function for the find_if

        if (prc_it != sen->getProcessorList().end())  // found something!
        {
            if ((*prc_it)->isMotion()) // found, and it's motion!
            {
                std::cout << "Found processor '" << _processor_name << "', of type Motion, and set as the main motion processor." << std::endl;
                processor_motion_ptr_ = std::static_pointer_cast<ProcessorMotion>(*prc_it);
                return processor_motion_ptr_;
            }
            else // found, but it's not motion!
            {
                std::cout << "Found processor '" << _processor_name << "', but not of type Motion!" << std::endl;
                return nullptr;
            }
        }
    }
    // nothing found!
    std::cout << "Processor '" << _processor_name << "' not found!" << std::endl;
    return nullptr;
}

void Problem::setProcessorMotion(ProcessorMotionPtr _processor_motion_ptr)
{
    processor_motion_ptr_ = _processor_motion_ptr;
}

void Problem::clearProcessorMotion()
{
    processor_motion_ptr_.reset();
}


FrameBasePtr Problem::emplaceFrame(const std::string& _frame_structure, //
                                   FrameType _frame_key_type, //
                                   const Eigen::VectorXs& _frame_state, //
                                   const TimeStamp& _time_stamp)
{
    FrameBasePtr frm = FrameFactory::get().create(_frame_structure, _frame_key_type, _time_stamp, _frame_state);
    trajectory_ptr_->addFrame(frm);
    return frm;
}

FrameBasePtr Problem::emplaceFrame(const std::string& _frame_structure, //
                                   FrameType _frame_key_type, //
                                   const TimeStamp& _time_stamp)
{
    return emplaceFrame(_frame_structure, _frame_key_type, getState(_time_stamp), _time_stamp);
}

FrameBasePtr Problem::emplaceFrame(FrameType _frame_key_type, //
                                   const Eigen::VectorXs& _frame_state, //
                                   const TimeStamp& _time_stamp)
{
    return emplaceFrame(trajectory_ptr_->getFrameStructure(), _frame_key_type, _frame_state, _time_stamp);
}

FrameBasePtr Problem::emplaceFrame(FrameType _frame_key_type, //
                                   const TimeStamp& _time_stamp)
{
    return emplaceFrame(trajectory_ptr_->getFrameStructure(), _frame_key_type, _time_stamp);
}

Eigen::VectorXs Problem::getCurrentState()
{
    Eigen::VectorXs state(getFrameStructureSize());
    getCurrentState(state);
    return state;
}

void Problem::getCurrentState(Eigen::VectorXs& state)
{
    assert(state.size() == getFrameStructureSize() && "Problem::getCurrentState: bad state size");

    if (processor_motion_ptr_ != nullptr)
        processor_motion_ptr_->getCurrentState(state);
    else if (trajectory_ptr_->getLastKeyFramePtr() != nullptr)
        trajectory_ptr_->getLastKeyFramePtr()->getState(state);
    else
        state = zeroState();
}


void Problem::getCurrentStateAndStamp(Eigen::VectorXs& state, TimeStamp& ts)
{
    assert(state.size() == getFrameStructureSize() && "Problem::getCurrentState: bad state size");

    if (processor_motion_ptr_ != nullptr)
    {
        processor_motion_ptr_->getCurrentState(state);
        processor_motion_ptr_->getCurrentTimeStamp(ts);
    }
    else if (trajectory_ptr_->getLastKeyFramePtr() != nullptr)
    {
        trajectory_ptr_->getLastKeyFramePtr()->getTimeStamp(ts);
        trajectory_ptr_->getLastKeyFramePtr()->getState(state);
    }
    else
        state = zeroState();
}

void Problem::getState(const TimeStamp& _ts, Eigen::VectorXs& state)
{
    assert(state.size() == getFrameStructureSize() && "Problem::getStateAtTimeStamp: bad state size");

    if (processor_motion_ptr_ != nullptr)
    {
        processor_motion_ptr_->getState(_ts, state);
    }
    else
    {
        FrameBasePtr closest_frame = trajectory_ptr_->closestKeyFrameToTimeStamp(_ts);
        if (closest_frame != nullptr)
        {
            closest_frame->getState(state);
        }else{
            state = zeroState();
        }
    }
}

Eigen::VectorXs Problem::getState(const TimeStamp& _ts)
{
    Eigen::VectorXs state(getFrameStructureSize());
    getState(_ts, state);
    return state;
}

Size Problem::getFrameStructureSize() const
{
    return state_size_;
}

void Problem::getFrameStructureSize(Size& _x_size, Size& _cov_size) const
{
    _x_size = state_size_;
    _cov_size = state_cov_size_;
}

Eigen::VectorXs Problem::zeroState()
{
    Eigen::VectorXs state = Eigen::VectorXs::Zero(getFrameStructureSize());

    // Set the quaternion identity for 3D states. Set only the real part to 1:
    if (trajectory_ptr_->getFrameStructure() == "PO 3D" ||
        trajectory_ptr_->getFrameStructure() == "POV 3D")
        state(6) = 1.0;

    return state;
}

bool Problem::permitKeyFrame(ProcessorBasePtr _processor_ptr)
{
    return true;
}

void Problem::keyFrameCallback(FrameBasePtr _keyframe_ptr, ProcessorBasePtr _processor_ptr, const Scalar& _time_tolerance)
{
    //std::cout << "Problem::keyFrameCallback: processor " << _processor_ptr->getName() << std::endl;
    for (auto sensor : hardware_ptr_->getSensorList())
    	for (auto processor : sensor->getProcessorList())
    		if (processor && (processor != _processor_ptr) )
                processor->keyFrameCallback(_keyframe_ptr, _time_tolerance);
}

LandmarkBasePtr Problem::addLandmark(LandmarkBasePtr _lmk_ptr)
{
    getMapPtr()->addLandmark(_lmk_ptr);
    return _lmk_ptr;
}

void Problem::addLandmarkList(LandmarkBaseList& _lmk_list)
{
    getMapPtr()->addLandmarkList(_lmk_list);
}
StateBlockPtr Problem::addStateBlock(StateBlockPtr _state_ptr)
{
    //std::cout << "Problem::addStateBlockPtr " << _state_ptr.get() << std::endl;

    // add the state unit to the list
    state_block_list_.push_back(_state_ptr);
    // queue for solver manager
    state_block_notification_list_.push_back(StateBlockNotification({ADD,_state_ptr}));
    return _state_ptr;
}

void Problem::updateStateBlockPtr(StateBlockPtr _state_ptr)
{
    //std::cout << "Problem::updateStateBlockPtr " << _state_ptr.get() << std::endl;

    // queue for solver manager
    state_block_notification_list_.push_back(StateBlockNotification({UPDATE,_state_ptr}));
}

void Problem::removeStateBlockPtr(StateBlockPtr _state_ptr)
{
    //std::cout << "Problem::removeStateBlockPtr " << _state_ptr.get() << std::endl;

    // add the state unit to the list
    state_block_list_.remove(_state_ptr);

    // Check if the state addition is still as a notification
    auto state_notif_it = state_block_notification_list_.begin();
    for (; state_notif_it != state_block_notification_list_.end(); state_notif_it++)
        if (state_notif_it->notification_ == ADD && state_notif_it->state_block_ptr_ == _state_ptr)
            break;

    // Remove addition notification
    if (state_notif_it != state_block_notification_list_.end())
    	state_block_notification_list_.erase(state_notif_it);
    // Add remove notification
    else
    	state_block_notification_list_.push_back(StateBlockNotification({REMOVE, _state_ptr}));

}

ConstraintBasePtr Problem::addConstraintPtr(ConstraintBasePtr _constraint_ptr)
{
    //std::cout << "Problem::addConstraintPtr " << _constraint_ptr->id() << std::endl;
    // queue for solver manager
    constraint_notification_list_.push_back(ConstraintNotification({ADD, _constraint_ptr}));

    return _constraint_ptr;
}

void Problem::removeConstraintPtr(ConstraintBasePtr _constraint_ptr)
{
    //std::cout << "Problem::removeConstraintPtr " << _constraint_ptr->id() << std::endl;

    // Check if the constraint addition is still as a notification
    auto ctr_notif_it = constraint_notification_list_.begin();
    for (; ctr_notif_it != constraint_notification_list_.end(); ctr_notif_it++)
        if (ctr_notif_it->notification_ == ADD && ctr_notif_it->constraint_ptr_ == _constraint_ptr)
            break;

    // Remove addition notification
    if (ctr_notif_it != constraint_notification_list_.end())
        constraint_notification_list_.erase(ctr_notif_it); // CHECKED shared_ptr is not active after erase
    // Add remove notification
    else
        constraint_notification_list_.push_back(ConstraintNotification({REMOVE, _constraint_ptr}));
}

void Problem::clearCovariance()
{
    covariances_.clear();
}

void Problem::addCovarianceBlock(StateBlockPtr _state1, StateBlockPtr _state2, const Eigen::MatrixXs& _cov)
{
    assert(_state1->getSize() == (unsigned int ) _cov.rows() && "wrong covariance block size");
    assert(_state2->getSize() == (unsigned int ) _cov.cols() && "wrong covariance block size");

    covariances_[std::pair<StateBlockPtr, StateBlockPtr>(_state1, _state2)] = _cov;
}

void Problem::addCovarianceBlock(StateBlockPtr _state1, const Eigen::MatrixXs& _cov)
{
    assert(_state1->getSize() == (unsigned int ) _cov.rows() && "wrong covariance block size");
    assert(_state1->getSize() == (unsigned int ) _cov.cols() && "wrong covariance block size");

    covariances_[std::make_pair(_state1, _state1)] = _cov;
}

bool Problem::getCovarianceBlock(StateBlockPtr _state1, StateBlockPtr _state2, Eigen::MatrixXs& _cov, const int _row,
                                 const int _col)
{
    //std::cout << "entire cov to be filled:" << std::endl << _cov << std::endl;
    //std::cout << "_row " << _row << std::endl;
    //std::cout << "_col " << _col << std::endl;
    //std::cout << "_state1 size: " << _state1->getSize() << std::endl;
    //std::cout << "_state2 size: " << _state2->getSize() << std::endl;
    //std::cout << "part of cov to be filled:" << std::endl <<  _cov.block(_row, _col, _state1->getSize(), _state2->getSize()) << std::endl;
    //if (covariances_.find(std::pair<StateBlockPtr, StateBlockPtr>(_state1, _state2)) != covariances_.end())
    //    std::cout << "stored cov" << std::endl << covariances_[std::pair<StateBlockPtr, StateBlockPtr>(_state1, _state2)] << std::endl;
    //else if (covariances_.find(std::pair<StateBlockPtr, StateBlockPtr>(_state2, _state1)) != covariances_.end())
    //    std::cout << "stored cov" << std::endl << covariances_[std::pair<StateBlockPtr, StateBlockPtr>(_state2, _state1)].transpose() << std::endl;

    assert(_row + _state1->getSize() <= _cov.rows() && _col + _state2->getSize() <= _cov.cols() && "Problem::getCovarianceBlock: Bad matrix covariance size!");

    if (covariances_.find(std::pair<StateBlockPtr, StateBlockPtr>(_state1, _state2)) != covariances_.end())
        _cov.block(_row, _col, _state1->getSize(), _state2->getSize()) =
                covariances_[std::pair<StateBlockPtr, StateBlockPtr>(_state1, _state2)];
    else if (covariances_.find(std::pair<StateBlockPtr, StateBlockPtr>(_state2, _state1)) != covariances_.end())
       _cov.block(_row, _col, _state1->getSize(), _state2->getSize()) =
                covariances_[std::pair<StateBlockPtr, StateBlockPtr>(_state2, _state1)].transpose();
    else
    {
      WOLF_DEBUG("Could not find the requested covariance block.");
      return false;
    }

    return true;
}

bool Problem::getCovarianceBlock(std::map<StateBlockPtr, unsigned int> _sb_2_idx, Eigen::MatrixXs& _cov)
{
    // fill covariance
    for (auto it1 = _sb_2_idx.begin(); it1 != _sb_2_idx.end(); it1++)
        for (auto it2 = it1; it2 != _sb_2_idx.end(); it2++)
        {
            StateBlockPtr sb1 = it1->first;
            StateBlockPtr sb2 = it2->first;
            std::pair<StateBlockPtr, StateBlockPtr> pair_12(sb1, sb2);
            std::pair<StateBlockPtr, StateBlockPtr> pair_21(sb2, sb1);

            // search st1 & st2
            if (covariances_.find(pair_12) != covariances_.end())
            {
                assert(_sb_2_idx[sb1] + sb1->getSize() <= _cov.rows() &&
                       _sb_2_idx[sb2] + sb2->getSize() <= _cov.cols() && "Problem::getCovarianceBlock: Bad matrix covariance size!");
                assert(_sb_2_idx[sb2] + sb2->getSize() <= _cov.rows() &&
                       _sb_2_idx[sb1] + sb1->getSize() <= _cov.cols() && "Problem::getCovarianceBlock: Bad matrix covariance size!");

                _cov.block(_sb_2_idx[sb1], _sb_2_idx[sb2], sb1->getSize(), sb2->getSize()) = covariances_[pair_12];
                _cov.block(_sb_2_idx[sb2], _sb_2_idx[sb1], sb2->getSize(), sb1->getSize()) = covariances_[pair_12].transpose();
            }
            else if (covariances_.find(pair_21) != covariances_.end())
            {
                assert(_sb_2_idx[sb1] + sb1->getSize() <= _cov.rows() &&
                       _sb_2_idx[sb2] + sb2->getSize() <= _cov.cols() && "Problem::getCovarianceBlock: Bad matrix covariance size!");
                assert(_sb_2_idx[sb2] + sb2->getSize() <= _cov.rows() &&
                       _sb_2_idx[sb1] + sb1->getSize() <= _cov.cols() && "Problem::getCovarianceBlock: Bad matrix covariance size!");

                _cov.block(_sb_2_idx[sb1], _sb_2_idx[sb2], sb1->getSize(), sb2->getSize()) = covariances_[pair_21].transpose();
                _cov.block(_sb_2_idx[sb2], _sb_2_idx[sb1], sb2->getSize(), sb1->getSize()) = covariances_[pair_21];
            }
            else
                return false;
        }

    return true;
}

bool Problem::getCovarianceBlock(StateBlockPtr _state, Eigen::MatrixXs& _cov, const int _row_and_col)
{
    return getCovarianceBlock(_state, _state, _cov, _row_and_col, _row_and_col);
}

bool Problem::getFrameCovariance(FrameBaseConstPtr _frame_ptr, Eigen::MatrixXs& _covariance)
{
    bool success(true);
    int i = 0, j = 0;

    const auto& state_bloc_vec = _frame_ptr->getStateBlockVec();

    for (const auto& sb_i : state_bloc_vec)
    {
        if (sb_i)
        {
            j = 0;
            for (const auto& sb_j : state_bloc_vec)
            {
                if (sb_j)
                {
                    success = success && getCovarianceBlock(sb_i, sb_j, _covariance, i, j);
                    j += sb_j->getSize();
                }
            }
            i += sb_i->getSize();
        }
    }
    return success;
}

Eigen::MatrixXs Problem::getFrameCovariance(FrameBaseConstPtr _frame_ptr)
{
    Size sz = 0;
    for (const auto& sb : _frame_ptr->getStateBlockVec())
        if (sb)
            sz += sb->getSize();

    Eigen::MatrixXs covariance(sz, sz);

    getFrameCovariance(_frame_ptr, covariance);
    return covariance;
}

Eigen::MatrixXs Problem::getLastKeyFrameCovariance()
{
    FrameBasePtr frm = getLastKeyFramePtr();
    return getFrameCovariance(frm);
}

bool Problem::getLandmarkCovariance(LandmarkBaseConstPtr _landmark_ptr, Eigen::MatrixXs& _covariance)
{
    bool success(true);
    int i = 0, j = 0;

    const auto& state_bloc_vec = _landmark_ptr->getStateBlockVec();

    for (const auto& sb_i : state_bloc_vec)
    {
        if (sb_i)
        {
            j = 0;
            for (const auto& sb_j : state_bloc_vec)
            {
                if (sb_j)
                {
                    success = success && getCovarianceBlock(sb_i, sb_j, _covariance, i, j);
                    j += sb_j->getSize();
                }
            }
            i += sb_i->getSize();
        }
    }
    return success;
}

Eigen::MatrixXs Problem::getLandmarkCovariance(LandmarkBaseConstPtr _landmark_ptr)
{
    Size sz = 0;
    for (const auto& sb : _landmark_ptr->getStateBlockVec())
        if (sb)
            sz += sb->getSize();

    Eigen::MatrixXs covariance(sz, sz);

    getLandmarkCovariance(_landmark_ptr, covariance);
    return covariance;
}

MapBasePtr Problem::getMapPtr()
{
    return map_ptr_;
}

TrajectoryBasePtr Problem::getTrajectoryPtr()
{
    return trajectory_ptr_;
}

HardwareBasePtr Problem::getHardwarePtr()
{
    return hardware_ptr_;
}

FrameBasePtr Problem::getLastFramePtr()
{
    return trajectory_ptr_->getLastFramePtr();
}

FrameBasePtr Problem::getLastKeyFramePtr()
{
    return trajectory_ptr_->getLastKeyFramePtr();
}

StateBlockList& Problem::getStateBlockList()
{
    return state_block_list_;
}


FrameBasePtr Problem::setPrior(const Eigen::VectorXs& _prior_state, const Eigen::MatrixXs& _prior_cov, const TimeStamp& _ts, const Scalar _time_tolerance)
{
    if ( ! prior_is_set_ )
    {
        // Create origin frame
        FrameBasePtr origin_keyframe = emplaceFrame(KEY_FRAME, _prior_state, _ts);

        // create origin capture with the given state as data
        // Capture fix only takes 3D position and Quaternion orientation
        CapturePosePtr init_capture;
        if (trajectory_ptr_->getFrameStructure() == "POV 3D")
            init_capture = std::make_shared<CapturePose>(_ts, nullptr, _prior_state.head(7), _prior_cov.topLeftCorner(6,6));
        else
            init_capture = std::make_shared<CapturePose>(_ts, nullptr, _prior_state, _prior_cov);

        origin_keyframe->addCapture(init_capture);

        // emplace feature and constraint
        init_capture->emplaceFeatureAndConstraint();

        // Notify all processors about the prior KF
        for (auto sensor : hardware_ptr_->getSensorList())
            for (auto processor : sensor->getProcessorList())
                if (processor->isMotion())
                    // Motion processors will set its origin at the KF
                    (std::static_pointer_cast<ProcessorMotion>(processor))->setOrigin(origin_keyframe);
                else
                    // Other processors will join the KF or not depending on their received data's time stamp and tolerances
                    processor->keyFrameCallback(origin_keyframe, _time_tolerance);


        prior_is_set_ = true;

//        keyFrameCallback(origin_keyframe, nullptr, _time_tolerance);

        // Notify all other processors about the origin KF --> they will join it or not depending on their received data
//        for (auto sensor : hardware_ptr_->getSensorList())
//            for (auto processor : sensor->getProcessorList())
//                if ( !processor->isMotion() )
//                    processor->keyFrameCallback(origin_keyframe, _time_tolerance);


        return origin_keyframe;
    }
    else
        throw std::runtime_error("Origin already set!");
}

void Problem::loadMap(const std::string& _filename_dot_yaml)
{
    getMapPtr()->load(_filename_dot_yaml);
}

void Problem::saveMap(const std::string& _filename_dot_yaml, const std::string& _map_name)
{
    getMapPtr()->save(_filename_dot_yaml, _map_name);
}

void Problem::print(int depth, bool constr_by, bool metric, bool state_blocks)
{
    using std::cout;
    using std::endl;

    cout << endl;
    cout << "P: wolf tree status ---------------------" << endl;
    cout << "Hardware" << ((depth < 1) ? ("   -- " + std::to_string(getHardwarePtr()->getSensorList().size()) + "S") : "")  << endl;
    if (depth >= 1)
    {
        // Sensors
        for (auto S : getHardwarePtr()->getSensorList())
        {
            cout << "  S" << S->id() << " " << S->getType();
            if (!metric && !state_blocks) cout << (S->isExtrinsicDynamic() ? " [Dyn," : " [Sta,") << (S->isIntrinsicDynamic() ? "Dyn]" : "Sta]");
            if (depth < 2)
                cout << " -- " << S->getProcessorList().size() << "p";
            cout << endl;
            if (metric && state_blocks)
            {
                for (auto i = 0; i < S->getStateBlockVec().size(); i++)
                {
                    if (i==0) cout << "    Extr " << (S->isExtrinsicDynamic() ? "[Dyn]" : "[Sta]") << " = [";
                    if (i==2) cout << "    Intr " << (S->isIntrinsicDynamic() ? "[Dyn]" : "[Sta]") << " = [";
                    auto sb = S->getStateBlockPtrAuto(i);
                    if (sb)
                    {
                        cout << (sb->isFixed() ? " Fix( " : " Est( ") << sb->getState().transpose() << " )";
                    }
                    if (i==1) cout << " ]" << endl;
                }
                if (S->getStateBlockVec().size() > 2) cout << " ]" << endl;
            }
            else if (metric)
            {
                cout << "    Extr " << (S->isExtrinsicDynamic() ? "[Dyn]" : "[Sta]") << "= ( ";
                if (S->getPPtr())
                    cout << S->getPPtr()->getState().transpose();
                if (S->getOPtr())
                    cout << " " << S->getOPtr()->getState().transpose();
                cout  << " )";
                if (S->getIntrinsicPtr())
                    cout << "    Intr " << (S->isIntrinsicDynamic() ? "[Dyn]" : "[Sta]") << "= ( " << S->getIntrinsicPtr()->getState().transpose() << " )";
                cout << endl;
            }
            else if (state_blocks)
            {
                cout << "    sb:" << (S->isExtrinsicDynamic() ? "[Dyn," : "[Sta,") << (S->isIntrinsicDynamic() ? "Dyn]" : "Sta]");
                for (auto sb : S->getStateBlockVec())
                    if (sb != nullptr)
                        cout << " " << (sb->isFixed() ? "Fix" : "Est");
                cout << endl;
            }
            if (depth >= 2)
            {
                // Processors
                for (auto p : S->getProcessorList())
                {
                    if (p->isMotion())
                    {
                        std::cout << "    pm" << p->id() << " " << p->getType() << endl;
                        ProcessorMotionPtr pm = std::static_pointer_cast<ProcessorMotion>(p);
                        if (pm->getOriginPtr())
                            cout << "      o: C" << pm->getOriginPtr()->id() << " - " << (pm->getOriginPtr()->getFramePtr()->isKey() ? "  KF" : "  F")
                            << pm->getOriginPtr()->getFramePtr()->id() << endl;
                        if (pm->getLastPtr())
                            cout << "      l: C" << pm->getLastPtr()->id() << " - " << (pm->getLastPtr()->getFramePtr()->isKey() ? "  KF" : "  F")
                            << pm->getLastPtr()->getFramePtr()->id() << endl;
                        if (pm->getIncomingPtr())
                            cout << "      i: C" << pm->getIncomingPtr()->id() << endl;
                    }
                    else
                    {
                        cout << "    pt" << p->id() << " " << p->getType() << endl;
                        ProcessorTrackerPtr pt = std::dynamic_pointer_cast<ProcessorTracker>(p);
                        if (pt)
                        {
                            if (pt->getOriginPtr())
                                cout << "      o: C" << pt->getOriginPtr()->id() << " - " << (pt->getOriginPtr()->getFramePtr()->isKey() ? "  KF" : "  F")
                                << pt->getOriginPtr()->getFramePtr()->id() << endl;
                            if (pt->getLastPtr())
                                cout << "      l: C" << pt->getLastPtr()->id() << " - " << (pt->getLastPtr()->getFramePtr()->isKey() ? "  KF" : "  F")
                                << pt->getLastPtr()->getFramePtr()->id() << endl;
                            if (pt->getIncomingPtr())
                                cout << "      i: C" << pt->getIncomingPtr()->id() << endl;
                        }
                    }
                } // for p
            }
        } // for S
    }
    cout << "Trajectory" << ((depth < 1) ? (" -- " + std::to_string(getTrajectoryPtr()->getFrameList().size()) + "F") : "")  << endl;
    if (depth >= 1)
    {
        // Frames
        for (auto F : getTrajectoryPtr()->getFrameList())
        {
            cout << (F->isKey() ? "  KF" : "  F") << F->id() << ((depth < 2) ? " -- " + std::to_string(F->getCaptureList().size()) + "C  " : "");
            if (constr_by)
            {
                cout << "  <-- ";
                for (auto cby : F->getConstrainedByList())
                    cout << "c" << cby->id() << " \t";
            }
            cout << endl;
            if (metric)
            {
                cout << (F->isFixed() ? "    Fix" : "    Est") << ", ts=" << std::setprecision(5)
                        << F->getTimeStamp().get();
                cout << ",\t x = ( " << std::setprecision(2) << F->getState().transpose() << " )";
                cout << endl;
            }
            if (state_blocks)
            {
                cout << "    sb:";
                for (auto sb : F->getStateBlockVec())
                    if (sb != nullptr)
                        cout << " " << (sb->isFixed() ? "Fix" : "Est");
                cout << endl;
            }
            if (depth >= 2)
            {
                // Captures
                for (auto C : F->getCaptureList())
                {
                    cout << "    C" << (C->isMotion() ? "M" : "") << C->id() << " " << C->getType();
                    
                    if(C->getSensorPtr() != nullptr)
                    {
                        cout << " -> S" << C->getSensorPtr()->id();
                        cout << (C->getSensorPtr()->isExtrinsicDynamic() ? " [Dyn, ": " [Sta, ");
                        cout << (C->getSensorPtr()->isIntrinsicDynamic() ? "Dyn]" : "Sta]");
                    }
                    else
                        cout << " -> S-";

                    cout << ((depth < 3) ? " -- " + std::to_string(C->getFeatureList().size()) + "f" : "");
                    if (constr_by)
                    {
                        cout << "  <-- ";
                        for (auto cby : C->getConstrainedByList())
                            cout << "c" << cby->id() << " \t";
                    }
                    cout << endl;

                    if (state_blocks)
                        for(auto sb : C->getStateBlockVec())
                            if(sb != nullptr)
                            {
                                cout << "      sb: ";
                                cout << (sb->isFixed() ? "Fix" : "Est");
                                if (metric)
                                    cout << std::setprecision(3) << " (" << sb->getState().transpose() << " )";
                                cout << endl;
                            }

                    if (C->isMotion() && metric)
                    {
                        try
                        {
                            CaptureMotionPtr CM = std::static_pointer_cast<CaptureMotion>(C);
                            cout << "      buffer size  :  " << CM->getBuffer().get().size() << endl;
                            if ( CM->getCalibSize() > 0 && ! CM->getBuffer().get().empty())
                            {
                                cout << "      delta preint : (" << CM->getDeltaPreint().transpose() << ")" << endl;
                                cout << "      calib preint : (" << CM->getCalibrationPreint().transpose() << ")" << endl;
                                cout << "      jacob preint : (" << CM->getJacobianCalib().row(0) << ")" << endl;
                                cout << "      calib current: (" << CM->getCalibration().transpose() << ")" << endl;
                                cout << "      delta correct: (" << CM->getDeltaCorrected(CM->getCalibration()).transpose() << ")" << endl;
                            }
                        }
                        catch  (std::runtime_error& e)
                        {
                        }
                    }

                    if (depth >= 3)
                    {
                        // Features
                        for (auto f : C->getFeatureList())
                        {
                            cout << "      f" << f->id() << " " << f->getType() << ((depth < 4) ? " -- " + std::to_string(f->getConstraintList().size()) + "c  " : "");
                            if (constr_by)
                            {
                                cout << "  <--\t";
                                for (auto cby : f->getConstrainedByList())
                                    cout << "c" << cby->id() << " \t";
                            }
                            cout << endl;
                            if (metric)
                                cout << "        m = ( " << std::setprecision(3) << f->getMeasurement().transpose()
                                        << " )" << endl;
                            if (depth >= 4)
                            {
                                // Constraints
                                for (auto c : f->getConstraintList())
                                {
                                    cout << "        c" << c->id() << " " << c->getType() << " -->";
                                    if (c->getFrameOtherPtr() == nullptr && c->getCaptureOtherPtr() == nullptr && c->getFeatureOtherPtr() == nullptr && c->getLandmarkOtherPtr() == nullptr)
                                        cout << " A";
                                    if (c->getFrameOtherPtr() != nullptr)
                                        cout << " F" << c->getFrameOtherPtr()->id();
                                    if (c->getCaptureOtherPtr() != nullptr)
                                        cout << " C" << c->getCaptureOtherPtr()->id();
                                    if (c->getFeatureOtherPtr() != nullptr)
                                        cout << " f" << c->getFeatureOtherPtr()->id();
                                    if (c->getLandmarkOtherPtr() != nullptr)
                                        cout << " L" << c->getLandmarkOtherPtr()->id();
                                    cout << endl;
                                } // for c
                            }
                        } // for f
                    }
                } // for C
            }
        } // for F
    }
    cout << "Map" << ((depth < 1) ? ("        -- " + std::to_string(getMapPtr()->getLandmarkList().size()) + "L") : "") << endl;
    if (depth >= 1)
    {
        // Landmarks
        for (auto L : getMapPtr()->getLandmarkList())
        {
            cout << "  L" << L->id() << " " << L->getType();
            if (constr_by)
            {
                cout << "\t<-- ";
                for (auto cby : L->getConstrainedByList())
                    cout << "c" << cby->id() << " \t";
            }
            cout << endl;
            if (metric)
            {
                cout << (L->isFixed() ? "    Fix" : "    Est");
                cout << ",\t x = ( " << std::setprecision(2) << L->getState().transpose() << " )";
                cout << endl;
            }
            if (state_blocks)
            {
                cout << "    sb:";
                for (auto sb : L->getStateBlockVec())
                    if (sb != nullptr)
                        cout << (sb->isFixed() ? " Fix" : " Est");
                cout << endl;
            }
        } // for L
    }
    cout << "-----------------------------------------" << endl;
    cout << endl;
}

FrameBasePtr wolf::Problem::closestKeyFrameToTimeStamp(const TimeStamp& _ts)
{
    return trajectory_ptr_->closestKeyFrameToTimeStamp(_ts);
}

bool Problem::check(int verbose_level)
{
    using std::cout;
    using std::endl;

    bool is_consistent = true; // true if all checks passed; false if any check fails.

    if (verbose_level) cout << endl;
    if (verbose_level) cout << "Wolf tree integrity ---------------------" << endl;
    auto P_raw = this;
    if (verbose_level > 0)
    {
        cout << "P @ " << P_raw << endl;
    }
    // ------------------------
    //     HARDWARE branch
    // ------------------------
    auto H = hardware_ptr_;
    if (verbose_level > 0)
    {
        cout << "H @ " << H.get() << endl;
    }
    // check pointer to Problem
    is_consistent = is_consistent && (H->getProblem().get() == P_raw);
    for (auto S : H->getSensorList())
    {
        if (verbose_level > 0)
        {
            cout << "  S" << S->id() << " @ " << S.get() << endl;
            cout << "    -> P @ " << S->getProblem().get() << endl;
            cout << "    -> H @ " << S->getHardwarePtr().get() << endl;
            for (auto sb : S->getStateBlockVec())
            {
                cout <<  "    sb @ " << sb.get();
                if (sb)
                {
                    auto lp = sb->getLocalParametrizationPtr();
                    if (lp)
                        cout <<  " (lp @ " << lp.get() << ")";
                }
                cout << endl;
            }
        }
        // check problem and hardware pointers
        is_consistent = is_consistent && (S->getProblem().get() == P_raw);
        is_consistent = is_consistent && (S->getHardwarePtr() == H);
        for (auto p : S->getProcessorList())
        {
            if (verbose_level > 0)
            {
                cout << "    p" << p->id() << " @ " << p.get() << " -> S" << p->getSensorPtr()->id() << endl;
                cout << "      -> P  @ " << p->getProblem().get() << endl;
                cout << "      -> S" << p->getSensorPtr()->id() << " @ " << p->getSensorPtr().get() << endl;
            }
            // check problem and sensor pointers
            is_consistent = is_consistent && (p->getProblem().get() == P_raw);
            is_consistent = is_consistent && (p->getSensorPtr() == S);
        }
    }
    // ------------------------
    //    TRAJECTORY branch
    // ------------------------
    auto T = trajectory_ptr_;
    if (verbose_level > 0)
    {
        cout << "T @ " << T.get() << endl;
    }
    // check pointer to Problem
    is_consistent = is_consistent && (T->getProblem().get() == P_raw);
    for (auto F : T->getFrameList())
    {
        if (verbose_level > 0)
        {
            cout << (F->isKey() ? "  KF" : "  F") << F->id() << " @ " << F.get() << endl;
            cout << "    -> P @ " << F->getProblem().get() << endl;
            cout << "    -> T @ " << F->getTrajectoryPtr().get() << endl;
            for (auto sb : F->getStateBlockVec())
            {
                cout <<  "    sb @ " << sb.get();
                if (sb)
                {
                    auto lp = sb->getLocalParametrizationPtr();
                    if (lp)
                        cout <<  " (lp @ " << lp.get() << ")";
                }
                cout << endl;
            }
        }
        // check problem and trajectory pointers
        is_consistent = is_consistent && (F->getProblem().get() == P_raw);
        is_consistent = is_consistent && (F->getTrajectoryPtr() == T);
        for (auto cby : F->getConstrainedByList())
        {
            if (verbose_level > 0)
            {
                cout << "    <- c" << cby->id() << " -> F" << cby->getFrameOtherPtr()->id() << endl;
            }
            // check constrained_by pointer to this frame
            is_consistent = is_consistent && (cby->getFrameOtherPtr() == F);
            for (auto sb : cby->getStateBlockPtrVector())
            {
                if (verbose_level > 0)
                {
                    cout << "      sb @ " << sb.get();
                    if (sb)
                    {
                        auto lp = sb->getLocalParametrizationPtr();
                        if (lp)
                            cout <<  " (lp @ " << lp.get() << ")";
                    }
                    cout << endl;
                }
            }
        }
        for (auto C : F->getCaptureList())
        {
            if (verbose_level > 0)
            {
                cout << "    C" << C->id() << " @ " << C.get() << " -> S";
                if (C->getSensorPtr()) cout << C->getSensorPtr()->id();
                else cout << "-";
                cout << endl;
                cout << "      -> P  @ " << C->getProblem().get() << endl;
                cout << "      -> F" << C->getFramePtr()->id() << " @ " << C->getFramePtr().get() << endl;
                for (auto sb : C->getStateBlockVec())
                {
                    cout <<  "      sb @ " << sb.get();
                    if (sb)
                    {
                        auto lp = sb->getLocalParametrizationPtr();
                        if (lp)
                            cout <<  " (lp @ " << lp.get() << ")";
                    }
                    cout << endl;
                }
            }
            // check problem and frame pointers
            is_consistent = is_consistent && (C->getProblem().get() == P_raw);
            is_consistent = is_consistent && (C->getFramePtr() == F);
            for (auto f : C->getFeatureList())
            {
                if (verbose_level > 0)
                {
                    cout << "      f" << f->id() << " @ " << f.get() << endl;
                    cout << "        -> P  @ " << f->getProblem().get() << endl;
                    cout << "        -> C" << f->getCapturePtr()->id() << " @ " << f->getCapturePtr().get()
                            << endl;
                }
                // check problem and capture pointers
                is_consistent = is_consistent && (f->getProblem().get() == P_raw);
                is_consistent = is_consistent && (f->getCapturePtr() == C);

                for (auto cby : f->getConstrainedByList())
                {
                    if (verbose_level > 0)
                    {
                        cout << "     <- c" << cby->id() << " -> f" << cby->getFeatureOtherPtr()->id() << endl;
                    }
                    // check constrained_by pointer to this feature
                    is_consistent = is_consistent && (cby->getFeatureOtherPtr() == f);
                }
                for (auto c : f->getConstraintList())
                {
                    if (verbose_level > 0)
                        cout << "        c" << c->id() << " @ " << c.get();

                    auto Fo = c->getFrameOtherPtr();
                    auto Co = c->getCaptureOtherPtr();
                    auto fo = c->getFeatureOtherPtr();
                    auto Lo = c->getLandmarkOtherPtr();

                    if ( !Fo && !Co && !fo && !Lo )    // case ABSOLUTE:
                    {
                        if (verbose_level > 0)
                            cout << " --> Abs." << endl;
                    }

                    // find constrained_by pointer in constrained frame
                    if ( Fo )  // case FRAME:
                    {
                        if (verbose_level > 0)
                            cout << " --> F" << Fo->id() << " <- ";
                        bool found = false;
                        for (auto cby : Fo->getConstrainedByList())
                        {
                            if (verbose_level > 0)
                                cout << " c" << cby->id();
                            found = found || (c == cby);
                        }
                        if (verbose_level > 0)
                            cout << endl;
                        // check constrained_by pointer in constrained frame
                        is_consistent = is_consistent && found;
                    }

                    // find constrained_by pointer in constrained capture
                    if ( Co )  // case CAPTURE:
                    {
                        if (verbose_level > 0)
                            cout << " --> C" << Co->id() << " <- ";
                        bool found = false;
                        for (auto cby : Co->getConstrainedByList())
                        {
                            if (verbose_level > 0)
                                cout << " c" << cby->id();
                            found = found || (c == cby);
                        }
                        if (verbose_level > 0)
                            cout << endl;
                        // check constrained_by pointer in constrained frame
                        is_consistent = is_consistent && found;
                    }

                    // find constrained_by pointer in constrained feature
                    if ( fo )   // case FEATURE:
                    {
                        if (verbose_level > 0)
                            cout << " --> f" << fo->id() << " <- ";
                        bool found = false;
                        for (auto cby : fo->getConstrainedByList())
                        {
                            if (verbose_level > 0)
                                cout << " c" << cby->id();
                            found = found || (c == cby);
                        }
                        if (verbose_level > 0)
                            cout << endl;
                        // check constrained_by pointer in constrained feature
                        is_consistent = is_consistent && found;
                    }

                    // find constrained_by pointer in constrained landmark
                    if ( Lo )      // case LANDMARK:
                    {
                        if (verbose_level > 0)
                            cout << " --> L" << Lo->id() << " <- ";
                        bool found = false;
                        for (auto cby : Lo->getConstrainedByList())
                        {
                            if (verbose_level > 0)
                                cout << " c" << cby->id();
                            found = found || (c == cby);
                        }
                        if (verbose_level > 0)
                            cout << endl;
                        // check constrained_by pointer in constrained landmark
                        is_consistent = is_consistent && found;
                    }
                    if (verbose_level > 0)
                    {
                        cout << "          -> P  @ " << c->getProblem().get() << endl;
                        cout << "          -> f" << c->getFeaturePtr()->id() << " @ " << c->getFeaturePtr().get() << endl;
                    }
                    // check problem and feature pointers
                    is_consistent = is_consistent && (c->getProblem().get() == P_raw);
                    is_consistent = is_consistent && (c->getFeaturePtr() == f);

                    // find state block pointers in all constrained nodes
                    SensorBasePtr S = c->getFeaturePtr()->getCapturePtr()->getSensorPtr(); // get own sensor to check sb
                    for (auto sb : c->getStateBlockPtrVector())
                    {
                        bool found = false;
                        if (verbose_level > 0)
                        {
                            cout <<  "          sb @ " << sb.get();
                            if (sb)
                            {
                                auto lp = sb->getLocalParametrizationPtr();
                                if (lp)
                                    cout <<  " (lp @ " << lp.get() << ")";
                            }
                        }
                        // find in own Frame
                        found = found || (std::find(F->getStateBlockVec().begin(), F->getStateBlockVec().end(), sb) != F->getStateBlockVec().end());
                        // find in own Capture
                        found = found || (std::find(C->getStateBlockVec().begin(), C->getStateBlockVec().end(), sb) != C->getStateBlockVec().end());
                        // find in own Sensor
                        if (S)
                            found = found || (std::find(S->getStateBlockVec().begin(), S->getStateBlockVec().end(), sb) != S->getStateBlockVec().end());
                        // find in constrained Frame
                        if (Fo)
                            found = found || (std::find(Fo->getStateBlockVec().begin(), Fo->getStateBlockVec().end(), sb) != Fo->getStateBlockVec().end());
                        // find in constrained Capture
                        if (Co)
                            found = found || (std::find(Co->getStateBlockVec().begin(), Co->getStateBlockVec().end(), sb) != Co->getStateBlockVec().end());
                        // find in constrained Feature
                        if (fo)
                        {
                            // find in constrained feature's Frame
                            FrameBasePtr foF = fo->getFramePtr();
                            found = found || (std::find(foF->getStateBlockVec().begin(), foF->getStateBlockVec().end(), sb) != foF->getStateBlockVec().end());
                            // find in constrained feature's Capture
                            CaptureBasePtr foC = fo->getCapturePtr();
                            found = found || (std::find(foC->getStateBlockVec().begin(), foC->getStateBlockVec().end(), sb) != foC->getStateBlockVec().end());
                            // find in constrained feature's Sensor
                            SensorBasePtr foS = fo->getCapturePtr()->getSensorPtr();
                            found = found || (std::find(foS->getStateBlockVec().begin(), foS->getStateBlockVec().end(), sb) != foS->getStateBlockVec().end());
                        }
                        // find in constrained landmark
                        if (Lo)
                            found = found || (std::find(Lo->getStateBlockVec().begin(), Lo->getStateBlockVec().end(), sb) != Lo->getStateBlockVec().end());
                        if (verbose_level > 0)
                        {
                            if (found)
                                cout << " found";
                            else
                                cout << " NOT FOUND !";
                            cout << endl;
                        }
                        // check that all state block pointers were found
                        is_consistent = is_consistent && found;
                    }
                }
            }
        }
    }
    // ------------------------
    //       MAP branch
    // ------------------------
    auto M = map_ptr_;
    if (verbose_level > 0)
        cout << "M @ " << M.get() << endl;
    // check pointer to Problem
    is_consistent = is_consistent && (M->getProblem().get() == P_raw);
    for (auto L : M->getLandmarkList())
    {
        if (verbose_level > 0)
        {
            cout << "  L" << L->id() << " @ " << L.get() << endl;
            cout << "  -> P @ " << L->getProblem().get() << endl;
            cout << "  -> M @ " << L->getMapPtr().get() << endl;
            for (auto sb : L->getStateBlockVec())
            {
                cout <<  "  sb @ " << sb.get();
                if (sb)
                {
                    auto lp = sb->getLocalParametrizationPtr();
                    if (lp)
                        cout <<  " (lp @ " << lp.get() << ")";
                }
                cout << endl;
            }
        }
        // check problem and map pointers
        is_consistent = is_consistent && (L->getProblem().get() == P_raw);
        is_consistent = is_consistent && (L->getMapPtr() == M);
        for (auto cby : L->getConstrainedByList())
        {
            if (verbose_level > 0)
                cout << "      <- c" << cby->id() << " -> L" << cby->getLandmarkOtherPtr()->id() << endl;
            // check constrained_by pointer to this landmark
            is_consistent = is_consistent && (cby->getLandmarkOtherPtr() && L->id() == cby->getLandmarkOtherPtr()->id());
            for (auto sb : cby->getStateBlockPtrVector())
            {
                if (verbose_level > 0)
                {
                    cout << "      sb @ " << sb.get();
                    if (sb)
                    {
                        auto lp = sb->getLocalParametrizationPtr();
                        if (lp)
                            cout <<  " (lp @ " << lp.get() << ")";
                    }
                    cout << endl;
                }
            }
        }
    }

    if (verbose_level) cout << "--------------------------- Wolf tree " << (is_consistent ? " OK" : "Not OK !!") << endl;
    if (verbose_level) cout << endl;

    return is_consistent;
}

void Problem::print(const std::string& depth, bool constr_by, bool metric, bool state_blocks)
{
    if (depth.compare("T") == 0)
        print(0, constr_by, metric, state_blocks);
    else if (depth.compare("F") == 0)
        print(1, constr_by, metric, state_blocks);
    else if (depth.compare("C") == 0)
        print(2, constr_by, metric, state_blocks);
    else if (depth.compare("f") == 0)
        print(3, constr_by, metric, state_blocks);
    else if (depth.compare("c") == 0)
        print(4, constr_by, metric, state_blocks);
    else
        print(0, constr_by, metric, state_blocks);
}

} // namespace wolf