/*
 * Copyright 2011, Nicolas Mansard, LAAS-CNRS
 *
 * This file is part of sot-dyninv.
 * sot-dyninv is free software: you can redistribute it and/or
 * modify it under the terms of the GNU Lesser General Public License
 * as published by the Free Software Foundation, either version 3 of
 * the License, or (at your option) any later version.
 * sot-dyninv is distributed in the hope that it will be
 * useful, but WITHOUT ANY WARRANTY; without even the implied warranty
 * of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU Lesser General Public License for more details.  You should
 * have received a copy of the GNU Lesser General Public License along
 * with sot-dyninv.  If not, see <http://www.gnu.org/licenses/>.
 */

//#define VP_DEBUG
#define VP_DEBUG_MODE 50
#include <sot/core/debug.hh>
#ifdef VP_DEBUG
class solver_op_space__INIT
{
public:solver_op_space__INIT( void ) { dynamicgraph::sot::DebugTrace::openFile("/tmp/dynh.txt"); }
};
solver_op_space__INIT solver_op_space_initiator;
#endif //#ifdef VP_DEBUG


#include <sot-dyninv/solver-op-space.h>
#include <sot-dyninv/commands-helper.h>
#include <dynamic-graph/factory.h>
#include <boost/foreach.hpp>
#include <sot-dyninv/commands-helper.h>
#include <dynamic-graph/pool.h>
#include <soth/HCOD.hpp>
#include <sot-dyninv/task-dyn-pd.h>
#include <sot/core/feature-point6d.hh>
#include <iostream>
#include <sstream>
#include <soth/Algebra.hpp>
#include <Eigen/QR>


namespace dynamicgraph
{
  namespace sot
  {
    namespace dyninv
    {

      namespace dg = ::dynamicgraph;
      using namespace dg;
      using dg::SignalBase;

      /* --- DG FACTORY ------------------------------------------------------- */
      DYNAMICGRAPH_FACTORY_ENTITY_PLUGIN(SolverOpSpace,"SolverOpSpace");

      /* --- CONSTRUCTION ----------------------------------------------------- */
      /* --- CONSTRUCTION ----------------------------------------------------- */
      /* --- CONSTRUCTION ----------------------------------------------------- */
      SolverOpSpace::
      SolverOpSpace( const std::string & name )
	: Entity(name)
	,stack_t()

	,CONSTRUCT_SIGNAL_IN(matrixInertia,dg::Matrix)
	,CONSTRUCT_SIGNAL_IN(velocity,dg::Vector)
	,CONSTRUCT_SIGNAL_IN(dyndrift,dg::Vector)
	,CONSTRUCT_SIGNAL_IN(damping,double)
	,CONSTRUCT_SIGNAL_IN(breakFactor,double)
	,CONSTRUCT_SIGNAL_IN(posture,dg::Vector)
	,CONSTRUCT_SIGNAL_IN(position,dg::Vector)

	,CONSTRUCT_SIGNAL_OUT(control,dg::Vector,
			      matrixInertiaSIN << dyndriftSIN
			      << velocitySIN )
	,CONSTRUCT_SIGNAL(zmp,OUT,dg::Vector)
	,CONSTRUCT_SIGNAL(acceleration,OUT,dg::Vector)

	,nbParam(0), nq(0),ntau(0),nfs(0)
	,hsolver()

	,Cdyn(),Ccontact(),Czmp(),Czero()
	,bdyn(),bcontact(),bzmp(),bzero()
	,Ctasks(),btasks()
	,solution()
      {
	signalRegistration( matrixInertiaSIN << dyndriftSIN
			    << velocitySIN << controlSOUT
			    << zmpSOUT << accelerationSOUT
			    << dampingSIN << breakFactorSIN
			    << postureSIN << positionSIN );

	/* Command registration. */
	boost::function<void(SolverOpSpace*,const std::string&)> f_addContact
	  =
	  boost::bind( &SolverOpSpace::addContact,_1,_2,
		       (dynamicgraph::Signal<dg::Matrix, int>*)NULL,
		       (dynamicgraph::Signal<dg::Matrix, int>*)NULL,
		       (dynamicgraph::Signal<dg::Vector, int>*)NULL,
		       (dynamicgraph::Signal<dg::Matrix, int>*)NULL);
	addCommand("add.Contact",
		   makeCommandVoid1(*this,f_addContact,
				    docCommandVoid1("create the contact signals, unpluged.",
						    "string")));
	addCommand("addContactFromTask",
		   makeCommandVoid2(*this,&SolverOpSpace::addContactFromTask,
				    docCommandVoid2("Add a contact from the named task. Remmeber to plug __p.",
						    "string(task name)","string (contact name)")));
	addCommand("rmContact",
		   makeCommandVoid1(*this,&SolverOpSpace::removeContact,
				    docCommandVoid1("remove the contact named in arguments.",
						    "string")));
	addCommand("dispContacts",
		   makeCommandVerbose(*this,&SolverOpSpace::dispContacts,
				      docCommandVerbose("Guess what?")));
	addCommand("debugOnce",
		   makeCommandVoid0(*this,&SolverOpSpace::debugOnce,
				    docCommandVoid0("open trace-file for next iteration of the solver.")));

	ADD_COMMANDS_FOR_THE_STACK;
      }

