Example #1
0
static void space_geom_collider (void *data, dxGeom *o1, dxGeom *o2)
{
  SpaceGeomColliderData *d = (SpaceGeomColliderData*) data;
  if (d->flags & NUMC_MASK) {
    int n = dCollide (o1,o2,d->flags,d->contact,d->skip);
    d->contact = CONTACT (d->contact,d->skip*n);
    d->flags -= n;
#ifndef dNODEBUG
	if(d->flags<=0)
	{
		//char s[64];
		//_snprintf (s,sizeof(s),"tmp %f,%f,%f \n avel %f,%f,%f",tmp[0],tmp[1],tmp[2],b->avel[0],b->avel[1],b->avel[2]);
		//dUASSERT(0,"tmp %f,%f,%f \n avel %f,%f,%f",tmp[0],tmp[1],tmp[2],b->avel[0],b->avel[1],b->avel[2]);

		dMessage(0, "Collider exceed contact buffer");
	}

#endif
  }
}
void resetSimulation()
{
	int i;
	i = 0;
	// destroy world if it exists
	if (bodies)
	{
		dJointGroupDestroy (contactgroup);
		dSpaceDestroy (space);
		dWorldDestroy (world);
	}
	
	for (i = 0; i < 1000; i++)
		wb_stepsdis[i] = 0;

	// recreate world
	
	world = dWorldCreate();

//	space = dHashSpaceCreate( 0 );
//	space = dSimpleSpaceCreate( 0 );
	space = dSweepAndPruneSpaceCreate( 0, dSAP_AXES_XYZ );

	contactgroup = dJointGroupCreate (0);
	dWorldSetGravity (world,0,0,-1.5);
	dWorldSetCFM (world, 1e-5);
	dWorldSetERP (world, 0.8);
	dWorldSetQuickStepNumIterations (world,ITERS);
	ground = dCreatePlane (space,0,0,1,0);
	
	bodies = 0;
	joints = 0;
	boxes = 0;
	spheres = 0;
	wb = 0;
	
#ifdef CARS
	for (dReal x = 0.0; x < COLS*(LENGTH+RADIUS); x += LENGTH+RADIUS)
		for (dReal y = -((ROWS-1)*(WIDTH/2+RADIUS)); y <= ((ROWS-1)*(WIDTH/2+RADIUS)); y += WIDTH+RADIUS*2)
			makeCar(x, y, bodies, joints, boxes, spheres);
#endif
#ifdef WALL
	bool offset = false;
	for (dReal z = WBOXSIZE/2.0; z <= WALLHEIGHT; z+=WBOXSIZE)
	{
		offset = !offset;
		for (dReal y = (-WALLWIDTH+z)/2; y <= (WALLWIDTH-z)/2; y+=WBOXSIZE)
		{
			wall_bodies[wb] = dBodyCreate (world);
			dBodySetPosition (wall_bodies[wb],-20,y,z);
			dMassSetBox (&m,1,WBOXSIZE,WBOXSIZE,WBOXSIZE);
			dMassAdjust (&m, WALLMASS);
			dBodySetMass (wall_bodies[wb],&m);
			wall_boxes[wb] = dCreateBox (space,WBOXSIZE,WBOXSIZE,WBOXSIZE);
			dGeomSetBody (wall_boxes[wb],wall_bodies[wb]);
			//dBodyDisable(wall_bodies[wb++]);
			wb++;
		}
	}
	dMessage(0,"wall boxes: %i", wb);
#endif
#ifdef BALLS
	for (dReal x = -7; x <= -4; x+=1)
		for (dReal y = -1.5; y <= 1.5; y+=1)
			for (dReal z = 1; z <= 4; z+=1)
			{
				b = dBodyCreate (world);
				dBodySetPosition (b,x*RADIUS*2,y*RADIUS*2,z*RADIUS*2);
				dMassSetSphere (&m,1,RADIUS);
				dMassAdjust (&m, BALLMASS);
				dBodySetMass (b,&m);
				sphere[spheres] = dCreateSphere (space,RADIUS);
				dGeomSetBody (sphere[spheres++],b);
			}
#endif
#ifdef ONEBALL
	b = dBodyCreate (world);
	dBodySetPosition (b,0,0,2);
	dMassSetSphere (&m,1,RADIUS);
	dMassAdjust (&m, 1);
	dBodySetMass (b,&m);
	sphere[spheres] = dCreateSphere (space,RADIUS);
	dGeomSetBody (sphere[spheres++],b);
#endif
#ifdef BALLSTACK
	for (dReal z = 1; z <= 6; z+=1)
	{
		b = dBodyCreate (world);
		dBodySetPosition (b,0,0,z*RADIUS*2);
		dMassSetSphere (&m,1,RADIUS);
		dMassAdjust (&m, 0.1);
		dBodySetMass (b,&m);
		sphere[spheres] = dCreateSphere (space,RADIUS);
		dGeomSetBody (sphere[spheres++],b);
	}
#endif
#ifdef CENTIPEDE
	dBodyID lastb = 0;
	for (dReal y = 0; y < 10*LENGTH; y+=LENGTH+0.1)
	{
		// chassis body
		
		b = body[bodies] = dBodyCreate (world);
		dBodySetPosition (body[bodies],-15,y,STARTZ);
		dMassSetBox (&m,1,WIDTH,LENGTH,HEIGHT);
		dMassAdjust (&m,CMASS);
		dBodySetMass (body[bodies],&m);
		box[boxes] = dCreateBox (space,WIDTH,LENGTH,HEIGHT);
		dGeomSetBody (box[boxes++],body[bodies++]);
		
		for (dReal x = -17; x > -20; x-=RADIUS*2)
		{
			body[bodies] = dBodyCreate (world);
			dBodySetPosition(body[bodies], x, y, STARTZ);
			dMassSetSphere(&m, 1, RADIUS);
			dMassAdjust(&m, WMASS);
			dBodySetMass(body[bodies], &m);
			sphere[spheres] = dCreateSphere (space, RADIUS);
			dGeomSetBody (sphere[spheres++], body[bodies]);
			
			joint[joints] = dJointCreateHinge2 (world,0);
			if (x == -17)
				dJointAttach (joint[joints],b,body[bodies]);
			else
				dJointAttach (joint[joints],body[bodies-2],body[bodies]);
			const dReal *a = dBodyGetPosition (body[bodies++]);
			dJointSetHinge2Anchor (joint[joints],a[0],a[1],a[2]);
			dJointSetHinge2Axis1 (joint[joints],0,0,1);
			dJointSetHinge2Axis2 (joint[joints],1,0,0);
			dJointSetHinge2Param (joint[joints],dParamSuspensionERP,1.0);
			dJointSetHinge2Param (joint[joints],dParamSuspensionCFM,1e-5);
			dJointSetHinge2Param (joint[joints],dParamLoStop,0);
			dJointSetHinge2Param (joint[joints],dParamHiStop,0);
			dJointSetHinge2Param (joint[joints],dParamVel2,-10.0);
			dJointSetHinge2Param (joint[joints++],dParamFMax2,FMAX);

			body[bodies] = dBodyCreate (world);
			dBodySetPosition(body[bodies], -30 - x, y, STARTZ);
			dMassSetSphere(&m, 1, RADIUS);
			dMassAdjust(&m, WMASS);
			dBodySetMass(body[bodies], &m);
			sphere[spheres] = dCreateSphere (space, RADIUS);
			dGeomSetBody (sphere[spheres++], body[bodies]);
			
			joint[joints] = dJointCreateHinge2 (world,0);
			if (x == -17)
				dJointAttach (joint[joints],b,body[bodies]);
			else
				dJointAttach (joint[joints],body[bodies-2],body[bodies]);
			const dReal *b = dBodyGetPosition (body[bodies++]);
			dJointSetHinge2Anchor (joint[joints],b[0],b[1],b[2]);
			dJointSetHinge2Axis1 (joint[joints],0,0,1);
			dJointSetHinge2Axis2 (joint[joints],1,0,0);
			dJointSetHinge2Param (joint[joints],dParamSuspensionERP,1.0);
			dJointSetHinge2Param (joint[joints],dParamSuspensionCFM,1e-5);
			dJointSetHinge2Param (joint[joints],dParamLoStop,0);
			dJointSetHinge2Param (joint[joints],dParamHiStop,0);
			dJointSetHinge2Param (joint[joints],dParamVel2,10.0);
			dJointSetHinge2Param (joint[joints++],dParamFMax2,FMAX);
		}
		if (lastb)
		{
			dJointID j = dJointCreateFixed(world,0);
			dJointAttach (j, b, lastb);
			dJointSetFixed(j);
		}
		lastb = b;
	}
#endif
#ifdef BOX
	body[bodies] = dBodyCreate (world);
	dBodySetPosition (body[bodies],0,0,HEIGHT/2);
	dMassSetBox (&m,1,LENGTH,WIDTH,HEIGHT);
	dMassAdjust (&m, 1);
	dBodySetMass (body[bodies],&m);
	box[boxes] = dCreateBox (space,LENGTH,WIDTH,HEIGHT);
	dGeomSetBody (box[boxes++],body[bodies++]);	
#endif
#ifdef CANNON
	cannon_ball_body = dBodyCreate (world);
	cannon_ball_geom = dCreateSphere (space,CANNON_BALL_RADIUS);
	dMassSetSphereTotal (&m,CANNON_BALL_MASS,CANNON_BALL_RADIUS);
	dBodySetMass (cannon_ball_body,&m);
	dGeomSetBody (cannon_ball_geom,cannon_ball_body);
	dBodySetPosition (cannon_ball_body,CANNON_X,CANNON_Y,CANNON_BALL_RADIUS);
#endif
}
Example #3
0
File: lcp.cpp Project: dartsim/dart
bool dSolveLCP (int n, dReal *A, dReal *x, dReal *b,
                dReal *outer_w/*=nullptr*/, int nub, dReal *lo, dReal *hi, int *findex, bool earlyTermination)
{
  dAASSERT (n>0 && A && x && b && lo && hi && nub >= 0 && nub <= n);
# ifndef dNODEBUG
  {
    // check restrictions on lo and hi
    for (int k=0; k<n; ++k) dIASSERT (lo[k] <= 0 && hi[k] >= 0);
  }
# endif


  // if all the variables are unbounded then we can just factor, solve,
  // and return
  if (nub >= n) {
    dReal *d = new dReal[n];
    dSetZero (d, n);

    int nskip = dPAD(n);
    dFactorLDLT (A, d, n, nskip);
    dSolveLDLT (A, d, b, n, nskip);
    memcpy (x, b, n*sizeof(dReal));

    delete[] d;
    return true;
  }

  const int nskip = dPAD(n);
  dReal *L = new dReal[ (n*nskip)];
  dReal *d = new dReal[ (n)];
  dReal *w = outer_w ? outer_w : (new dReal[n]);
  dReal *delta_w = new dReal[ (n)];
  dReal *delta_x = new dReal[ (n)];
  dReal *Dell = new dReal[ (n)];
  dReal *ell = new dReal[ (n)];
#ifdef ROWPTRS
  dReal **Arows = new dReal* [n];
#else
  dReal **Arows = nullptr;
#endif
  int *p = new int[n];
  int *C = new int[n];

  // for i in N, state[i] is 0 if x(i)==lo(i) or 1 if x(i)==hi(i)
  bool *state = new bool[n];

  // create LCP object. note that tmp is set to delta_w to save space, this
  // optimization relies on knowledge of how tmp is used, so be careful!
  dLCP lcp(n,nskip,nub,A,x,b,w,lo,hi,L,d,Dell,ell,delta_w,state,findex,p,C,Arows);
  int adj_nub = lcp.getNub();

  // loop over all indexes adj_nub..n-1. for index i, if x(i),w(i) satisfy the
  // LCP conditions then i is added to the appropriate index set. otherwise
  // x(i),w(i) is driven either +ve or -ve to force it to the valid region.
  // as we drive x(i), x(C) is also adjusted to keep w(C) at zero.
  // while driving x(i) we maintain the LCP conditions on the other variables
  // 0..i-1. we do this by watching out for other x(i),w(i) values going
  // outside the valid region, and then switching them between index sets
  // when that happens.

  bool hit_first_friction_index = false;
  for (int i=adj_nub; i<n; ++i) {
    bool s_error = false;
    // the index i is the driving index and indexes i+1..n-1 are "dont care",
    // i.e. when we make changes to the system those x's will be zero and we
    // don't care what happens to those w's. in other words, we only consider
    // an (i+1)*(i+1) sub-problem of A*x=b+w.

    // if we've hit the first friction index, we have to compute the lo and
    // hi values based on the values of x already computed. we have been
    // permuting the indexes, so the values stored in the findex vector are
    // no longer valid. thus we have to temporarily unpermute the x vector. 
    // for the purposes of this computation, 0*infinity = 0 ... so if the
    // contact constraint's normal force is 0, there should be no tangential
    // force applied.

    if (!hit_first_friction_index && findex && findex[i] >= 0) {
      // un-permute x into delta_w, which is not being used at the moment
      for (int j=0; j<n; ++j) delta_w[p[j]] = x[j];

      // set lo and hi values
      for (int k=i; k<n; ++k) {
        dReal wfk = delta_w[findex[k]];
        if (wfk == 0) {
          hi[k] = 0;
          lo[k] = 0;
        }
        else {
          hi[k] = dFabs (hi[k] * wfk);
          lo[k] = -hi[k];
        }
      }
      hit_first_friction_index = true;
    }

    // thus far we have not even been computing the w values for indexes
    // greater than i, so compute w[i] now.
    w[i] = lcp.AiC_times_qC (i,x) + lcp.AiN_times_qN (i,x) - b[i];

    // if lo=hi=0 (which can happen for tangential friction when normals are
    // 0) then the index will be assigned to set N with some state. however,
    // set C's line has zero size, so the index will always remain in set N.
    // with the "normal" switching logic, if w changed sign then the index
    // would have to switch to set C and then back to set N with an inverted
    // state. this is pointless, and also computationally expensive. to
    // prevent this from happening, we use the rule that indexes with lo=hi=0
    // will never be checked for set changes. this means that the state for
    // these indexes may be incorrect, but that doesn't matter.

    // see if x(i),w(i) is in a valid region
    if (lo[i]==0 && w[i] >= 0) {
      lcp.transfer_i_to_N (i);
      state[i] = false;
    }
    else if (hi[i]==0 && w[i] <= 0) {
      lcp.transfer_i_to_N (i);
      state[i] = true;
    }
    else if (w[i]==0) {
      // this is a degenerate case. by the time we get to this test we know
      // that lo != 0, which means that lo < 0 as lo is not allowed to be +ve,
      // and similarly that hi > 0. this means that the line segment
      // corresponding to set C is at least finite in extent, and we are on it.
      // NOTE: we must call lcp.solve1() before lcp.transfer_i_to_C()
      lcp.solve1 (delta_x,i,0,1);

      lcp.transfer_i_to_C (i);
    }
    else {
      // we must push x(i) and w(i)
      for (;;) {
        int dir;
        dReal dirf;
        // find direction to push on x(i)
        if (w[i] <= 0) {
          dir = 1;
          dirf = REAL(1.0);
        }
        else {
          dir = -1;
          dirf = REAL(-1.0);
        }

        // compute: delta_x(C) = -dir*A(C,C)\A(C,i)
        lcp.solve1 (delta_x,i,dir);

        // note that delta_x[i] = dirf, but we wont bother to set it

        // compute: delta_w = A*delta_x ... note we only care about
        // delta_w(N) and delta_w(i), the rest is ignored
        lcp.pN_equals_ANC_times_qC (delta_w,delta_x);
        lcp.pN_plusequals_ANi (delta_w,i,dir);
        delta_w[i] = lcp.AiC_times_qC (i,delta_x) + lcp.Aii(i)*dirf;

        // find largest step we can take (size=s), either to drive x(i),w(i)
        // to the valid LCP region or to drive an already-valid variable
        // outside the valid region.

        int cmd = 1;		// index switching command
        int si = 0;		// si = index to switch if cmd>3
        dReal s = -w[i]/delta_w[i];
        if (dir > 0) {
          if (hi[i] < dInfinity) {
            dReal s2 = (hi[i]-x[i])*dirf;	// was (hi[i]-x[i])/dirf	// step to x(i)=hi(i)
            if (s2 < s) {
              s = s2;
              cmd = 3;
            }
          }
        }
        else {
          if (lo[i] > -dInfinity) {
            dReal s2 = (lo[i]-x[i])*dirf;	// was (lo[i]-x[i])/dirf	// step to x(i)=lo(i)
            if (s2 < s) {
              s = s2;
              cmd = 2;
            }
          }
        }

        {
          const int numN = lcp.numN();
          for (int k=0; k < numN; ++k) {
            const int indexN_k = lcp.indexN(k);
            if (!state[indexN_k] ? delta_w[indexN_k] < 0 : delta_w[indexN_k] > 0) {
                // don't bother checking if lo=hi=0
                if (lo[indexN_k] == 0 && hi[indexN_k] == 0) continue;
                dReal s2 = -w[indexN_k] / delta_w[indexN_k];
                if (s2 < s) {
                  s = s2;
                  cmd = 4;
                  si = indexN_k;
                }
            }
          }
        }

        {
          const int numC = lcp.numC();
          for (int k=adj_nub; k < numC; ++k) {
            const int indexC_k = lcp.indexC(k);
            if (delta_x[indexC_k] < 0 && lo[indexC_k] > -dInfinity) {
              dReal s2 = (lo[indexC_k]-x[indexC_k]) / delta_x[indexC_k];
              if (s2 < s) {
                s = s2;
                cmd = 5;
                si = indexC_k;
              }
            }
            if (delta_x[indexC_k] > 0 && hi[indexC_k] < dInfinity) {
              dReal s2 = (hi[indexC_k]-x[indexC_k]) / delta_x[indexC_k];
              if (s2 < s) {
                s = s2;
                cmd = 6;
                si = indexC_k;
              }
            }
          }
        }

        //static char* cmdstring[8] = {0,"->C","->NL","->NH","N->C",
        //			     "C->NL","C->NH"};
        //printf ("cmd=%d (%s), si=%d\n",cmd,cmdstring[cmd],(cmd>3) ? si : i);

        // if s <= 0 then we've got a problem. if we just keep going then
        // we're going to get stuck in an infinite loop. instead, just cross
        // our fingers and exit with the current solution.
        if (s <= REAL(0.0)) {

          if (earlyTermination) {
            if (!outer_w)
              delete[] w;
            delete[] L;
            delete[] d;
            delete[] delta_w;
            delete[] delta_x;
            delete[] Dell;
            delete[] ell;
          #ifdef ROWPTRS
            delete[] Arows;
          #endif
            delete[] p;
            delete[] C;

            delete[] state;

            return false;
          }

          // We shouldn't be overly aggressive about printing this warning,
          // because sometimes it gets spammed if s is just a tiny bit beneath
          // 0.0.
          if (s < REAL(-1e-6)) {
            dMessage (d_ERR_LCP, "LCP internal error, s <= 0 (s=%.4e)",
                      (double)s);
          }

          if (i < n) {
            dSetZero (x+i,n-i);
            dSetZero (w+i,n-i);
          }
          s_error = true;
          break;
        }

        // apply x = x + s * delta_x
        lcp.pC_plusequals_s_times_qC (x, s, delta_x);
        x[i] += s * dirf;

        // apply w = w + s * delta_w
        lcp.pN_plusequals_s_times_qN (w, s, delta_w);
        w[i] += s * delta_w[i];

        // void *tmpbuf;
        // switch indexes between sets if necessary
        switch (cmd) {
        case 1:		// done
          w[i] = 0;
          lcp.transfer_i_to_C (i);
          break;
        case 2:		// done
          x[i] = lo[i];
          state[i] = false;
          lcp.transfer_i_to_N (i);
          break;
        case 3:		// done
          x[i] = hi[i];
          state[i] = true;
          lcp.transfer_i_to_N (i);
          break;
        case 4:		// keep going
          w[si] = 0;
          lcp.transfer_i_from_N_to_C (si);
          break;
        case 5:		// keep going
          x[si] = lo[si];
          state[si] = false;
          lcp.transfer_i_from_C_to_N (si, nullptr);
          break;
        case 6:		// keep going
          x[si] = hi[si];
          state[si] = true;
          lcp.transfer_i_from_C_to_N (si, nullptr);
          break;
        }

        if (cmd <= 3) break;
      } // for (;;)
    } // else

    if (s_error) {
      break;
    }
  } // for (int i=adj_nub; i<n; ++i)

  lcp.unpermute();

  if (!outer_w)
	  delete[] w;
  delete[] L;
  delete[] d;
  delete[] delta_w;
  delete[] delta_x;
  delete[] Dell;
  delete[] ell;
#ifdef ROWPTRS
  delete[] Arows;
#endif
  delete[] p;
  delete[] C;

  delete[] state;

  return true;
}
Example #4
0
void dSolveLCP (int n, dReal *A, dReal *x, dReal *b,
		dReal *w, int nub, dReal *lo, dReal *hi, int *findex)
{
  dAASSERT (n>0 && A && x && b && w && lo && hi && nub >= 0 && nub <= n);

  int i,k,hit_first_friction_index = 0;
  int nskip = dPAD(n);

  // if all the variables are unbounded then we can just factor, solve,
  // and return
  if (nub >= n) {
    dFactorLDLT (A,w,n,nskip);		// use w for d
    dSolveLDLT (A,w,b,n,nskip);
    memcpy (x,b,n*sizeof(dReal));
    dSetZero (w,n);

    return;
  }
# ifndef dNODEBUG
  // check restrictions on lo and hi
  for (k=0; k<n; k++) dIASSERT (lo[k] <= 0 && hi[k] >= 0);
# endif
  ALLOCA (dReal,L,n*nskip*sizeof(dReal));
#ifdef dUSE_MALLOC_FOR_ALLOCA
    if (L == NULL) {
      dMemoryFlag = d_MEMORY_OUT_OF_MEMORY;
      return;
    }
#endif
  ALLOCA (dReal,d,n*sizeof(dReal));
#ifdef dUSE_MALLOC_FOR_ALLOCA
    if (d == NULL) {
      UNALLOCA(L);
      dMemoryFlag = d_MEMORY_OUT_OF_MEMORY;
      return;
    }
#endif
  ALLOCA (dReal,delta_x,n*sizeof(dReal));
#ifdef dUSE_MALLOC_FOR_ALLOCA
    if (delta_x == NULL) {
      UNALLOCA(d);
      UNALLOCA(L);
      dMemoryFlag = d_MEMORY_OUT_OF_MEMORY;
      return;
    }
#endif
  ALLOCA (dReal,delta_w,n*sizeof(dReal));
#ifdef dUSE_MALLOC_FOR_ALLOCA
    if (delta_w == NULL) {
      UNALLOCA(delta_x);
      UNALLOCA(d);
      UNALLOCA(L);
      dMemoryFlag = d_MEMORY_OUT_OF_MEMORY;
      return;
    }
#endif
  ALLOCA (dReal,Dell,n*sizeof(dReal));
#ifdef dUSE_MALLOC_FOR_ALLOCA
    if (Dell == NULL) {
      UNALLOCA(delta_w);
      UNALLOCA(delta_x);
      UNALLOCA(d);
      UNALLOCA(L);
      dMemoryFlag = d_MEMORY_OUT_OF_MEMORY;
      return;
    }
#endif
  ALLOCA (dReal,ell,n*sizeof(dReal));
#ifdef dUSE_MALLOC_FOR_ALLOCA
    if (ell == NULL) {
      UNALLOCA(Dell);
      UNALLOCA(delta_w);
      UNALLOCA(delta_x);
      UNALLOCA(d);
      UNALLOCA(L);
      dMemoryFlag = d_MEMORY_OUT_OF_MEMORY;
      return;
    }
#endif
  ALLOCA (dReal*,Arows,n*sizeof(dReal*));
#ifdef dUSE_MALLOC_FOR_ALLOCA
    if (Arows == NULL) {
      UNALLOCA(ell);
      UNALLOCA(Dell);
      UNALLOCA(delta_w);
      UNALLOCA(delta_x);
      UNALLOCA(d);
      UNALLOCA(L);
      dMemoryFlag = d_MEMORY_OUT_OF_MEMORY;
      return;
    }
#endif
  ALLOCA (int,p,n*sizeof(int));
#ifdef dUSE_MALLOC_FOR_ALLOCA
    if (p == NULL) {
      UNALLOCA(Arows);
      UNALLOCA(ell);
      UNALLOCA(Dell);
      UNALLOCA(delta_w);
      UNALLOCA(delta_x);
      UNALLOCA(d);
      UNALLOCA(L);
      dMemoryFlag = d_MEMORY_OUT_OF_MEMORY;
      return;
    }
#endif
  ALLOCA (int,C,n*sizeof(int));
#ifdef dUSE_MALLOC_FOR_ALLOCA
    if (C == NULL) {
      UNALLOCA(p);
      UNALLOCA(Arows);
      UNALLOCA(ell);
      UNALLOCA(Dell);
      UNALLOCA(delta_w);
      UNALLOCA(delta_x);
      UNALLOCA(d);
      UNALLOCA(L);
      dMemoryFlag = d_MEMORY_OUT_OF_MEMORY;
      return;
    }
#endif

  int dir;
  dReal dirf;

  // for i in N, state[i] is 0 if x(i)==lo(i) or 1 if x(i)==hi(i)
  ALLOCA (int,state,n*sizeof(int));
#ifdef dUSE_MALLOC_FOR_ALLOCA
    if (state == NULL) {
      UNALLOCA(C);
      UNALLOCA(p);
      UNALLOCA(Arows);
      UNALLOCA(ell);
      UNALLOCA(Dell);
      UNALLOCA(delta_w);
      UNALLOCA(delta_x);
      UNALLOCA(d);
      UNALLOCA(L);
      dMemoryFlag = d_MEMORY_OUT_OF_MEMORY;
      return;
    }
#endif

  // create LCP object. note that tmp is set to delta_w to save space, this
  // optimization relies on knowledge of how tmp is used, so be careful!
  dLCP *lcp=new dLCP(n,nub,A,x,b,w,lo,hi,L,d,Dell,ell,delta_w,state,findex,p,C,Arows);
  nub = lcp->getNub();

  // loop over all indexes nub..n-1. for index i, if x(i),w(i) satisfy the
  // LCP conditions then i is added to the appropriate index set. otherwise
  // x(i),w(i) is driven either +ve or -ve to force it to the valid region.
  // as we drive x(i), x(C) is also adjusted to keep w(C) at zero.
  // while driving x(i) we maintain the LCP conditions on the other variables
  // 0..i-1. we do this by watching out for other x(i),w(i) values going
  // outside the valid region, and then switching them between index sets
  // when that happens.

  for (i=nub; i<n; i++) {
    // the index i is the driving index and indexes i+1..n-1 are "dont care",
    // i.e. when we make changes to the system those x's will be zero and we
    // don't care what happens to those w's. in other words, we only consider
    // an (i+1)*(i+1) sub-problem of A*x=b+w.

    // if we've hit the first friction index, we have to compute the lo and
    // hi values based on the values of x already computed. we have been
    // permuting the indexes, so the values stored in the findex vector are
    // no longer valid. thus we have to temporarily unpermute the x vector. 
    // for the purposes of this computation, 0*infinity = 0 ... so if the
    // contact constraint's normal force is 0, there should be no tangential
    // force applied.

    if (hit_first_friction_index == 0 && findex && findex[i] >= 0) {
      // un-permute x into delta_w, which is not being used at the moment
      for (k=0; k<n; k++) delta_w[p[k]] = x[k];

      // set lo and hi values
      for (k=i; k<n; k++) {
	dReal wfk = delta_w[findex[k]];
	if (wfk == 0) {
	  hi[k] = 0;
	  lo[k] = 0;
	}
	else {
	  hi[k] = dFabs (hi[k] * wfk);
	  lo[k] = -hi[k];
	}
      }
      hit_first_friction_index = 1;
    }

    // thus far we have not even been computing the w values for indexes
    // greater than i, so compute w[i] now.
    w[i] = lcp->AiC_times_qC (i,x) + lcp->AiN_times_qN (i,x) - b[i];

    // if lo=hi=0 (which can happen for tangential friction when normals are
    // 0) then the index will be assigned to set N with some state. however,
    // set C's line has zero size, so the index will always remain in set N.
    // with the "normal" switching logic, if w changed sign then the index
    // would have to switch to set C and then back to set N with an inverted
    // state. this is pointless, and also computationally expensive. to
    // prevent this from happening, we use the rule that indexes with lo=hi=0
    // will never be checked for set changes. this means that the state for
    // these indexes may be incorrect, but that doesn't matter.

    // see if x(i),w(i) is in a valid region
    if (lo[i]==0 && w[i] >= 0) {
      lcp->transfer_i_to_N (i);
      state[i] = 0;
    }
    else if (hi[i]==0 && w[i] <= 0) {
      lcp->transfer_i_to_N (i);
      state[i] = 1;
    }
    else if (w[i]==0) {
      // this is a degenerate case. by the time we get to this test we know
      // that lo != 0, which means that lo < 0 as lo is not allowed to be +ve,
      // and similarly that hi > 0. this means that the line segment
      // corresponding to set C is at least finite in extent, and we are on it.
      // NOTE: we must call lcp->solve1() before lcp->transfer_i_to_C()
      lcp->solve1 (delta_x,i,0,1);

#ifdef dUSE_MALLOC_FOR_ALLOCA
      if (dMemoryFlag == d_MEMORY_OUT_OF_MEMORY) {
	UNALLOCA(state);
	UNALLOCA(C);
	UNALLOCA(p);
	UNALLOCA(Arows);
	UNALLOCA(ell);
	UNALLOCA(Dell);
	UNALLOCA(delta_w);
	UNALLOCA(delta_x);
	UNALLOCA(d);
	UNALLOCA(L);
	return;
      }
#endif

      lcp->transfer_i_to_C (i);
    }
    else {
      // we must push x(i) and w(i)
      for (;;) {
	// find direction to push on x(i)
	if (w[i] <= 0) {
	  dir = 1;
	  dirf = REAL(1.0);
	}
	else {
	  dir = -1;
	  dirf = REAL(-1.0);
	}

	// compute: delta_x(C) = -dir*A(C,C)\A(C,i)
	lcp->solve1 (delta_x,i,dir);

#ifdef dUSE_MALLOC_FOR_ALLOCA
	if (dMemoryFlag == d_MEMORY_OUT_OF_MEMORY) {
	  UNALLOCA(state);
	  UNALLOCA(C);
	  UNALLOCA(p);
	  UNALLOCA(Arows);
	  UNALLOCA(ell);
	  UNALLOCA(Dell);
	  UNALLOCA(delta_w);
	  UNALLOCA(delta_x);
	  UNALLOCA(d);
	  UNALLOCA(L);
	  return;
	}
#endif

	// note that delta_x[i] = dirf, but we wont bother to set it

	// compute: delta_w = A*delta_x ... note we only care about
        // delta_w(N) and delta_w(i), the rest is ignored
	lcp->pN_equals_ANC_times_qC (delta_w,delta_x);
	lcp->pN_plusequals_ANi (delta_w,i,dir);
        delta_w[i] = lcp->AiC_times_qC (i,delta_x) + lcp->Aii(i)*dirf;

	// find largest step we can take (size=s), either to drive x(i),w(i)
	// to the valid LCP region or to drive an already-valid variable
	// outside the valid region.

	int cmd = 1;		// index switching command
	int si = 0;		// si = index to switch if cmd>3
	dReal s = -w[i]/delta_w[i];
	if (dir > 0) {
	  if (hi[i] < dInfinity) {
	    dReal s2 = (hi[i]-x[i])/dirf;		// step to x(i)=hi(i)
	    if (s2 < s) {
	      s = s2;
	      cmd = 3;
	    }
	  }
	}
	else {
	  if (lo[i] > -dInfinity) {
	    dReal s2 = (lo[i]-x[i])/dirf;		// step to x(i)=lo(i)
	    if (s2 < s) {
	      s = s2;
	      cmd = 2;
	    }
	  }
	}

	for (k=0; k < lcp->numN(); k++) {
	  if ((state[lcp->indexN(k)]==0 && delta_w[lcp->indexN(k)] < 0) ||
	      (state[lcp->indexN(k)]!=0 && delta_w[lcp->indexN(k)] > 0)) {
	    // don't bother checking if lo=hi=0
	    if (lo[lcp->indexN(k)] == 0 && hi[lcp->indexN(k)] == 0) continue;
	    dReal s2 = -w[lcp->indexN(k)] / delta_w[lcp->indexN(k)];
	    if (s2 < s) {
	      s = s2;
	      cmd = 4;
	      si = lcp->indexN(k);
	    }
	  }
	}

	for (k=nub; k < lcp->numC(); k++) {
	  if (delta_x[lcp->indexC(k)] < 0 && lo[lcp->indexC(k)] > -dInfinity) {
	    dReal s2 = (lo[lcp->indexC(k)]-x[lcp->indexC(k)]) /
	      delta_x[lcp->indexC(k)];
	    if (s2 < s) {
	      s = s2;
	      cmd = 5;
	      si = lcp->indexC(k);
	    }
	  }
	  if (delta_x[lcp->indexC(k)] > 0 && hi[lcp->indexC(k)] < dInfinity) {
	    dReal s2 = (hi[lcp->indexC(k)]-x[lcp->indexC(k)]) /
	      delta_x[lcp->indexC(k)];
	    if (s2 < s) {
	      s = s2;
	      cmd = 6;
	      si = lcp->indexC(k);
	    }
	  }
	}

	//static char* cmdstring[8] = {0,"->C","->NL","->NH","N->C",
	//			     "C->NL","C->NH"};
	//printf ("cmd=%d (%s), si=%d\n",cmd,cmdstring[cmd],(cmd>3) ? si : i);

	// if s <= 0 then we've got a problem. if we just keep going then
	// we're going to get stuck in an infinite loop. instead, just cross
	// our fingers and exit with the current solution.
	if (s <= 0) {
	  dMessage (d_ERR_LCP, "LCP internal error, s <= 0 (s=%.4e)",s);
	  if (i < (n-1)) {
	    dSetZero (x+i,n-i);
	    dSetZero (w+i,n-i);
	  }
	  goto done;
	}

	// apply x = x + s * delta_x
	lcp->pC_plusequals_s_times_qC (x,s,delta_x);
	x[i] += s * dirf;

	// apply w = w + s * delta_w
	lcp->pN_plusequals_s_times_qN (w,s,delta_w);
	w[i] += s * delta_w[i];

	// switch indexes between sets if necessary
	switch (cmd) {
	case 1:		// done
	  w[i] = 0;
	  lcp->transfer_i_to_C (i);
	  break;
	case 2:		// done
	  x[i] = lo[i];
	  state[i] = 0;
	  lcp->transfer_i_to_N (i);
	  break;
	case 3:		// done
	  x[i] = hi[i];
	  state[i] = 1;
	  lcp->transfer_i_to_N (i);
	  break;
	case 4:		// keep going
	  w[si] = 0;
	  lcp->transfer_i_from_N_to_C (si);
	  break;
	case 5:		// keep going
	  x[si] = lo[si];
	  state[si] = 0;
	  lcp->transfer_i_from_C_to_N (si);
	  break;
	case 6:		// keep going
	  x[si] = hi[si];
	  state[si] = 1;
	  lcp->transfer_i_from_C_to_N (si);
	  break;
	}

	if (cmd <= 3) break;
      }
    }
  }

 done:
  lcp->unpermute();
  delete lcp;

  UNALLOCA (L);
  UNALLOCA (d);
  UNALLOCA (delta_x);
  UNALLOCA (delta_w);
  UNALLOCA (Dell);
  UNALLOCA (ell);
  UNALLOCA (Arows);
  UNALLOCA (p);
  UNALLOCA (C);
  UNALLOCA (state);
}
Example #5
0
void dSolveLCPBasic (int n, dReal *A, dReal *x, dReal *b,
		     dReal *w, int nub, dReal *lo, dReal *hi)
{
  dAASSERT (n>0 && A && x && b && w && nub == 0);

  int i,k;
  int nskip = dPAD(n);
  ALLOCA (dReal,L,n*nskip*sizeof(dReal));
#ifdef dUSE_MALLOC_FOR_ALLOCA
    if (L == NULL) {
      dMemoryFlag = d_MEMORY_OUT_OF_MEMORY;
      return;
    }
#endif
  ALLOCA (dReal,d,n*sizeof(dReal));
#ifdef dUSE_MALLOC_FOR_ALLOCA
    if (d == NULL) {
      UNALLOCA(L);
      dMemoryFlag = d_MEMORY_OUT_OF_MEMORY;
      return;
    }
#endif
  ALLOCA (dReal,delta_x,n*sizeof(dReal));
#ifdef dUSE_MALLOC_FOR_ALLOCA
    if (delta_x == NULL) {
      UNALLOCA(d);
      UNALLOCA(L);
      dMemoryFlag = d_MEMORY_OUT_OF_MEMORY;
      return;
    }
#endif
  ALLOCA (dReal,delta_w,n*sizeof(dReal));
#ifdef dUSE_MALLOC_FOR_ALLOCA
    if (delta_w == NULL) {
      UNALLOCA(delta_x);
      UNALLOCA(d);
      UNALLOCA(L);
      dMemoryFlag = d_MEMORY_OUT_OF_MEMORY;
      return;
    }
#endif
  ALLOCA (dReal,Dell,n*sizeof(dReal));
#ifdef dUSE_MALLOC_FOR_ALLOCA
    if (Dell == NULL) {
      UNALLOCA(delta_w);
      UNALLOCA(delta_x);
      UNALLOCA(d);
      UNALLOCA(L);
      dMemoryFlag = d_MEMORY_OUT_OF_MEMORY;
      return;
    }
#endif
  ALLOCA (dReal,ell,n*sizeof(dReal));
#ifdef dUSE_MALLOC_FOR_ALLOCA
    if (ell == NULL) {
      UNALLOCA(Dell);
      UNALLOCA(delta_w);
      UNALLOCA(delta_x);
      UNALLOCA(d);
      UNALLOCA(L);
      dMemoryFlag = d_MEMORY_OUT_OF_MEMORY;
      return;
    }
#endif
  ALLOCA (dReal,tmp,n*sizeof(dReal));
#ifdef dUSE_MALLOC_FOR_ALLOCA
    if (tmp == NULL) {
      UNALLOCA(ell);
      UNALLOCA(Dell);
      UNALLOCA(delta_w);
      UNALLOCA(delta_x);
      UNALLOCA(d);
      UNALLOCA(L);
      dMemoryFlag = d_MEMORY_OUT_OF_MEMORY;
      return;
    }
#endif
  ALLOCA (dReal*,Arows,n*sizeof(dReal*));
#ifdef dUSE_MALLOC_FOR_ALLOCA
    if (Arows == NULL) {
      UNALLOCA(tmp);
      UNALLOCA(ell);
      UNALLOCA(Dell);
      UNALLOCA(delta_w);
      UNALLOCA(delta_x);
      UNALLOCA(d);
      UNALLOCA(L);
      dMemoryFlag = d_MEMORY_OUT_OF_MEMORY;
      return;
    }
#endif
  ALLOCA (int,p,n*sizeof(int));
#ifdef dUSE_MALLOC_FOR_ALLOCA
    if (p == NULL) {
      UNALLOCA(Arows);
      UNALLOCA(tmp);
      UNALLOCA(ell);
      UNALLOCA(Dell);
      UNALLOCA(delta_w);
      UNALLOCA(delta_x);
      UNALLOCA(d);
      UNALLOCA(L);
      dMemoryFlag = d_MEMORY_OUT_OF_MEMORY;
      return;
    }
#endif
  ALLOCA (int,C,n*sizeof(int));
#ifdef dUSE_MALLOC_FOR_ALLOCA
    if (C == NULL) {
      UNALLOCA(p);
      UNALLOCA(Arows);
      UNALLOCA(tmp);
      UNALLOCA(ell);
      UNALLOCA(Dell);
      UNALLOCA(delta_w);
      UNALLOCA(delta_x);
      UNALLOCA(d);
      UNALLOCA(L);
      dMemoryFlag = d_MEMORY_OUT_OF_MEMORY;
      return;
    }
#endif
  ALLOCA (int,dummy,n*sizeof(int));
#ifdef dUSE_MALLOC_FOR_ALLOCA
    if (dummy == NULL) {
      UNALLOCA(C);
      UNALLOCA(p);
      UNALLOCA(Arows);
      UNALLOCA(tmp);
      UNALLOCA(ell);
      UNALLOCA(Dell);
      UNALLOCA(delta_w);
      UNALLOCA(delta_x);
      UNALLOCA(d);
      UNALLOCA(L);
      dMemoryFlag = d_MEMORY_OUT_OF_MEMORY;
      return;
    }
#endif


  dLCP lcp (n,0,A,x,b,w,tmp,tmp,L,d,Dell,ell,tmp,dummy,dummy,p,C,Arows);
  nub = lcp.getNub();

  for (i=0; i<n; i++) {
    w[i] = lcp.AiC_times_qC (i,x) - b[i];
    if (w[i] >= 0) {
      lcp.transfer_i_to_N (i);
    }
    else {
      for (;;) {
	// compute: delta_x(C) = -A(C,C)\A(C,i)
	dSetZero (delta_x,n);
	lcp.solve1 (delta_x,i);
#ifdef dUSE_MALLOC_FOR_ALLOCA
	if (dMemoryFlag == d_MEMORY_OUT_OF_MEMORY) {
	  UNALLOCA(dummy);
	  UNALLOCA(C);
	  UNALLOCA(p);
	  UNALLOCA(Arows);
	  UNALLOCA(tmp);
	  UNALLOCA(ell);
	  UNALLOCA(Dell);
	  UNALLOCA(delta_w);
	  UNALLOCA(delta_x);
	  UNALLOCA(d);
	  UNALLOCA(L);
	  return;
	}
#endif
	delta_x[i] = 1;

	// compute: delta_w = A*delta_x
	dSetZero (delta_w,n);
	lcp.pN_equals_ANC_times_qC (delta_w,delta_x);
	lcp.pN_plusequals_ANi (delta_w,i);
        delta_w[i] = lcp.AiC_times_qC (i,delta_x) + lcp.Aii(i);

	// find index to switch
	int si = i;		// si = switch index
	int si_in_N = 0;	// set to 1 if si in N
	dReal s = -w[i]/delta_w[i];

	if (s <= 0) {
	  dMessage (d_ERR_LCP, "LCP internal error, s <= 0 (s=%.4e)",s);
	  if (i < (n-1)) {
	    dSetZero (x+i,n-i);
	    dSetZero (w+i,n-i);
	  }
	  goto done;
	}

	for (k=0; k < lcp.numN(); k++) {
	  if (delta_w[lcp.indexN(k)] < 0) {
	    dReal s2 = -w[lcp.indexN(k)] / delta_w[lcp.indexN(k)];
	    if (s2 < s) {
	      s = s2;
	      si = lcp.indexN(k);
	      si_in_N = 1;
	    }
	  }
	}
	for (k=0; k < lcp.numC(); k++) {
	  if (delta_x[lcp.indexC(k)] < 0) {
	    dReal s2 = -x[lcp.indexC(k)] / delta_x[lcp.indexC(k)];
	    if (s2 < s) {
	      s = s2;
	      si = lcp.indexC(k);
	      si_in_N = 0;
	    }
	  }
	}

	// apply x = x + s * delta_x
	lcp.pC_plusequals_s_times_qC (x,s,delta_x);
	x[i] += s;
	lcp.pN_plusequals_s_times_qN (w,s,delta_w);
	w[i] += s * delta_w[i];

	// switch indexes between sets if necessary
	if (si==i) {
	  w[i] = 0;
	  lcp.transfer_i_to_C (i);
	  break;
	}
	if (si_in_N) {
          w[si] = 0;
	  lcp.transfer_i_from_N_to_C (si);
	}
	else {
          x[si] = 0;
	  lcp.transfer_i_from_C_to_N (si);
	}
      }
    }
  }

 done:
  lcp.unpermute();

  UNALLOCA (L);
  UNALLOCA (d);
  UNALLOCA (delta_x);
  UNALLOCA (delta_w);
  UNALLOCA (Dell);
  UNALLOCA (ell);
  UNALLOCA (tmp);
  UNALLOCA (Arows);
  UNALLOCA (p);
  UNALLOCA (C);
  UNALLOCA (dummy);
}
Example #6
0
void dSolveLCPBasic (int n, dReal *A, dReal *x, dReal *b,
		     dReal *w, int nub, dReal *lo, dReal *hi)
{
  dAASSERT (n>0 && A && x && b && w && nub == 0);

  int i,k;
  int nskip = dPAD(n);
  dReal *L = (dReal*) ALLOCA (n*nskip*sizeof(dReal));
  dReal *d = (dReal*) ALLOCA (n*sizeof(dReal));
  dReal *delta_x = (dReal*) ALLOCA (n*sizeof(dReal));
  dReal *delta_w = (dReal*) ALLOCA (n*sizeof(dReal));
  dReal *Dell = (dReal*) ALLOCA (n*sizeof(dReal));
  dReal *ell = (dReal*) ALLOCA (n*sizeof(dReal));
  dReal *tmp = (dReal*) ALLOCA (n*sizeof(dReal));
  dReal **Arows = (dReal**) ALLOCA (n*sizeof(dReal*));
  int *p = (int*) ALLOCA (n*sizeof(int));
  int *C = (int*) ALLOCA (n*sizeof(int));
  int *dummy = (int*) ALLOCA (n*sizeof(int));

  dLCP lcp (n,0,A,x,b,w,tmp,tmp,L,d,Dell,ell,tmp,dummy,dummy,p,C,Arows);
  nub = lcp.getNub();

  for (i=0; i<n; i++) {
    w[i] = lcp.AiC_times_qC (i,x) - b[i];
    if (w[i] >= 0) {
      lcp.transfer_i_to_N (i);
    }
    else {
      for (;;) {
	// compute: delta_x(C) = -A(C,C)\A(C,i)
	dSetZero (delta_x,n);
	lcp.solve1 (delta_x,i);
	delta_x[i] = 1;

	// compute: delta_w = A*delta_x
	dSetZero (delta_w,n);
	lcp.pN_equals_ANC_times_qC (delta_w,delta_x);
	lcp.pN_plusequals_ANi (delta_w,i);
        delta_w[i] = lcp.AiC_times_qC (i,delta_x) + lcp.Aii(i);

	// find index to switch
	int si = i;		// si = switch index
	int si_in_N = 0;	// set to 1 if si in N
	dReal s = -w[i]/delta_w[i];

	if (s <= 0) {
	  dMessage (d_ERR_LCP, "LCP internal error, s <= 0 (s=%.4e)",s);
	  if (i < (n-1)) {
	    dSetZero (x+i,n-i);
	    dSetZero (w+i,n-i);
	  }
	  goto done;
	}

	for (k=0; k < lcp.numN(); k++) {
	  if (delta_w[lcp.indexN(k)] < 0) {
	    dReal s2 = -w[lcp.indexN(k)] / delta_w[lcp.indexN(k)];
	    if (s2 < s) {
	      s = s2;
	      si = lcp.indexN(k);
	      si_in_N = 1;
	    }
	  }
	}
	for (k=0; k < lcp.numC(); k++) {
	  if (delta_x[lcp.indexC(k)] < 0) {
	    dReal s2 = -x[lcp.indexC(k)] / delta_x[lcp.indexC(k)];
	    if (s2 < s) {
	      s = s2;
	      si = lcp.indexC(k);
	      si_in_N = 0;
	    }
	  }
	}

	// apply x = x + s * delta_x
	lcp.pC_plusequals_s_times_qC (x,s,delta_x);
	x[i] += s;
	lcp.pN_plusequals_s_times_qN (w,s,delta_w);
	w[i] += s * delta_w[i];

	// switch indexes between sets if necessary
	if (si==i) {
	  w[i] = 0;
	  lcp.transfer_i_to_C (i);
	  break;
	}
	if (si_in_N) {
          w[si] = 0;
	  lcp.transfer_i_from_N_to_C (si);
	}
	else {
          x[si] = 0;
	  lcp.transfer_i_from_C_to_N (si);
	}
      }
    }
  }

 done:
  lcp.unpermute();
}