chiark / gitweb /
movpos: wip multiple movfeatkinds in one request; working on indep code
[trains.git] / hostside / movpos.c
index 632fbdee94e63d0feaaa89413bc794fadc8cbf10..845cee05aebfadf8a87fb95f46eb17b03f243544 100644 (file)
@@ -43,8 +43,8 @@ typedef struct Method Method;
 typedef struct Change Change;
 
 struct Change {                    /* valid in:  filled in by and when:      */
-  Method *meth;                    /*  PQ         indep after allocate()     */
-  MovPosChange *indep;             /*  PQ         indep after allocate()     */
+  Method *meth;                    /*  PQ         indep after prepare()      */
+  MovPosChange *indep;             /*  PQ         indep after prepare()      */
   /* kind-specific data follows */ /*  varies     kind-specific code, varies */
 } Change;
   /* `actual' contains the kind's public opinion about the physical
@@ -67,7 +67,7 @@ struct Method {
                       Segment *move,
                       int n_motions, const Motion *motions,
                       int ms, int confirming,
-                      Change *chg_r,           /* U->P; err: U->U; may be 0 */
+                      Change *chg_r,           /* 0->P; err: 0->0; may be 0 */
                       int *cost_r /* may be 0 */);
   ErrorCode (*consider)(Method *m,                                 /* TYE->T */
                        Change *remove,                   /* Q->P; err: Q->Q */
@@ -78,7 +78,7 @@ struct Method {
 
   ErrorCode (*check)(Method *m);                    /* TYE->Y; err: TYE->TYE */
   void (*execute)(Method *m);                                       /* EY->E */
-  void (*all_abandon)(Method *m);
+  void (*all_abandon)(Method *m);                                       /* I */
 };
 
 const char *movpos_pname(Segment *move, MovPosComb poscomb) {
@@ -241,8 +241,8 @@ static void fsq_queue_remove_item(FsqQueue *q, FsqReq *r) {
   fsq_queue_remove_index(q, i);
 }
 
-static FsqQueue *fsq_item_queue(FsqMethod *m, FsqReq *r) {
-  return r->motions[0].i ? &m->f.confirmed : &m->f.reserved;
+static FsqQueue *fsq_item_queue(FsqMethod *m, FsqReq *r)
+  { return r->motions[0].i ? &m->f.confirmed : &m->f.reserved; }
 
 #define WHICH(wh)                              \
   (whichr= wh##r,                              \
@@ -689,102 +689,206 @@ static void indep_change_done(Method *m, Change *chg) {
   free(indep);
 }
 
+#define EVAL_MAX_METHODS 2
+#define EVAL_MAX_MOTIONS 2
+
 static ErrorCode evaluate_target(Segment *move, MovPosComb target,
                                 MovPosComb startpoint,
-                                int *n_changes_r,
-                                Change *changes_r[N_METHODS],
-                                int *cost_r) {
+                                int ms, int confirming,
+                                MovPosChange *indep_r /* 0 ok */,
+                                int *cost_r /* 0 ok */) {
+  static int n_meths;
+  static Method *meths[EVAL_MAX_METHODS];
+  static int n_motions[EVAL_MAX_METHODS];
+  static Motion meths[EVAL_MAX_METHODS][EVAL_MAX_MOTIONS];
+
   const SegmentInfo *movei= move->i;
   int feat;
   const MovFeatInfo *feati;
-  MovFeatKind kind;
-  int n_changes;
-  Method *change_methods[N_METHODS];
-  Motion *change_motions[N_METHODS];
-  int i;
 
-  DPRINTF(movpos,eval, "%s/%s <-%s\n", move->i->pname,
+  MovPosChange *indep=0;
+
+  DPRINTF(movpos,eval, "%s/%s <-%s", move->i->pname,
          movpos_pname(move,target), movpos_pname(move,startpoint));
 
   if (!SOMEP(startpoint)) {
     startpoint= movpos_poscomb_actual(move);
-    DPRINTF(movpos,eval, "  actual <-%s\n",
+    fixme actual plumbing etc;
+    DPRINTF(movpos,eval, " actual <-%s\n",
            movpos_pname(move,startpoint));
   }
 
-  n_changes= 0;
+  n_meths= 0;
 
   for (feat=0, feati=movei->movfeats, tchanges=0, kind= mfk_none;
        feat<movei->n_movfeats;
        feat++, feati++) {
     if (!change_needed(feati,startpoint,target)) continue;
-    for (i=0; i<n_changes; i++)
-      
+    MovPosComb posn= target / feati->weight % feati->posns;
+    Method *meth= methods[kind];
+
+    int methi;
+    for (methi=0; methi<n_meths; methi++)
+      if (meths[methi] == meth) goto found_method;
+    /* need a new method */
+    methi= ++n_meths;
+    if (methi >= EVAL_MAX_METHODS) return EC_MovFeatTooManyMethods;
+    meths[methi]= meth;
+    n_motions[methi]= 0;
+    DPRINTF(movpos,eval, " meths[%d]=%s", methi,meth->pname);
+
+  found_method:
+    int motioni= ++n_motions[methi];
+    if (motioni >= EVAL_MAX_MOTIONS) return EC_MovFeatTooManyMotions;
+    DPRINTF(movpos,eval, " motion[%d][%d]=%s%d",
+           methi,motioni,feati->pname,posn);
+    motions[methi][motioni].i= feati;
+    motions[methi][motioni].posn= posn;
+  }
+
+  if (indep_r) {
+    DPRINTF(movpos,eval, " alloc");
+    indep= mmalloc(sizeof(*indep) + sizeof(Change*) * n_meths);
+    memset(indep->changes, 0, sizeof(Change*) * n_meths);
+    indep->move= move;
+    indep->start= fixme startpoint;
+    indep->actual= fixme startbfixpoint;
+  }
+  DPRINTF(movpos,eval, "\n");
+
+  int totalcost= 0;
+
+  for (int changei=0; changei<n_meths; changei++) {
+    Method *meth= meths[changei];
+    int thiscost= 0;
+    ec= meth->prepare(meth,move,
+                     n_motions[changei],motions[changei],
+                     ms, confirming,
+                     indep ? &indep->changes[changei] : 0,
+                     thiscost);
+    if (ec) goto x;
+    if (indep) {
+      Change *chg= indep->changes[changei];
+      chg->meth= meth;
+      chg->indep= indep;
+    }
+    totalcost += thiscost;
+  }
+
+  if (indep_r) *indep_r= indep;
+  if (cost_r) *cost_r= totalcost;
+  DPRINTF(movpos,eval, "%s/%s ok cost=%d\n", move->i->pname,
+         movpos_pname(move,target), totalcost);
+  return 0;
+
+ x:
+  DPRINTF(movpos,eval, "%s/%s abandon %s\n", move->i->pname,
+         movpos_pname(move,target), totalcost, ec2str(ec));
+  indep_dispose(indep);
+  return ec;
+}
+
+static ErrorCode
+indep_swap(MovPosChange *remv, MovPosChange *inst) {
+  /* does consider and check */
+  assert(inst->n_changes <= 32);
+  assert(remv->n_changes <= 32);
+  uint32_t inst_done, remv_done;
+  int inst2remv[inst->n_changes]; /* valid only if inst_done; -ve => none */
+
+  int ii, jj;
+  
+  for (ii=0; ii<inst->n_changes; ii++) {
+    Method *meth= inst->changes[ii].meth;
+    for (jj=remv->n_changes-1; jj>=0; jj++)
+      if (remv->changes[jj].meth == meth) break;
+    ec= meth->consider(meth,
+                      jj>=0 ? remv->changes[jj] : 0,
+                      inst->changes[ii]);
+    if (ec) goto x;
 
-    tchanges++;
-    if (kind && feati->kind != kind) return -1;
-    kind= feati->kind;
+    inst_done |= (1UL << ii);
+    inst2remv[ii]= jj;
+    if (jj>=0) remv_done |= (1UL << jj);
+
+    ec= meth->check(meth);
+    if (ec) goto x;
+  }
+  for (jj=0; jj<remv->n_changes; jj++) {
+    if (remv_done & (1UL << jj)) continue;
+    ec= meth->consider(meth, remv->changes[jj], 0);
+    assert(!ec);
+    ec= meth->check(meth);
+    assert(!ec);
+    /* remv_done |= (1UL << jj);
+       not needed because we never roll back from here */
   }
+  return 0;
 
-  if (kind_r) *kind_r= kind;
-  DPRINTF(movpos,eval, "changes=%d kind=%s\n",
-         tchanges, methods[kind]->pname);
-  return tchanges;
+ x:
+  for (ii=0; ii<inst->n_changes; ii++) {
+    if (!(inst_done & (1UL << ii))) continue;
+    Method *meth= inst->changes[ii].meth;
+    jj= inst2remv[ii];
+    ec= meth->consider(meth,
+                      inst->changes[ii],
+                      jj>=0 ? remv->changes[jj] : 0);
+    assert(!ec);
+    ec= meth->check(meth);
+    assert(!ec);
+  }
+  /* we do not need to unwind methods for which we are only removing
+   * since we never roll back after starting those */
+  return ec;
 }
 
+static void indep_execute(void) {
+  for (Method **methwalk= methods;
+       (meth= *methwalk);
+       methwalk++) {
+    meth->execute(meth);
+  }
+}
 
+static void indep_dispose(MovPosChange *indep) {
+  if (!indep) return;
+
+  for (int changei=0; changei<indep->n_changes; changei++) {
+      Change *chg= indep->changes[changei];
+      Method *meth= chg->meth;
+      if (chg)
+       meth->dispose(meth, chg);
+  }
+  free(indep);
+}
 
 ErrorCode
 movpos_reserve(Segment *move, int maxdelay_ms, MovPosChange **res_r,
               MovPosComb target, MovPosComb startpoint /*as for findcomb*/) {
-  MovFeatKind kind= mfk_none;
   ErrorCode ec;
-  int nchanges;
-
-  int n_changes;
-  Change *changes[N_METHODS];
+  MovPosChange *indep= 0;
 
   DPRINTF(movpos,reserve, "%s/%s maxdelay=%dms startpoint=%s\n",
          move->i->pname, movpos_pname(move,target),
          maxdelay_ms, movpos_pname(move,startpoint));
 
-  evaluate_target(move,target,startpoint, &n_changes,&changes);
-  
-
-  if (nchanges==-1) return EC_MovFeatKindsCombination;
+  ec= evaluate_target(move,target, startpoint,
+                     ms,1,
+                     &indep, 0);
+  if (ec) return ec;
 
-  Method *meth= methods[kind];
-  DPRINTF(movpos,reserve, "allocate %s:%d...\n",
-         meth->pname, nchanges);
-  Change *chg= mp_allocate(meth, move, nchanges, target);
-  ec= meth->reserve(meth, chg, move, maxdelay_ms);
-  DPRINTF(movpos,reserve, "reserve => %s\n",errorcodelist[ec]);
+  ec= indep_consider(0, indep);
   if (ec) goto x;
 
-  *res_r= chg;
+  indep_execute();
   return 0;
 
  x:
-  movpos_unreserve(chg);
+  indep_dispose(indep);
+  indep_execute();
   return ec;
 }
 
-
-
-
-
-static Change *mp_allocate(Method *meth, Segment *move,
-                          int alloc_motions, MovPosComb target) {
-  assert(sta_state >= Sta_Resolving || sta_state == Sta_Manual);
-  Change *chg= meth->allocate(meth, alloc_motions);
-  chg->meth=      meth;
-  chg->move=      move;
-  chg->intent=    target;
-  return chg;
-}
-
 static int change_needed(const MovFeatInfo *feati,
                         MovPosComb startpoint, MovPosComb target) {
   int r;
@@ -801,7 +905,7 @@ ErrorCode movpos_findcomb_bysegs(Segment *back, Segment *move, Segment *fwd,
                                 MovPosComb startpoint, MovPosComb *chosen_r) {
   const SegmentInfo *movei= move->i;
   MovPosComb tcomb, bestcomb=-1;
-  int tchanges, bestchanges=INT_MAX;
+  int tcost, bestcost=INT_MAX;
   const SegPosCombInfo *pci;
 
   for (tcomb=0, pci=movei->poscombs;
@@ -813,25 +917,24 @@ ErrorCode movpos_findcomb_bysegs(Segment *back, Segment *move, Segment *fwd,
     if (fwd  && !(fwd ==tback || fwd ==tfwd)) continue;
 
     /* we have to search for the one which is least effort */
-    tchanges= evaluate_target(move,tcomb,startpoint,0);
+    ec= evaluate_target(move,tcomb,startpoint, -1,0, 0,&tcost);
+    if (ec) return ec;
 
-    if (tchanges==-1)
-      /* mixed kinds */
-      tchanges= INT_MAX-1;
-
-    if (tchanges >= bestchanges) /* prefer low-numbered movposcombs */
+    if (tcost >= bestcost) /* prefer low-numbered movposcombs */
       continue;
 
     bestcomb= tcomb;
-    bestchanges= tchanges;
+    bestcost= tcost;
   }
   if (chosen_r) *chosen_r= bestcomb;
   return
-    bestchanges==INT_MAX ? EC_MovFeatRouteNotFound :
-    bestchanges==INT_MAX-1 ? EC_MovFeatKindsCombination :
+    bestcost==INT_MAX ? EC_MovFeatRouteNotFound :
     0;
 }
 
+
+NEW CODE UP TO HERE
+
 ErrorCode movpos_change(Segment *move, MovPosComb target,
                        int maxdelay_ms, MovPosChange *chg) {
   const SegmentInfo *movei= move->i;
@@ -860,21 +963,7 @@ ErrorCode movpos_change(Segment *move, MovPosComb target,
     int n_motions=0;
     Motion motions[movei->n_movfeats];
 
-    for (feat=0, feati=movei->movfeats;
-        feat<movei->n_movfeats;
-        feat++, feati++) {
-      if (!change_needed(feati,actual,target))
-       continue;
-      MovPosComb posn= target / feati->weight % feati->posns;
-      if (kind) {
-       if (feati->kind != kind) { ec= EC_MovFeatKindsCombination; goto x; }
-      } else {
-       kind= feati->kind;
-      }
-      motions[n_motions].i= feati;
-      motions[n_motions].posn= posn;
-      n_motions++;
-    }
+    there was code here to fill in motions
 
     Method *meth= methods[kind];
 
@@ -1077,3 +1166,14 @@ in points_all_abandon
  *
 
  * seg->moving and ->motion is in one of the states UC
+
+static Change *mp_allocate(Method *meth, Segment *move,
+                          int alloc_motions, MovPosComb target) {
+  assert(sta_state >= Sta_Resolving || sta_state == Sta_Manual);
+  Change *chg= meth->allocate(meth, alloc_motions);
+  chg->meth=      meth;
+  chg->move=      move;
+  chg->intent=    target;
+  return chg;
+}
+