      /* --- STACK ----------------------------------------------------------- */
      /* --- STACK ----------------------------------------------------------- */
      /* --- STACK ----------------------------------------------------------- */

      SolverOpSpace::TaskDependancyList_t SolverOpSpace::
      getTaskDependancyList( const TaskDynPD& task )
      {
	TaskDependancyList_t res;
	res.push_back( &task.taskSOUT );
	res.push_back( &task.jacobianSOUT );
	res.push_back( &task.JdotSOUT );
	return res;
      }
      void SolverOpSpace::
      addDependancy( const TaskDependancyList_t& depList )
      {
	BOOST_FOREACH( const SignalBase<int>* sig, depList )
	  { controlSOUT.addDependency( *sig ); }
      }
      void  SolverOpSpace::
      removeDependancy( const TaskDependancyList_t& depList )
      {
	BOOST_FOREACH( const SignalBase<int>* sig, depList )
	  { controlSOUT.removeDependency( *sig ); }
      }
      void SolverOpSpace::
      resetReady( void )
      {
	controlSOUT.setReady();
      }

      /* --- CONTACT LIST ---------------------------------------------------- */
      /* --- CONTACT LIST ---------------------------------------------------- */
      /* --- CONTACT LIST ---------------------------------------------------- */

      /* TODO: push this method directly in signal. */
      static std::string signalShortName( const std::string & longName )
      {
	std::istringstream iss( longName );
	const int SIZE = 128;
	char buffer[SIZE];
	while( iss.good() )
	  { iss.getline(buffer,SIZE,':'); }
	return std::string( buffer );
      }

      void SolverOpSpace::
      addContactFromTask( const std::string & taskName,const std::string & contactName )
      {
	using namespace dynamicgraph::sot;

	TaskDynPD & task = dynamic_cast<TaskDynPD&> ( g_pool().getEntity( taskName ) );
	assert( task.getFeatureList().size() == 1 );
	BOOST_FOREACH( FeatureAbstract* fptr, task.getFeatureList() )
	  {
	    FeaturePoint6d* f6 = dynamic_cast< FeaturePoint6d* >( fptr );
	    assert( NULL!=f6 );
	    f6->positionSIN.recompute(controlSOUT.getTime());
	    f6->servoCurrentPosition();
	    f6->FeatureAbstract::selectionSIN = true;
	  }
	addContact( contactName, &task.jacobianSOUT, &task.JdotSOUT,&task.taskVectorSOUT, NULL );
      }

