From 3f12f4567a608b21e7a1c2feb4c8ee7d787165f1 Mon Sep 17 00:00:00 2001
From: Mansard <nmansard@laas.fr>
Date: Thu, 28 Jul 2011 14:19:36 +0200
Subject: [PATCH] IVIGIT.

---
 src/solver-dyn-reduced.cpp | 796 +++++++++++++++++++++++++++++++++++++
 src/solver-dyn-reduced.h   | 169 ++++++++
 2 files changed, 965 insertions(+)
 create mode 100644 src/solver-dyn-reduced.cpp
 create mode 100644 src/solver-dyn-reduced.h

diff --git a/src/solver-dyn-reduced.cpp b/src/solver-dyn-reduced.cpp
new file mode 100644
index 0000000..88c39bb
--- /dev/null
+++ b/src/solver-dyn-reduced.cpp
@@ -0,0 +1,796 @@
+/*
+ * 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/dynred.txt"); }
+};
+solver_op_space__INIT solver_op_space_initiator;
+#endif //#ifdef VP_DEBUG
+
+
+#include <sot-dyninv/solver-dyn-reduced.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 <sot-dyninv/mal-to-eigen.h>
+#include <soth/HCOD.hpp>
+#include <sot-dyninv/mal-to-eigen.h>
+#include <sot-dyninv/task-dyn-pd.h>
+#include <sot/core/feature-point6d.hh>
+#include <sstream>
+#include <soth/Algebra.hpp>
+#include <Eigen/QR>
+
+
+namespace dynamicgraph
+{
+  namespace sot
+  {
+    namespace dyninv
+    {
+#include <Eigen/Cholesky>
+
+      namespace dg = ::dynamicgraph;
+      using namespace dg;
+      using dg::SignalBase;
+
+      /* --- DG FACTORY ------------------------------------------------------- */
+      DYNAMICGRAPH_FACTORY_ENTITY_PLUGIN(SolverDynReduced,"SolverDynReduced");
+
+      /* --- CONSTRUCTION ----------------------------------------------------- */
+      /* --- CONSTRUCTION ----------------------------------------------------- */
+      /* --- CONSTRUCTION ----------------------------------------------------- */
+      SolverDynReduced::
+      SolverDynReduced( const std::string & name )
+	: Entity(name)
+	,stack_t()
+
+	,CONSTRUCT_SIGNAL_IN(matrixInertia,ml::Matrix)
+	,CONSTRUCT_SIGNAL_IN(inertiaSqroot,ml::Matrix)
+	,CONSTRUCT_SIGNAL_IN(inertiaSqrootInv,ml::Matrix)
+	,CONSTRUCT_SIGNAL_IN(velocity,ml::Vector)
+	,CONSTRUCT_SIGNAL_IN(dyndrift,ml::Vector)
+	,CONSTRUCT_SIGNAL_IN(damping,double)
+	,CONSTRUCT_SIGNAL_IN(breakFactor,double)
+	,CONSTRUCT_SIGNAL_IN(posture,ml::Vector)
+	,CONSTRUCT_SIGNAL_IN(position,ml::Vector)
+
+	,CONSTRUCT_SIGNAL_OUT(precompute,int,
+			      inertiaSqrootInvSIN << inertiaSqrootSIN )
+	,CONSTRUCT_SIGNAL_OUT(inertiaSqrootOut,ml::Matrix,
+			      matrixInertiaSIN)
+	,CONSTRUCT_SIGNAL_OUT(inertiaSqrootInvOut,ml::Matrix,
+			      inertiaSqrootSIN)
+	,CONSTRUCT_SIGNAL_OUT(sizeForce,int,
+			      precomputeSOUT )
+	,CONSTRUCT_SIGNAL_OUT(Jc,ml::Matrix, sotNOSIGNAL)
+	,CONSTRUCT_SIGNAL_OUT(freeMotionBase,ml::Matrix,
+			      JcSOUT << inertiaSqrootInvSIN)
+
+	,CONSTRUCT_SIGNAL_OUT(solution,ml::Vector,
+			      freeMotionBaseSOUT << inertiaSqrootInvSIN << inertiaSqrootSIN
+			      << dyndriftSIN << velocitySIN
+			      << dampingSIN << breakFactorSIN
+			      << postureSIN << positionSIN)
+	,CONSTRUCT_SIGNAL_OUT(reducedControl,ml::Vector,
+			      solutionSOUT)
+	,CONSTRUCT_SIGNAL_OUT(acceleration,ml::Vector,
+			      reducedControlSOUT << inertiaSqrootSIN << freeMotionBaseSOUT)
+	,CONSTRUCT_SIGNAL_OUT(forces,ml::Vector,
+			      solutionSOUT)
+	,CONSTRUCT_SIGNAL_OUT(torque,ml::Vector,
+			      JcSOUT << forcesSOUT << reducedControlSOUT << inertiaSqrootSIN )
+
+	,hsolver()
+
+	,Cforce(),Czero()
+	,bforce(),bzero()
+	,Ctasks(),btasks()
+	,solution()
+      {
+	signalRegistration( matrixInertiaSIN
+			    << inertiaSqrootSIN
+			    << inertiaSqrootInvSIN
+			    << velocitySIN
+			    << dyndriftSIN
+			    << dampingSIN
+			    << breakFactorSIN
+			    << postureSIN
+			    << positionSIN
+
+			    << inertiaSqrootOutSOUT
+			    << inertiaSqrootInvOutSOUT
+			    << JcSOUT
+			    << freeMotionBaseSOUT
+			    << solutionSOUT
+			    << reducedControlSOUT
+			    << accelerationSOUT
+			    << forcesSOUT
+			    << torqueSOUT
+			    );
+
+	inertiaSqrootInvSIN.plug( &inertiaSqrootInvOutSOUT );
+	inertiaSqrootSIN.plug( &inertiaSqrootOutSOUT );
+
+	/* Command registration. */
+	boost::function<void(SolverDynReduced*,const std::string&)> f_addContact
+	  =
+	  boost::bind( &SolverDynReduced::addContact,_1,_2,
+		       (dynamicgraph::Signal<ml::Matrix, int>*)NULL,
+		       (dynamicgraph::Signal<ml::Matrix, int>*)NULL,
+		       (dynamicgraph::Signal<ml::Vector, int>*)NULL,
+		       (dynamicgraph::Signal<ml::Matrix, int>*)NULL);
+	addCommand("addContact",
+		   makeCommandVoid1(*this,f_addContact,
+				    docCommandVoid1("create the contact signals, unpluged.",
+						    "string")));
+	addCommand("addContactFromTask",
+		   makeCommandVoid2(*this,&SolverDynReduced::addContactFromTask,
+				    docCommandVoid2("Add a contact from the named task. Remmeber to plug __p.",
+						    "string(task name)","string (contact name)")));
+	addCommand("rmContact",
+		   makeCommandVoid1(*this,&SolverDynReduced::removeContact,
+				    docCommandVoid1("remove the contact named in arguments.",
+						    "string")));
+	addCommand("dispContacts",
+		   makeCommandVerbose(*this,&SolverDynReduced::dispContacts,
+				      docCommandVerbose("Guess what?")));
+	addCommand("debugOnce",
+		   makeCommandVoid0(*this,&SolverDynReduced::debugOnce,
+				    docCommandVoid0("open trace-file for next iteration of the solver.")));
+
+	ADD_COMMANDS_FOR_THE_STACK;
+      }
+
+      /* --- COMMANDS ---------------------------------------------------------- */
+      /* --- COMMANDS ---------------------------------------------------------- */
+      /* --- COMMANDS ---------------------------------------------------------- */
+
+      void SolverDynReduced::
+      debugOnce( void )
+      {
+	dg::sot::DebugTrace::openFile("/tmp/sot.txt");
+	hsolver->debugOnce();
+      }
+
+      /* --- STACK ----------------------------------------------------------- */
+      /* --- STACK ----------------------------------------------------------- */
+      /* --- STACK ----------------------------------------------------------- */
+
+      SolverDynReduced::TaskDependancyList_t SolverDynReduced::
+      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 SolverDynReduced::
+      addDependancy( const TaskDependancyList_t& depList )
+      {
+	BOOST_FOREACH( const SignalBase<int>* sig, depList )
+	  { solutionSOUT.addDependency( *sig ); }
+      }
+      void  SolverDynReduced::
+      removeDependancy( const TaskDependancyList_t& depList )
+      {
+	BOOST_FOREACH( const SignalBase<int>* sig, depList )
+	  { solutionSOUT.removeDependency( *sig ); }
+      }
+      void SolverDynReduced::
+      resetReady( void )
+      {
+	solutionSOUT.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 SolverDynReduced::
+      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(solutionSOUT.getTime());
+	    f6->servoCurrentPosition();
+	    f6->FeatureAbstract::selectionSIN = true;
+	  }
+	addContact( contactName, &task.jacobianSOUT, &task.JdotSOUT,&task.taskVectorSOUT, NULL );
+      }
+
+      void SolverDynReduced::
+      addContact( const std::string & name,
+		  Signal<ml::Matrix,int> * jacobianSignal,
+		  Signal<ml::Matrix,int> * JdotSignal,
+		  Signal<ml::Vector,int> * corrSignal,
+		  Signal<ml::Matrix,int> * contactPointsSignal )
+      {
+	if( contactMap.find(name) != contactMap.end())
+	  {
+	    std::cerr << "!! Contact " << name << " already exists." << std::endl;
+	    return;
+	  }
+
+	contactMap[name].jacobianSIN
+	  = matrixSINPtr( new SignalPtr<ml::Matrix,int>
+			  ( jacobianSignal,
+			    "sotDynInvWB("+getName()+")::input(matrix)::_"+name+"_J" ) );
+	signalRegistration( *contactMap[name].jacobianSIN );
+	JcSOUT.addDependency( *contactMap[name].jacobianSIN );
+	precomputeSOUT.addDependency( *contactMap[name].jacobianSIN );
+	JcSOUT.setReady();
+	precomputeSOUT.setReady();
+
+	contactMap[name].JdotSIN
+	  = matrixSINPtr( new SignalPtr<ml::Matrix,int>
+			  ( JdotSignal,
+			    "sotDynInvWB("+getName()+")::input(matrix)::_"+name+"_Jdot" ) );
+	signalRegistration( *contactMap[name].JdotSIN );
+
+	contactMap[name].supportSIN
+	  = matrixSINPtr( new SignalPtr<ml::Matrix,int>
+			  ( contactPointsSignal,
+			    "sotDynInvWB("+getName()+")::input(matrix)::_"+name+"_p" ) );
+	signalRegistration( *contactMap[name].supportSIN );
+
+	contactMap[name].correctorSIN
+	  = vectorSINPtr( new SignalPtr<ml::Vector,int>
+			  ( corrSignal,
+			    "sotDynInvWB("+getName()+")::input(vector)::_"+name+"_x" ) );
+	signalRegistration( *contactMap[name].correctorSIN );
+
+	contactMap[name].forceSOUT
+	  = vectorSOUTPtr( new Signal<ml::Vector,int>
+			   ( "sotDynInvWB("+getName()+")::output(vector)::_"+name+"_f" ) );
+	signalRegistration( *contactMap[name].forceSOUT );
+
+	contactMap[name].fnSOUT
+	  = vectorSOUTPtr( new Signal<ml::Vector,int>
+			   ( "sotDynInvWB("+getName()+")::output(vector)::_"+name+"_fn" ) );
+	signalRegistration( *contactMap[name].fnSOUT );
+
+      }
+
+      void SolverDynReduced::
+      removeContact( const std::string & name )
+      {
+	if( contactMap.find(name) == contactMap.end() )
+	  {
+	    std::cerr << "!! Contact " << name << " does not exist." << std::endl;
+	    return;
+	  }
+
+	JcSOUT.removeDependency( *contactMap[name].jacobianSIN );
+	precomputeSOUT.removeDependency( *contactMap[name].jacobianSIN );
+	JcSOUT.setReady();
+	precomputeSOUT.setReady();
+	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 SolverDynReduced::
+      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;
+	  }
+      }
+
+
+      /* --- 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 SolverDynReduced::
+      refreshTaskTime( int time )
+      {
+	// TODO BOOST_FOREACH
+	for( StackIterator_t iter=stack.begin();stack.end()!=iter;++iter )
+	  {
+	    TaskDynPD& task = **iter;
+	    task.taskSOUT( time );
+	  }
+      }
+
+
+
+     /* --------------------------------------------------------------------- */
+      /* --- STATIC INTERNAL ------------------------------------------------- */
+      /* --------------------------------------------------------------------- */
+      namespace sotSolverDyn
+      {
+	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   ;
+	}
+
+	//soth::VectorBound& vbAssign ( soth::VectorBound& vb, const Eigen::VectorXd& vx )
+	template<typename D1,typename D2>
+	Eigen::MatrixBase<D1>& vbAssign ( Eigen::MatrixBase<D1>& vb,
+					  const Eigen::MatrixBase<D2>& vx )
+	{
+	  vb.resize(vx.size());
+	  for( int i=0;i<vx.size();++i ){ vb[i] = vx[i]; }
+	  return vb;
+	}
+      }
+
+      /* --- SIGNALS ---------------------------------------------------------- */
+      /* --- SIGNALS ---------------------------------------------------------- */
+      /* --- SIGNALS ---------------------------------------------------------- */
+
+      // TODO: the following should be replace by the middleColumn and
+      // middleRow functions.
+#define COLS(__ri,__rs) leftCols(__rs).rightCols((__rs)-(__ri))
+#define ROWS(__ri,__rs) topRows(__rs).bottomRows((__rs)-(__ri))
+
+      ml::Matrix& SolverDynReduced::
+      inertiaSqrootOutSOUT_function( ml::Matrix& mlAsq, int t )
+      {
+	EIGEN_CONST_MATRIX_FROM_SIGNAL(A,matrixInertiaSIN(t));
+	EIGEN_MATRIX_FROM_MATRIX(Asq,mlAsq,A.rows(),A.cols());
+
+	using namespace Eigen;
+	sotDEBUG(1) << "A = " << (soth::MATLAB)A << std::endl;
+
+	Asq = A.llt().matrixU();
+
+	/* Asq is such that Asq^T Asq = A. */
+	return mlAsq;
+      }
+
+      ml::Matrix& SolverDynReduced::
+      inertiaSqrootInvOutSOUT_function( ml::Matrix& mlAsqi,int t)
+      {
+	EIGEN_CONST_MATRIX_FROM_SIGNAL(Asq,inertiaSqrootSIN(t));
+	const int n = Asq.rows();
+	EIGEN_MATRIX_FROM_MATRIX(Asqi,mlAsqi,n,n);
+	Asqi = Asq.triangularView<Eigen::Upper>().solve( Eigen::MatrixXd::Identity(n,n));
+
+	/* Asqi is such that Asq^-1 = Asqi and Asqi Asqi^T = A^-1. Asqi is upper triangular. */
+	return mlAsqi;
+      }
+
+      /* This function compute all the input matrix and vector signals that
+       * will be needed by the solver. The main objective of this precomputation
+       * is to get the size of all the elements. */
+      int& SolverDynReduced::
+      precomputeSOUT_function( int& dummy, int t )
+      {
+	/* Precompute the dynamic data. */
+	inertiaSqrootInvSIN.recompute(t);
+	inertiaSqrootSIN.recompute(t);
+
+	/* Precompute the contact data. */
+	BOOST_FOREACH(contacts_t::value_type& pContact, contactMap)
+	  {
+	    Contact& contact = pContact.second;
+	    contact.jacobianSIN->recompute(t);
+	    contact.JdotSIN->recompute(t);
+	    contact.supportSIN->recompute(t);
+	    contact.correctorSIN->recompute(t);
+	  }
+
+	/* Precompute the tasks data. */
+	for( int i=0;i<(int)stack.size();++i )
+	  {
+	    stack[i]->taskSOUT.recompute(t);
+	    stack[i]->jacobianSOUT.recompute(t);
+	  }
+
+	return dummy;
+      }
+
+      int& SolverDynReduced::
+      sizeForceSOUT_function( int& nf, int t )
+      {
+	precomputeSOUT(t);
+
+	nf=0;
+	BOOST_FOREACH(contacts_t::value_type& pContact, contactMap)
+	  {
+	    Contact& contact = pContact.second;
+	    const int nfi = (*contact.supportSIN)(t).nbCols()*3;
+	    contact.range = std::make_pair(nf,nf+nfi);
+	    nf+=nfi;
+	  }
+	return nf;
+      }
+
+      ml::Matrix& SolverDynReduced::
+      JcSOUT_function( ml::Matrix& mlJ,int t )
+      {
+	using namespace Eigen;
+
+	const int& nf = sizeForceSOUT(t);
+	const int nq= velocitySIN(t).size();
+	EIGEN_MATRIX_FROM_MATRIX(J,mlJ,nf,nq);
+
+	BOOST_FOREACH(contacts_t::value_type& pContact, contactMap)
+	  {
+	    Contact& contact = pContact.second;
+	    EIGEN_CONST_MATRIX_FROM_SIGNAL(Ji,(*contact.jacobianSIN)(t));
+	    EIGEN_CONST_MATRIX_FROM_SIGNAL(support,(*contact.supportSIN)(t));
+	    const int n0 = contact.range.first, n1 = contact.range.second;
+	    assert( Ji.rows()==6 && Ji.cols()==nq );
+	    assert( n0>=0 && J.rows()>=n1 );
+
+	    const int nbp = support.cols();
+	    assert( ((n1-n0) % 3 == 0) && nbp == (n1-n0)/3);
+	    Matrix3d X;
+	    for( int i=0;i<nbp;++i )
+	      {
+		sotSolverDyn::preCross(support.col(i),X);
+		J.ROWS(n0+i*3,n0+(i+1)*3)
+		  = Ji.ROWS(0,3) - X* Ji.ROWS(3,6);
+	      }
+	  }
+	return mlJ;
+      }
+
+      ml::Matrix& SolverDynReduced::
+      freeMotionBaseSOUT_function( ml::Matrix& mlV,int t )
+      {
+	using namespace Eigen;
+	EIGEN_CONST_MATRIX_FROM_SIGNAL(B,inertiaSqrootInvSIN(t));
+	EIGEN_CONST_MATRIX_FROM_SIGNAL(J,JcSOUT(t));
+	const int nf = J.rows(), nq = B.cols();
+	assert( J.cols()==nq && B.rows() == nq );
+
+	MatrixXd Gt = (J*B.triangularView<Eigen::Upper>()).transpose();
+	FullPivHouseholderQR<MatrixXd> qr( Gt );
+	qr.setThreshold( 1e-3 );
+
+	EIGEN_MATRIX_FROM_MATRIX(V,mlV,nq,nf-qr.rank());
+	assert( qr.matrixQ().cols()==nq && qr.matrixQ().rows()==nq
+		&& qr.matrixQ().rows()==nq );
+	V = qr.matrixQ().rightCols(nf-qr.rank());
+	return mlV;
+      }
+
+      void SolverDynReduced::
+      resizeSolver( void )
+      {
+	sotDEBUGIN(15);
+	const int & nf = sizeForceSOUT.accessCopy(),
+	  & nu = freeMotionBaseSOUT.accessCopy().nbCols(),
+	  & nq = freeMotionBaseSOUT.accessCopy().nbRows(),
+	  nbTasks = stack.size();
+
+	bool toBeResize = hsolver==NULL
+	  || (nu+nf)!=(int)hsolver->sizeProblem
+	  || stack.size()+2!= (int)hsolver->nbStages();
+
+	/* Resize the force level. */
+	if( Cforce.rows()!=nf/3+6 || Cforce.cols()!=nf+nu || bforce.size()!=nf/3+6)
+	  {
+	    Cforce.resize(nf/3+6,nf+nu);
+	    bforce.resize(nf/3+6);
+	    toBeResize = true;
+	  }
+
+	/* Resize the task levels. */
+	if( Ctasks.size()!=nbTasks || btasks.size()!=nbTasks )
+	  {
+	    Ctasks.resize(nbTasks);
+	    btasks.resize(nbTasks);
+	  }
+	for( int i=0;i<(int)stack.size();++i )
+	  {
+	    const int ntask = stack[i]->taskSOUT.accessCopy().size();
+	    if( ntask != btasks[i].size()
+		|| ntask != Ctasks[i].rows()
+		|| nf+nu != Ctasks[i].cols() )
+	      {
+		Ctasks[i].resize( ntask,nu+nf );
+		btasks[i].resize( ntask );
+		toBeResize = true;
+	      }
+	  }
+
+	/* Resize the final level. */
+	if( Czero.cols()!=nf+nu || Czero.rows()!=nq-6 || bzero.size()!=nq-6 )
+	  {
+	    Czero.resize(nq-6,nf+nu);
+	    bzero.resize(nq-6);
+	    toBeResize = true;
+	  }
+
+	/* Rebuild the solver. */
+	if( toBeResize )
+	  {
+	    sotDEBUG(1) << "Resize all." << std::endl;
+	    hsolver = hcod_ptr_t(new soth::HCOD(nf+nu,nbTasks+2));
+
+	    hsolver->pushBackStage( Cforce,    bforce );
+	    hsolver->stages.back()->name = "force";
+
+	    for( int i=0;i<(int)stack.size();++i )
+	      {
+		hsolver->pushBackStage( Ctasks[i],    btasks[i] );
+		hsolver->stages.back()->name = stack[i]->getName();
+	      }
+
+	    hsolver->pushBackStage( Czero,    bzero );
+	    hsolver->stages.back()->name = "zero";
+
+	    solution.resize( nf+nu );
+	  }
+      }
+
+      ml::Vector& SolverDynReduced::
+      solutionSOUT_function( ml::Vector &mlres, int t )
+      {
+	sotDEBUG(15) << " # In time = " << t << std::endl;
+	using namespace soth;
+	using namespace Eigen;
+	using namespace sotSolverDyn;
+
+	precomputeSOUT(t);
+	EIGEN_CONST_MATRIX_FROM_SIGNAL(sB,inertiaSqrootInvSIN(t));
+	EIGEN_CONST_MATRIX_FROM_SIGNAL(sBi,inertiaSqrootSIN(t));
+	EIGEN_CONST_MATRIX_FROM_SIGNAL(V,freeMotionBaseSOUT(t));
+	EIGEN_CONST_MATRIX_FROM_SIGNAL(Jc,JcSOUT(t));
+	EIGEN_CONST_VECTOR_FROM_SIGNAL(b,dyndriftSIN(t));
+	Eigen::TriangularView<const_SigMatrixXd,Eigen::Upper> B(sB);
+	Eigen::TriangularView<const_SigMatrixXd,Eigen::Upper> Bi(sBi);
+
+	const int & nf = sizeForceSOUT(t);
+	const int nq = B.cols(), nu = V.cols(), nbForce= nf/3;
+	resizeSolver();
+
+	assert( (nf%3)==0 );
+
+	sotDEBUG(1) << "b = " << (MATLAB)b << std::endl;
+	sotDEBUG(1) << "B = " << (MATLAB)sB << std::endl;
+	sotDEBUG(1) << "Bi = " << (MATLAB)sBi << std::endl;
+	sotDEBUG(1) << "V = " << (MATLAB)V << std::endl;
+	sotDEBUG(1) << "Jc = " << (MATLAB)Jc << std::endl;
+
+
+	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 );
+	  }
+
+	/* SOT:
+	 * 1.a Sb J' f = - S' B^-T V u
+	 * 1.b Sf f > 0
+	 * 2... Ji B u = ddxi
+	 * 3 ...
+
+
+	 * 1.a [ S'*B^-T*V  Sb J' ] =  -Sb b
+	 * 1.b [ 0          Sf    ] >= 0
+	 * 2.. [ Ji*B       0     ] = xddi
+	 */
+
+
+#define COLS_U leftCols( nu )
+#define COLS_F rightCols( nf )
+#define ROWS_FF topRows( 6 )
+#define ROWS_ACT bottomRows( nq-6 )
+
+	/* -1- */
+	assert( Cforce.cols()==nu+nf && Cforce.rows()==6+nf/3 && (nf%3)==0 );
+	/* C[Upart] = Sbar*Bi^T*V = [ Bi^T[FFpart] 0 ]*V
+	 *          = Bi^T[FFpart] * V[FFpart] because Bi^T is lower triangular. */ 
+	Cforce.ROWS_FF.COLS_U
+	  = sBi.transpose().topLeftCorner(6,6).triangularView<Upper>()*V.ROWS_FF;
+	Cforce.ROWS_FF.COLS_F = Jc.transpose().ROWS_FF;
+	VectorBlock<VectorBound> bff = bforce.head(6);//.ROWS_FF;
+	vbAssign(bff,b.ROWS_FF);
+	/* C[lower-part] ... */
+	Cforce.bottomRows(nbForce).setZero();
+	for( int i=0; i<nbForce;++i )
+	  {
+	    Cforce.bottomRightCorner(nbForce,nf)(i,3*i+2)=1;
+	  }
+	bforce.tail(nbForce).fill( Bound( 0,Bound::BOUND_INF) );
+	sotDEBUG(15) << "Cforce = "     << (MATLAB)Cforce << std::endl;
+	sotDEBUG(1) << "bforce = "     << bforce << std::endl;
+
+	/* The matrix B*V has to be stored to avoid unecessary
+	 * recomputation. */
+	BV = B*V;
+	sotDEBUG(15) << "BV = "     << (MATLAB)BV << std::endl;
+	sotDEBUG(15) << "B = "     << (MATLAB)(MatrixXd)B << std::endl;
+
+	/* -2- */
+	for( int i=0;i<(int)stack.size();++i )
+	  {
+	    TaskDynPD & task = * stack[i];
+	    MatrixXd & Ctask1 = Ctasks[i];
+	    VectorBound & btask1 = btasks[i];
+
+	    EIGEN_CONST_MATRIX_FROM_SIGNAL(Jdot,task.JdotSOUT(t));
+	    EIGEN_CONST_MATRIX_FROM_SIGNAL(J,task.jacobianSOUT(t));
+	    const dg::sot::VectorMultiBound & ddx = task.taskSOUT(t);
+	    const int nx = 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();
+
+	  }
+
+	/* -3- */
+	/* Czero = [ BV 0 ] */
+	assert( Czero.cols() == nu+nf && Czero.rows()==nq-6 && bzero.size() ==nq-6 );
+	Czero.COLS_U = BV.ROWS_ACT;
+	Czero.COLS_F.setZero();
+	const double & Kv = breakFactorSIN(t);
+	EIGEN_CONST_VECTOR_FROM_SIGNAL(dq,velocitySIN(t));
+	if( postureSIN && positionSIN )
+	   {
+	     EIGEN_CONST_VECTOR_FROM_SIGNAL(qref,postureSIN(t));
+	     EIGEN_CONST_VECTOR_FROM_SIGNAL(q,positionSIN(t));
+	     const double Kp = .25*Kv*Kv;
+	     vbAssign( bzero,(-Kp*(q-qref)-Kv*dq).tail(nbDofs) );
+	   }
+	else
+	  {	vbAssign(bzero,(-Kv*dq).tail(nbDofs));	  }
+	sotDEBUG(15) << "Czero = "     << (MATLAB)Czero << std::endl;
+	sotDEBUG(1) << "bzero = "     << bzero << std::endl;
+
+	/* Run solver */
+	/* --- */
+	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;
+	EIGEN_VECTOR_FROM_VECTOR(res,mlres,nf+nu);
+	res=solution;
+
+	sotDEBUGOUT(15);
+	return mlres;
+      }
+
+      ml::Vector& SolverDynReduced::
+      reducedControlSOUT_function( ml::Vector& res,int t )
+      {
+	EIGEN_CONST_VECTOR_FROM_SIGNAL(x,solutionSOUT(t));
+	const int nu = freeMotionBaseSOUT(t).nbCols();
+	EIGEN_VECTOR_FROM_VECTOR(u,res,nu);
+	u = x.head(nu);
+
+	return res;
+      }
+      ml::Vector& SolverDynReduced::
+      accelerationSOUT_function( ml::Vector& mlddq,int t )
+      {
+	EIGEN_CONST_VECTOR_FROM_SIGNAL(u,reducedControlSOUT(t));
+	EIGEN_VECTOR_FROM_VECTOR(ddq,mlddq,BV.rows());
+	/* BV has already been computed, but I don't know if it is the best
+	 * idea to go for it a second time. This suppose that the matrix has
+	 * not been modified in between. It should work, but start with that if
+	 * you are looking for a bug in ddq. */
+	ddq = BV*u;
+	return mlddq;
+      }
+      ml::Vector& SolverDynReduced::
+      forcesSOUT_function( ml::Vector& res,int t )
+      {
+	EIGEN_CONST_VECTOR_FROM_SIGNAL(x,solutionSOUT(t));
+	const int nf = JcSOUT(t).nbRows();
+	EIGEN_VECTOR_FROM_VECTOR(f,res,nf);
+	f = x.tail(nf);
+
+	/* Copy the 3d values of each body forces. */
+	BOOST_FOREACH(contacts_t::value_type& pContact, contactMap)
+	  {
+	    Contact& contact = pContact.second;
+	    const int n0 = contact.range.first, n1 = contact.range.second;
+	    {
+	      ml::Vector mlfi;
+	      EIGEN_VECTOR_FROM_VECTOR( fi,mlfi,n1-n0 );
+	      fi = f.segment(n0,n1-n0);
+	      (*contact.forceSOUT)= mlfi;
+	    }
+
+	    {
+	      assert( ((n1-n0)%3) ==0 );
+	      ml::Vector mlfi;
+	      EIGEN_VECTOR_FROM_VECTOR( fi,mlfi,(n1-n0)/3 );
+	      for( int i=0;i<(n1-n0)/3;++i ) { fi[i] = f.segment(n0,(n1-n0))[3*i]; }
+	      (*contact.fnSOUT)= mlfi;
+	    }
+	  }
+
+	return res;
+      }
+      ml::Vector& SolverDynReduced::
+      torqueSOUT_function( ml::Vector& res,int ) { return res; }
+
+      /* --- ENTITY ----------------------------------------------------------- */
+      /* --- ENTITY ----------------------------------------------------------- */
+      /* --- ENTITY ----------------------------------------------------------- */
+
+      void SolverDynReduced::
+      display( std::ostream& os ) const
+      {
+	os << "SolverDynReduced "<<getName() << ": " << nbDofs <<" joints." << std::endl;
+	try{
+	  os <<"solution = "<< solutionSOUT.accessCopy() <<std::endl << std::endl;
+	}  catch (dynamicgraph::ExceptionSignal e) {}
+	stack_t::display(os);
+	dispContacts(os);
+      }
+
+    } // namespace dyninv
+  } // namespace sot
+} // namespace dynamicgraph
+
diff --git a/src/solver-dyn-reduced.h b/src/solver-dyn-reduced.h
new file mode 100644
index 0000000..5fb9091
--- /dev/null
+++ b/src/solver-dyn-reduced.h
@@ -0,0 +1,169 @@
+/*
+ * 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/>.
+ */
+
+#ifndef __sot_dyninv_SolverDynReduced_H__
+#define __sot_dyninv_SolverDynReduced_H__
+/* --------------------------------------------------------------------- */
+/* --- API ------------------------------------------------------------- */
+/* --------------------------------------------------------------------- */
+
+#if defined (WIN32)
+#  if defined (solver_op_space_EXPORTS)
+#    define SOTSOLVERDYNREDUCED_EXPORT __declspec(dllexport)
+#  else
+#    define SOTSOLVERDYNREDUCED_EXPORT __declspec(dllimport)
+#  endif
+#else
+#  define SOTSOLVERDYNREDUCED_EXPORT
+#endif
+
+/* --------------------------------------------------------------------- */
+/* --- INCLUDE --------------------------------------------------------- */
+/* --------------------------------------------------------------------- */
+
+
+/* SOT */
+#include <sot-dyninv/signal-helper.h>
+#include <sot-dyninv/entity-helper.h>
+#include <sot-dyninv/stack-template.h>
+#include <sot-dyninv/task-dyn-pd.h>
+#include <soth/HCOD.hpp>
+
+namespace dynamicgraph {
+  namespace sot {
+    namespace dyninv {
+
+      /* --------------------------------------------------------------------- */
+      /* --- CLASS ----------------------------------------------------------- */
+      /* --------------------------------------------------------------------- */
+
+      class SOTSOLVERDYNREDUCED_EXPORT SolverDynReduced
+	:public ::dynamicgraph::Entity
+	,public ::dynamicgraph::EntityHelper<SolverDynReduced>
+	,public sot::Stack< TaskDynPD >
+	{
+
+	public: /* --- CONSTRUCTOR ---- */
+
+	  SolverDynReduced( const std::string & name );
+
+	public: /* --- STACK INHERITANCE --- */
+
+	  typedef sot::Stack<TaskDynPD> stack_t;
+	  using stack_t::TaskDependancyList_t;
+	  using stack_t::StackIterator_t;
+	  using stack_t::StackConstIterator_t;
+	  using stack_t::stack;
+
+	  virtual TaskDependancyList_t getTaskDependancyList( const TaskDynPD& task );
+	  virtual void addDependancy( const TaskDependancyList_t& depList );
+	  virtual void removeDependancy( const TaskDependancyList_t& depList );
+	  virtual void resetReady( void );
+
+	public: /* --- ENTITY INHERITANCE --- */
+
+	  static const std::string CLASS_NAME;
+	  virtual void display( std::ostream& os ) const;
+	  virtual const std::string& getClassName( void ) const { return CLASS_NAME; }
+
+	public:  /* --- SIGNALS --- */
+
+	  DECLARE_SIGNAL_IN(matrixInertia,ml::Matrix);
+	  DECLARE_SIGNAL_IN(inertiaSqroot,ml::Matrix);
+	  DECLARE_SIGNAL_IN(inertiaSqrootInv,ml::Matrix);
+	  DECLARE_SIGNAL_IN(velocity,ml::Vector);
+	  DECLARE_SIGNAL_IN(dyndrift,ml::Vector);
+	  DECLARE_SIGNAL_IN(damping,double);
+	  DECLARE_SIGNAL_IN(breakFactor,double);
+	  DECLARE_SIGNAL_IN(posture,ml::Vector);
+	  DECLARE_SIGNAL_IN(position,ml::Vector);
+
+
+	  DECLARE_SIGNAL_OUT(precompute,int);
+
+	  DECLARE_SIGNAL_OUT(inertiaSqrootOut,ml::Matrix);
+	  DECLARE_SIGNAL_OUT(inertiaSqrootInvOut,ml::Matrix);
+
+	  DECLARE_SIGNAL_OUT(sizeForce,int);
+	  DECLARE_SIGNAL_OUT(Jc,ml::Matrix);
+
+	  DECLARE_SIGNAL_OUT(freeMotionBase,ml::Matrix);
+	  DECLARE_SIGNAL_OUT(solution,ml::Vector);
+	  DECLARE_SIGNAL_OUT(reducedControl,ml::Vector);
+	  DECLARE_SIGNAL_OUT(acceleration,ml::Vector);
+	  DECLARE_SIGNAL_OUT(forces,ml::Vector);
+	  DECLARE_SIGNAL_OUT(torque,ml::Vector);
+
+
+
+	private:  /* --- CONTACT POINTS --- */
+
+	  typedef boost::shared_ptr<dynamicgraph::SignalPtr<ml::Matrix,int> > matrixSINPtr;
+	  typedef boost::shared_ptr<dynamicgraph::SignalPtr<ml::Vector,int> > vectorSINPtr;
+	  typedef boost::shared_ptr<dynamicgraph::Signal<ml::Vector,int> > vectorSOUTPtr;
+	  struct Contact
+	  {
+	    matrixSINPtr jacobianSIN;
+	    matrixSINPtr JdotSIN;
+	    matrixSINPtr supportSIN;
+	    vectorSINPtr correctorSIN;
+	    vectorSOUTPtr forceSOUT,fnSOUT;
+	    std::pair<int,int> range;
+	  };
+	  typedef std::map< std::string,Contact > contacts_t;
+	  contacts_t contactMap;
+
+	public:
+	  void addContact( const std::string & name,
+			   dynamicgraph::Signal<ml::Matrix,int> * jacobianSignal,
+			   dynamicgraph::Signal<ml::Matrix,int> * JdotSignal,
+			   dynamicgraph::Signal<ml::Vector,int> * corrSignal,
+			   dynamicgraph::Signal<ml::Matrix,int> * contactPointsSignal );
+	  void addContactFromTask( const std::string & taskName, const std::string & contactName );
+	  void removeContact( const std::string & name );
+	  void dispContacts( std::ostream& os ) const;
+
+
+	public: /* --- COMMANDS --- */
+	  void debugOnce( void );
+
+
+	private: /* --- INTERNAL COMPUTATIONS --- */
+	  void refreshTaskTime( int time );
+	  void resizeSolver( void );
+
+	private:
+	  typedef boost::shared_ptr<soth::HCOD> hcod_ptr_t;
+	  hcod_ptr_t hsolver;
+
+	  Eigen::MatrixXd Cforce,Czero;
+	  soth::VectorBound bforce,bzero;
+	  std::vector< Eigen::MatrixXd > Ctasks;
+	  std::vector< soth::VectorBound > btasks;
+
+	  Eigen::MatrixXd BV;
+
+	  Eigen::VectorXd solution;
+
+	}; // class SolverDynReduced
+
+    } // namespace dyninv
+  } // namespace sot
+} // namespace dynamicgraph
+
+
+
+#endif // #ifndef __sot_dyninv_SolverDynReduced_H__
-- 
GitLab