      void SolverOpSpace::
      addContact( const std::string & name,
		  Signal<dg::Matrix,int> * jacobianSignal,
		  Signal<dg::Matrix,int> * JdotSignal,
		  Signal<dg::Vector,int> * corrSignal,
		  Signal<dg::Matrix,int> * contactPointsSignal )
      {
	if( contactMap.find(name) != contactMap.end())
	  {
	    std::cerr << "!! Contact " << name << " already exists." << std::endl;
	    return;
	  }

	contactMap[name].jacobianSIN
	  = matrixSINPtr( new SignalPtr<dg::Matrix,int>
			  ( jacobianSignal,
			    "sotDynInvWB("+getName()+")::input(matrix)::_"+name+"_J" ) );
	signalRegistration( *contactMap[name].jacobianSIN );

	contactMap[name].JdotSIN
	  = matrixSINPtr( new SignalPtr<dg::Matrix,int>
			  ( JdotSignal,
			    "sotDynInvWB("+getName()+")::input(matrix)::_"+name+"_Jdot" ) );
	signalRegistration( *contactMap[name].JdotSIN );

	contactMap[name].supportSIN
	  = matrixSINPtr( new SignalPtr<dg::Matrix,int>
			  ( contactPointsSignal,
			    "sotDynInvWB("+getName()+")::input(matrix)::_"+name+"_p" ) );
	signalRegistration( *contactMap[name].supportSIN );

	contactMap[name].correctorSIN
	  = vectorSINPtr( new SignalPtr<dg::Vector,int>
			  ( corrSignal,
			    "sotDynInvWB("+getName()+")::input(vector)::_"+name+"_x" ) );
	signalRegistration( *contactMap[name].correctorSIN );

	contactMap[name].forceSOUT
	  = vectorSOUTPtr( new Signal<dg::Vector,int>
			   ( "sotDynInvWB("+getName()+")::output(vector)::_"+name+"_f" ) );
	signalRegistration( *contactMap[name].forceSOUT );

	contactMap[name].fnSOUT
	  = vectorSOUTPtr( new Signal<dg::Vector,int>
			   ( "sotDynInvWB("+getName()+")::output(vector)::_"+name+"_fn" ) );
	signalRegistration( *contactMap[name].fnSOUT );

      }

      void SolverOpSpace::
      removeContact( const std::string & name )
      {
	if( contactMap.find(name) == contactMap.end() )
	  {
	    std::cerr << "!! Contact " << name << " does not exist." << std::endl;
	    return;
	  }

	signalDeregistration( signalShortName(contactMap[name].jacobianSIN->getName()) );
	signalDeregistration( signalShortName(contactMap[name].supportSIN->getName()) );
	signalDeregistration( signalShortName(contactMap[name].forceSOUT->getName()) );
	signalDeregistration( signalShortName(contactMap[name].fnSOUT->getName()) );
	signalDeregistration( signalShortName(contactMap[name].JdotSIN->getName()) );
	signalDeregistration( signalShortName(contactMap[name].correctorSIN->getName()) );
	contactMap.erase(name);
      }

      void SolverOpSpace::
      dispContacts( std::ostream& os ) const
      {
	os << "+-----------------\n+   Contacts\n+-----------------" << std::endl;
	// TODO BOOST FOREACH
	for( contacts_t::const_iterator iter=contactMap.begin();
	     iter!=contactMap.end(); ++iter )
	  {
	    os << "| " << iter->first <<std::endl;
	  }
      }

      /* --------------------------------------------------------------------- */
      /* --- STATIC INTERNAL ------------------------------------------------- */
      /* --------------------------------------------------------------------- */
      namespace sotOPH
      {
	template< typename D1,typename D2 >
	void preCross( const Eigen::MatrixBase<D1> & M,Eigen::MatrixBase<D2> & Tx )
	{
	  EIGEN_STATIC_ASSERT_VECTOR_ONLY(Eigen::MatrixBase<D1>);
	  assert( Tx.cols()==3 && Tx.rows()==3 && M.size()==3 );
	  Tx( 0,0 ) = 0   ;  Tx( 0,1 )=-M[2];  Tx( 0,2 ) = M[1];
	  Tx( 1,0 ) = M[2];  Tx( 1,1 )= 0   ;  Tx( 1,2 ) =-M[0];
	  Tx( 2,0 ) =-M[1];  Tx( 2,1 )= M[0];  Tx( 2,2 ) = 0   ;
	}

	template< typename D1, typename D2  >
	void computeForceNormalConversion( Eigen::MatrixBase<D1> & Ci,
					   const Eigen::MatrixBase<D2> & positions )
	{
	  /* General Constraint is: phi^0 = Psi.fi, with Psi = [ I; skew(OP1);
	     skew(OP2); skew(OP3); skew(OP4) ].  But phi^0 = X_c^0*phi^c (both feet
	     are 0.105cm above the ground so X_c^0 is the transformation matri from
	     actual ankle force to the actual contact force).  * X_c^0*phi^c - Psi*fi
	     = 0 Since phi_{x,y,Rz}^0 ~ fi_{x,y} and phi_{z,Rx,Ry} ~ fi_{z,Rx,Ry}: *
	     Reduced Constraint Ci is applied as:[ X_c^0*phi^c - Psi*fi ]_{z,Rx,Ry} =
	     0 [ C_phi -C_fi ]_{z,Rx,Ry}*[phi^c; fi_{z,Rx,Ry}] = 0, so Ci = [ C_phi
	     -C_fi ]_{z,Rx,Ry} with C_phi = X_c^0 and C_fi = Psi.
	  */

	  using namespace Eigen;

	  const int nbPoint = (int) positions.cols();
	  assert( positions.rows()==3 );
	  assert( Ci.rows()==3 && Ci.cols()==6+nbPoint );

	  //Ci.leftCols(6) = -MatrixXd::Identity(6,6);
	  /* Ci = [ X_c^0_{z,Rx,Ry} -Psi_{z,Rx,Ry}];
	   *   with X_c^0_{z,Rx,Ry} = [ 0 0 1 0 0 0; 0 -z 0 1 0 0; z 0 0 0 1 0 ]
	   *   and Psi_{z,Rx,Ry} = [ 1 1 1 1; y_1 y_2 y_3 y_4; -x_1 -x_2 -x_3 -x_4 ]. */
	  //const double z = positions(2,0);
	  /* position(3) is the position of the ground wrt the ankle. We need the opposite. */
	  const double z = -positions(2,0); // DEBUG TRIAL
	  Ci.setZero();
	  Ci(0,2)=1;
	  Ci(1,1)=-z; Ci(1,3)=1;
	  Ci(2,0)=+z; Ci(2,4)=1;

	  typename D1::ColsBlockXpr Phi = Ci.rightCols( nbPoint );
	  for( int i=0;i<nbPoint;++i )
	    {
	      const double x = positions(0,i);
	      const double y = positions(1,i);
	      Phi.col(i) << -1,-y,+x;
	    }
	  sotDEBUG(5) << "Psi = " << (soth::MATLAB) Phi << std::endl;
	}
      }


      /* --- INIT SOLVER ------------------------------------------------------ */
      /* --- INIT SOLVER ------------------------------------------------------ */
      /* --- INIT SOLVER ------------------------------------------------------ */

      /** Force the update of all the task in-signals, in order to fix their
       * size for resizing the solver.
       */
      void SolverOpSpace::
      refreshTaskTime( int time )
      {
	// TODO BOOST_FOREACH
	for( StackIterator_t iter=stack.begin();stack.end()!=iter;++iter )
	  {
	    TaskDynPD& task = **iter;
	    task.taskSOUT( time );
	  }
      }

      /** Knowing the sizes of all the stages (except the task ones),
       * the function resizes the matrix and vector of all stages (except...).
       */
      void SolverOpSpace::
      initialResizeSolver( void )
      {
	const int nbContactCst = 3*nbContactBodies+nbContactPoints;

	Cdyn.resize( nbDofs+6,nbParam );              bdyn.resize( nbDofs+6 );
	Ccontact.resize( 6*nbContactBodies,nbParam ); bcontact.resize( 6*nbContactBodies );
	Czmp.resize( nbContactCst,nbParam );          bzmp.resize( nbContactCst );
	Czero.resize( nbDofs,nbParam );               bzero.resize( nbDofs );
      }

      void SolverOpSpace::
      resizeSolver( void )
      {
	sotDEBUGIN(15);

	assert( nbDofs>0 );
	nq = nbDofs+6; ntau=nbDofs;
	nbContactBodies = contactMap.size();
	nbContactPoints = 0;
	int range = 0;
	BOOST_FOREACH(contacts_t::value_type& pContact, contactMap)
	  {
	    Contact & contact = pContact.second;
	    const int nbi = contact.supportSIN->accessCopy().cols();
	    nbContactPoints += nbi;
	    int sizeVar = 6+nbi;
	    contact.range = std::make_pair( range,range+sizeVar );
	    range+=sizeVar;
	  }
	nfs=6*nbContactBodies+nbContactPoints;
	nbParam = nq+ntau+nfs;

	const int nbDynConstraint = 3;
	/* constraint [B]efore and [A]fter the tasks. */
	const int nbCstB = nbDynConstraint, nbCstA = 1;
	const int nbCst = nbCstB+stack.size()+nbCstA;

	bool toBeResized =
	  (hsolver==NULL
	   || (int)hsolver->nbStages()!=nbCst
	   || (int)hsolver->sizeProblem!=nbParam
	   // || (int)hsolver->stage(1).nbConstraints()!=nbContactBodies*6
	   // || (int)hsolver->stage(2).nbConstraints()!=3*nbContactBodies+nbContactPoints
	   );
	if(! toBeResized )
	  for( int i=0;i<(int)stack.size();++i )
	    if( stack[i]->taskSOUT.accessCopy().size()
		!=hsolver->stage(nbCstB+i).nbConstraints() )
	      { toBeResized = true; break; }

	if( toBeResized )
	  {
	    std::cout << "Resize all..." << std::endl;
	    sotDEBUG(1) << "Resize all." << std::endl;
	    hsolver = hcod_ptr_t(new soth::HCOD(nbParam,nbCst));
	    initialResizeSolver();

	    hsolver->pushBackStage( Cdyn,    bdyn );
	    hsolver->stages.back()->name = "dyn";
	    hsolver->pushBackStage( Ccontact,bcontact );
	    hsolver->stages.back()->name = "contact";
	    hsolver->pushBackStage( Czmp,    bzmp );
	    hsolver->stages.back()->name = "zmp";

	    Ctasks.clear(); Ctasks.resize( stack.size() );
	    btasks.clear(); btasks.resize( stack.size() );

	    for( int i=0;i<(int)stack.size();++i )
	      {
		TaskDynPD & task = *stack[i];
		const int nx = task.taskSOUT.accessCopy().size();
		Ctasks[i].resize(nx,nbParam);
		btasks[i].resize(nx);

		hsolver->pushBackStage( Ctasks[i],btasks[i] );
		hsolver->stages.back()->name = task.getName();
	      }

	    hsolver->pushBackStage( Czero, bzero );
	    hsolver->stages.back()->name = "zero";

	    solution.resize( nbDofs );
	  }

	sotDEBUGOUT(15);
      }


      /* --- SIGNALS ---------------------------------------------------------- */
      /* --- SIGNALS ---------------------------------------------------------- */
      /* --- SIGNALS ---------------------------------------------------------- */

      dg::Vector& SolverOpSpace::
      controlSOUT_function( dg::Vector &control, int t )
      {
	sotDEBUG(15) << " # In time = " << t << std::endl;

	refreshTaskTime( t );
	resizeSolver();

	// if( t==1112 ) { hsolver->debugOnce(); }

	const Eigen::VectorXd b = dyndriftSIN(t);
	const Eigen::MatrixXd A = matrixInertiaSIN(t);
	const Eigen::VectorXd dq = velocitySIN(t);

	using namespace sotOPH;
	using namespace soth;

	if( dampingSIN ) //damp?
	  {
	    sotDEBUG(5) << "Using damping. " << std::endl;
	    hsolver->setDamping( 0 );
	    hsolver->useDamp( true );
	    hsolver->stages.back()->damping( dampingSIN(t) );
	  }
	else
	  {
	    sotDEBUG(5) << "Without damping. " << std::endl;
	    hsolver->useDamp( false );
	  }
	sotDEBUG(1) << "A = " << (MATLAB)A << std::endl;
	sotDEBUG(1) << "b = " << (MATLAB)b << std::endl;
	sotDEBUG(1) << "dq = " << (MATLAB)dq << std::endl;

	/* SOT:
	 * -1- A ddq + b + J'f = S' tau
	 * -2- J ddq = 0
	 * -3- Xp f  > eps
	 * -i- Ji ddq = ddxi - Jidot dq
	 *
	 * -1- [ A -S' J' ] [ ddq; tau; f ] = -b
	 * -2- [ J  0  0  ] [ ddq; tau; f ] =  0
	 * -3- [ 0  0  Xp ] [ ddq; tau; f ] > EPS
	 * -3- [ Ji 0  0  ] [ ddq; tau; f ] = ddxi - Jidot qdot
	 */


#define COLS_Q leftCols( nq )
#define COLS_TAU leftCols( nq+ntau ).rightCols( ntau )
#define COLS_F rightCols( nfs )
#define ROWS_FF topRows( 6 )
#define ROWS_ACT bottomRows( nbDofs )

#define COLS(__ri,__rs) leftCols(__rs).rightCols((__rs)-(__ri))
#define ROWS(__ri,__rs) topRows(__rs).bottomRows((__rs)-(__ri))

	/* -1- */
	/* Cdyn = [ A 0 [0(6x30);-I(30x30)] J1.transpose 0 J2.transpose 0 ] */
	assert( Cdyn.rows() == A.rows() && bdyn.size() == A.rows() );
	Cdyn.COLS_Q = A;
	Cdyn.COLS_TAU.ROWS_FF.setZero();
	Cdyn.COLS_TAU.ROWS_ACT = -MatrixXd::Identity(nbDofs,nbDofs);
	BOOST_FOREACH(contacts_t::value_type& pContact, contactMap)
	  {
	    Contact & contact = pContact.second;
	    const Eigen::MatrixXd Jc = (*contact.jacobianSIN)(t);
	    const int ri = contact.range.first,rs = contact.range.second;
	    Cdyn.COLS_F.COLS(ri,ri+6) = Jc.transpose();
	    Cdyn.COLS_F.COLS(ri+6,rs).setZero();
	  }

	for( int i=0;i<nbDofs+6;++i ) bdyn[i] = -b[i];
	sotDEBUG(15) << "Cdyn = "     << (MATLAB)Cdyn << std::endl;
	sotDEBUG(1) << "bdyn = "     << bdyn << std::endl;

	/* -2- */
	/* Ccontact = [ Jc1 0 0 0 0 0 ; Jc2 0 0 0 0 0 ]  */
	{
	  assert( Ccontact.rows() == nbContactBodies*6
		  && bcontact.size() == nbContactBodies*6 );
	  Ccontact.COLS_TAU.setZero();
	  Ccontact.COLS_F.setZero();
	  int nci = 0;
	  BOOST_FOREACH(contacts_t::value_type& pContact, contactMap)
	    {
	      Contact& contact = pContact.second;  const int n6 = nci*6;
	      const Eigen::MatrixXd Jc = (*contact.jacobianSIN)(t);
	      Ccontact.COLS_Q.ROWS(n6,n6+6) = Jc;

	      VectorXd reference = VectorXd::Zero(6);
	      if( (*contact.JdotSIN) )
		{
		  sotDEBUG(5) << "Accounting for Jcontact_dot. " << std::endl;
		  const Eigen::MatrixXd Jcdot = (*contact.JdotSIN)(t);
		  reference -= Jcdot*dq;
		}
	      if( (*contact.correctorSIN) )
		{
		  sotDEBUG(5) << "Accounting for contact_xddot. " << std::endl;
		  const Eigen::VectorXd xdd = (*contact.correctorSIN)(t);
		  reference += xdd;
		}
	      for( int r=0;r<6;++r ) bcontact[n6+r] = reference[r];
	      nci++;
	    }
	  sotDEBUG(15) << "Ccontact = " << (MATLAB)Ccontact << std::endl;
	  sotDEBUG(1) << "bcontact = " << bcontact << std::endl;
	}

	/* -3- */
	/* Czmp = [ 0 0 -X_c^0_{z,Rx,Ry} Psi_{z,Rx,Ry} 0  0; 0 0 0 Iz 0 0 ] */
	{
	  Czmp.setZero();
	  int rows=0;
	  BOOST_FOREACH(const contacts_t::value_type& pContact, contactMap)
	    {
	      const Contact & contact = pContact.second;
	      const Eigen::MatrixXd support = (*contact.supportSIN)(t);
	      const int nbP = support.cols();
	      const int ri = contact.range.first, rs=contact.range.second;

	      assert( nq+ntau+rs<=Czmp.cols() && rows+3+nbP<=Czmp.rows() );
	      assert( bzmp.size() == Czmp.rows() );

	      MatrixXd::ColsBlockXpr::ColsBlockXpr::ColsBlockXpr
		::RowsBlockXpr::RowsBlockXpr    Czi
		= Czmp.COLS_F.COLS(ri,rs). ROWS(rows,rows+3);
	      computeForceNormalConversion(Czi,support);
	      //for( int i=0;i<3;++i ) bzmp. ROWS(rows,rows+3)[i] = 0;
	      bzmp. ROWS(rows,rows+3).fill( 0 );

	      Czmp.COLS_F.COLS(ri,ri+6).ROWS(rows+3,rows+3+nbP).setZero();
	      Czmp.COLS_F.COLS(ri+6,rs).ROWS(rows+3,rows+3+nbP).setIdentity();
	      bzmp.ROWS(rows+3,rows+3+nbP).fill( soth::Bound(0,soth::Bound::BOUND_SUP) );
	      // for( int p=0;p<nbP;++p )
	      // 	{
	      // 	  Czmp.COLS_F.COLS(ri+6,rs).ROWS(rows+3,rows+3+nbP)
	      // 	    (p,p) = 1;
	      // 	  bzmp.ROWS(rows+3,rows+3+nbP)
	      // 	    [p] = soth::Bound(0,soth::Bound::BOUND_SUP);
	      // 	}
	      rows += 3+nbP;
	    }
	  sotDEBUG(15) << "Czmp = "     << (MATLAB)Czmp << std::endl;
	  sotDEBUG(15) << "Czmp = "     << Czmp << std::endl;
	  sotDEBUG(1) << "bzmp = "     << bzmp << std::endl;
	}

	/* -Tasks 1:n- */
	/* Ctaski = [ Ji 0 0 0 0 0 ] */
	for( int i=0;i<(int)stack.size();++i )
	  {
	    TaskDynPD & task = * stack[i];
	    MatrixXd & Ctask1 = Ctasks[i];
	    VectorBound & btask1 = btasks[i];

	    const Eigen::MatrixXd Jdot = task.JdotSOUT(t);
	    const Eigen::MatrixXd J = task.jacobianSOUT(t);
	    const dg::sot::VectorMultiBound & ddx = task.taskSOUT(t);

	    const int nx1 = ddx.size();

	    sotDEBUG(5) << "ddx"<<i<<" = " << ddx << std::endl;
	    sotDEBUG(25) << "J"<<i<<" = " << J << std::endl;
	    sotDEBUG(45) << "Jdot"<<i<<" = " << Jdot << std::endl;

	    assert( Ctask1.rows() == nx1 && btask1.size() == nx1 );
	    assert( J.rows()==nx1 && J.cols()==nq && (int)ddx.size()==nx1 );
	    assert( Jdot.rows()==nx1 && Jdot.cols()==nq );
	    Ctask1.COLS_Q = J;
	    Ctask1.COLS_TAU.setZero();
	    Ctask1.COLS_F.setZero();

	    VectorXd ddxdrift = - (Jdot*dq);
	    for( int c=0;c<nx1;++c )
	      {
		if( ddx[c].getMode() == dg::sot::MultiBound::MODE_SINGLE )
		  btask1[c] = ddx[c].getSingleBound() + ddxdrift[c];
		else
		  {
		    const bool binf = ddx[c].getDoubleBoundSetup( dg::sot::MultiBound::BOUND_INF );
		    const bool bsup = ddx[c].getDoubleBoundSetup( dg::sot::MultiBound::BOUND_SUP );
		    if( binf&&bsup )
		      {
			const double xi = ddx[c].getDoubleBound(dg::sot::MultiBound::BOUND_INF);
			const double xs = ddx[c].getDoubleBound(dg::sot::MultiBound::BOUND_SUP);
			btask1[c] = std::make_pair( xi+ddxdrift[c], xs+ddxdrift[c] );
		      }
		    else if( binf )
		      {
			const double xi = ddx[c].getDoubleBound(dg::sot::MultiBound::BOUND_INF);
			btask1[c] = Bound( xi+ddxdrift[c], Bound::BOUND_INF );
		      }
		    else
		      {
			assert( bsup );
			const double xs = ddx[c].getDoubleBound(dg::sot::MultiBound::BOUND_SUP);
			btask1[c] = Bound( xs+ddxdrift[c], Bound::BOUND_SUP );
		      } //else
		  } //else
	      } //for c

	    sotDEBUG(15) << "Ctask"<<i<<" = "     << (MATLAB)Ctask1 << std::endl;
	    sotDEBUG(1) << "btask"<<i<<" = "     << btask1 << std::endl;
	  } //for i

	/* -Last stage- */
	/* Czero = [ [0(30x6) I(30x30)] 0 0 0 0 0 ] */
	Czero.COLS_Q.leftCols(6).setZero();
	Czero.COLS_Q.rightCols(nbDofs).setIdentity();
	Czero.COLS_TAU.setZero();
	Czero.COLS_F.setZero();
	VectorXd ref;
	const double Kv = breakFactorSIN(t);
	if( postureSIN && positionSIN )
	  {
	    const Eigen::VectorXd qref = postureSIN(t);
	    const Eigen::VectorXd q = positionSIN(t);
	    const double Kp = .25*Kv*Kv;
	    ref = (-Kp*(q-qref)-Kv*dq).tail(nbDofs);
	  }
	else
	  {	    ref = (-Kv*dq).tail(nbDofs);	  }
	for( int i=0;i<nbDofs;++i )
	  bzero[i] = ref[i];

	sotDEBUG(15) << "Czero = "     << (MATLAB)Czero << std::endl;
	sotDEBUG(1) << "bzero = "     << bzero << std::endl;

	/* --- */
	sotDEBUG(1) << "Initial config." << std::endl;
	hsolver->reset();
	hsolver->setInitialActiveSet();

	sotDEBUG(1) << "Run for a solution." << std::endl;
	hsolver->activeSearch(solution);
	sotDEBUG(1) << "solution = " << (MATLAB)solution << std::endl;
	sotDEBUG(1) << "solution = " << solution << std::endl;

	control.resize(nbDofs );
	sotDEBUG(1) << "controlb = " << control << std::endl;
	control = solution.transpose().COLS_TAU;
	sotDEBUG(1) << "stct = " << (MATLAB)solution.transpose().COLS_TAU << std::endl;
	sotDEBUG(1) << "controla = " << control << std::endl;

	/* --- forces signal --- */
	BOOST_FOREACH(contacts_t::value_type& pContact, contactMap)
	  {
	    Contact& contact = pContact.second;
	    const int nbP = (*contact.supportSIN)(t).cols();
	    const int ri = contact.range.first;
	    /* range is an object of the struct Contact containing 2 integers:
	       first: the position of the 1st contact in the parameters vector
	       second: the position of the 2nd contact in the parameters vector */
	    dg::Vector mlf6;
	    mlf6.resize(6);
	    dg::Vector mlfn;
	    mlfn.resize(nbP);
	    //EIGEN_VECTOR_FROM_VECTOR(fn,mlfn,nbP);

	    mlf6 = solution.transpose().COLS_F.COLS(ri,ri+6);
	    (*contact.forceSOUT) = mlf6;
	    contact.forceSOUT->setTime(t);

	    for( int i=0;i<nbP;++i ) mlfn[i] = solution.transpose().COLS_F[ri+6+i];
	    (*contact.fnSOUT) = mlfn;
	    contact.fnSOUT->setTime(t);
	  }

	/* ACC signal */
	{
	  dg::Vector mlacc;
	  mlacc.resize(nbDofs+6);
	  //EIGEN_VECTOR_FROM_VECTOR( acc,mlacc,nbDofs+6 );
	  mlacc = solution.transpose().COLS_Q;
	  accelerationSOUT = mlacc;
	}

	/* --- verif --- */
	sotDEBUG(1) << "Vdyn = " << (MATLAB)(VectorXd)(Cdyn*solution) << std::endl;
	sotDEBUG(1) << "Vcontact = " << (MATLAB)(VectorXd)(Ccontact*solution) << std::endl;
	sotDEBUG(1) << "Vzmp = " << (MATLAB)(VectorXd)(Czmp*solution) << std::endl;
	for( int i=0;i<(int)stack.size();++i )
	  {
	    MatrixXd & Ctask1 = Ctasks[i];
	    VectorBound & btask1 = btasks[i];
	    sotDEBUG(1) << "Vtask"<<i<<" = " << (MATLAB)(VectorXd)(Ctask1*solution) << std::endl;
	    sotDEBUG(1) << "btask"<<i<<" = " << btask1 << std::endl;
	  }
	sotDEBUG(1) << "control = " << control << std::endl;
	return control;
      }


      /* --- COMMANDS ---------------------------------------------------------- */
      /* --- COMMANDS ---------------------------------------------------------- */
      /* --- COMMANDS ---------------------------------------------------------- */

      void SolverOpSpace::
      debugOnce( void )
      {
	dg::sot::DebugTrace::openFile("/tmp/sot.txt");
	hsolver->debugOnce();
      }

      /* --- ENTITY ----------------------------------------------------------- */
      /* --- ENTITY ----------------------------------------------------------- */
      /* --- ENTITY ----------------------------------------------------------- */

      void SolverOpSpace::
      display( std::ostream& os ) const
      {
	os << "SolverOpSpace "<<getName() << ": " << nbDofs <<" joints." << std::endl;
	try{
	  os <<"control = "<<controlSOUT.accessCopy() <<std::endl << std::endl;
	}  catch (dynamicgraph::ExceptionSignal e) {}
	stack_t::display(os);
	dispContacts(os);
      }
    } // namespace dyninv
  } // namespace sot
} // namespace dynamicgraph