atlas.c
Go to the documentation of this file.
1 #include "atlas.h"
2 
3 #include "defines.h"
4 #include "error.h"
5 #include "random.h"
6 #include "algebra.h"
7 #include "samples.h"
8 
9 #include <string.h>
10 #include <math.h>
11 #ifdef _OPENMP
12  #include <omp.h>
13 #endif
14 
25 /***************************************************************/
26 
32 typedef struct {
33  unsigned int st;
34  unsigned int nc;
36  unsigned int ns;
37  unsigned int ms;
38  double **path;
39 } TMinTrace;
40 
41 
42 
43 /***************************************************************/
44 
50 typedef struct {
51  double cost;
52  double heuristic;
53  unsigned int status;
54 } TAStarInfo;
55 
56 /***************************************************************/
57 
66 
75 
145 
162 
195 
208 
217 
229 
239 
249 
266 
267 /***********************************************************************/
268 /***********************************************************************/
269 /***********************************************************************/
270 
282 boolean HaveChartAtPoint(double eps,double *p,Tatlas *a);
283 
299 void PostProcessNewCharts(Tparameters *pr,boolean bif,unsigned int parentID,
300  TAtlasStatistics *st,Tatlas *a);
301 
327 void NewChartFromPoint(Tparameters *pr,unsigned int parentID,double *t,
328  Tchart **newChart,Tatlas *a);
329 
351 void ReconstructAtlasPath(Tparameters *pr,unsigned int *pred,
352  unsigned int mID,double *goal,unsigned int nv,
353  boolean *systemVars,
354  double *pl,unsigned int *ns,double ***path,Tatlas *a);
355 
395 boolean DetermineChartNeighbours(Tparameters *pr,boolean bif,
396  unsigned int cmID,unsigned int parentID,Tatlas *a);
397 
425 double GeodesicDistance(Tparameters *pr,unsigned int parentID,unsigned int childID,
426  Tatlas *a);
427 
436 void SetAtlasTopology(Tparameters *pr,Tatlas *a);
437 
438 /***********************************************************************/
439 /***********************************************************************/
440 /***********************************************************************/
441 
459 boolean DetectBifurcation(Tparameters *pr,unsigned int mID1,unsigned int mID2,Tatlas *a);
460 
482 boolean FindSingularPoint(Tparameters *pr,unsigned int bID,Tatlas *a);
483 
511 boolean RefineSingularPoint(Tparameters *pr,unsigned int bID,Tatlas *a);
512 
539 unsigned int FindRightNullVector(Tparameters *pr,unsigned int bID,
540  double **phi,Tatlas *a);
541 
542 
581 boolean FindPointInOtherBranch(Tparameters *pr,unsigned int bID,double *phi,double **p,Tatlas *a);
582 
583 
602 void DefineChartsAtBifurcation(Tparameters *pr,unsigned int bID,double *v,
603  TAtlasStatistics *ast,Tatlas *a);
604 
621 void ProcessBifurcation(Tparameters *pr,unsigned int bID,TAtlasStatistics *ast,Tatlas *a);
622 
631 void LoadBifurcations(FILE *f,Tatlas *a);
632 
641 void SaveBifurcations(FILE *f,Tatlas *a);
642 
659 void PlotBifurcations(Tparameters *pr,Tplot3d *p3d,
660  unsigned int xID,unsigned int yID,unsigned int zID,Tatlas *a);
661 
669 void DeleteBifurcations(Tatlas *a);
670 
671 /***********************************************************************/
672 /***********************************************************************/
673 /***********************************************************************/
674 
676 {
677  if (ast!=NULL)
678  {
679  ast->nExtensions=0;
680  ast->nBoundaryAttempts=0;
681  ast->nNotInBoundary=0;
682  ast->nLargeError=0;
683  ast->nNonRegularPoint=0;
684  ast->nNotInManifold=0;
685  ast->nQRSVDError=0;
686  ast->nFarFromParent=0;
687  ast->nInCollision=0;
688  ast->nRadiousChange=0;
689  ast->nGoodExtension=0;
690  ast->nImpossible=0;
691  ast->nSingImpossible=0;
692  ast->nBifurcations=0;
693  ast->nSmallAngle=0;
694  ast->nSPMissed=0;
695  ast->nNoSingularEnough=0;
696  ast->nNoJumpBranch=0;
697  }
698 }
699 
701 {
702  if (ast!=NULL)
703  ast->nExtensions++;
704 }
705 
707 {
708  if (ast!=NULL)
709  ast->nBoundaryAttempts++;
710 }
711 
713 {
714  if (ast!=NULL)
715  ast->nNotInBoundary++;
716 }
717 
719 {
720  if (ast!=NULL)
721  ast->nLargeError++;
722 }
723 
725 {
726  if (ast!=NULL)
727  ast->nNonRegularPoint++;
728 }
729 
731 {
732  if (ast!=NULL)
733  ast->nNotInManifold++;
734 }
735 
737 {
738  if (ast!=NULL)
739  ast->nQRSVDError++;
740 }
741 
743 {
744  if (ast!=NULL)
745  ast->nFarFromParent++;
746 }
747 
749 {
750  if (ast!=NULL)
751  ast->nInCollision++;
752 }
753 
755 {
756  if (ast!=NULL)
757  ast->nRadiousChange++;
758 }
759 
761 {
762  if (ast!=NULL)
763  ast->nGoodExtension++;
764 }
765 
767 {
768  if (ast!=NULL)
769  ast->nImpossible++;
770 }
771 
773 {
774  if (ast!=NULL)
775  ast->nSingImpossible++;
776 }
777 
779 {
780  if (ast!=NULL)
781  ast->nBifurcations++;
782 }
783 
785 {
786  if (ast!=NULL)
787  ast->nSmallAngle++;
788 }
789 
791 {
792  if (ast!=NULL)
793  ast->nSPMissed++;
794 }
795 
797 {
798  if (ast!=NULL)
799  ast->nNoSingularEnough++;
800 }
801 
803 {
804  if (ast!=NULL)
805  ast->nNoJumpBranch++;
806 }
807 
809 {
810  unsigned int db;
811 
812  if (ast!=NULL)
813  {
814  printf("Boundary attempts: %u\n",ast->nBoundaryAttempts);
815  printf(" Not in Boundary : %u (%3.2f)\n",
816  ast->nNotInBoundary,
817  100*(double)ast->nNotInBoundary/(double)ast->nBoundaryAttempts);
818  printf("Num Extensions : %u\n",ast->nExtensions);
819  printf(" Errors : %u (%3.2f)\n",
820  ast->nImpossible,
821  100*(double)ast->nImpossible/(double)ast->nExtensions);
822  printf(" Errors (Sing) : %u (%3.2f)\n",
823  ast->nSingImpossible,
824  100*(double)ast->nSingImpossible/(double)ast->nExtensions);
825  printf(" Large Error : %u (%3.2f)\n",
826  ast->nLargeError,
827  100*(double)ast->nLargeError/(double)ast->nExtensions);
828  printf(" Non-regular point : %u (%3.2f)\n",
829  ast->nNonRegularPoint,
830  100*(double)ast->nNonRegularPoint/(double)ast->nExtensions);
831  printf(" Not in Manifold : %u (%3.2f)\n",
832  ast->nNotInManifold,
833  100*(double)ast->nNotInManifold/(double)ast->nExtensions);
834  printf(" Decomp. Error : %u (%3.2f)\n",
835  ast->nQRSVDError,
836  100*(double)ast->nQRSVDError/(double)ast->nExtensions);
837  printf(" Far From Parent : %u (%3.2f)\n",
838  ast->nFarFromParent,
839  100*(double)ast->nFarFromParent/(double)ast->nExtensions);
840  printf(" Radius Changes : %u (%3.2f)\n",
841  ast->nRadiousChange,
842  100*(double)ast->nRadiousChange/(double)ast->nExtensions);
843  printf(" Collisions : %u (%3.2f)\n",
844  ast->nInCollision,
845  100*(double)ast->nInCollision/(double)ast->nExtensions);
846  printf(" Good ones : %u (%3.2f)\n",
847  ast->nGoodExtension,
848  100*(double)ast->nGoodExtension/(double)ast->nExtensions);
849 
850  db=(unsigned int)GetParameter(CT_DETECT_BIFURCATIONS,pr);
851  if (db==0)
852  printf("Bifurcation detection disabled\n");
853  else
854  {
855  printf("Detected bifurcations: %u\n",ast->nBifurcations);
856  if (ast->nBifurcations>0)
857  {
858  unsigned int n;
859 
860  n=(ast->nBifurcations-ast->nSPMissed-ast->nNoSingularEnough-ast->nNoJumpBranch);
861  printf(" Correct jumps : %u (%3.2f)\n",
862  n,100*n/(double)ast->nBifurcations);
863  if (n>0)
864  printf(" Num Small angle : %u (%3.2f)\n",ast->nSmallAngle,
865  100*(double)ast->nSmallAngle/(double)n);
866  printf(" Missed singular points: %u (%3.2f)\n",ast->nSPMissed,
867  100*(double)ast->nSPMissed/(double)ast->nBifurcations);
868  printf(" Not enough singular : %u (%3.2f)\n",ast->nNoSingularEnough,
869  100*(double)ast->nNoSingularEnough/(double)ast->nBifurcations);
870  printf(" Error jumping : %u (%3.2f)\n",ast->nNoJumpBranch,
871  100*(double)ast->nNoJumpBranch/(double)ast->nBifurcations);
872  }
873  }
874  }
875 }
876 
877 /***********************************************************************/
878 /***********************************************************************/
879 /***********************************************************************/
880 
881 boolean HaveChartAtPoint(double eps,double *p,Tatlas *a)
882 {
883  boolean found;
884 
885  #if (USE_ATLAS_TREE)
886  found=PointInBTree(eps,p,&(a->tree));
887  #else
888  unsigned int i;
889  double e2,d;
890 
891  found=FALSE;
892  e2=eps*eps;
893  for(i=0;((!found)&&(i<a->currentChart));i++)
894  {
895  d=SquaredDistanceTopologyMin(e2,a->m,a->tp,
896  p,GetChartCenter(a->charts[i]));
897  found=(d<e2);
898  }
899  #endif
900  return(found);
901 }
902 
903 void PostProcessNewCharts(Tparameters *pr,boolean bif,unsigned int parentID,
904  TAtlasStatistics *st,Tatlas *a)
905 {
906  unsigned int i;
907 
908  for(i=a->npCharts;i<a->currentChart;i++)
909  {
910  if (!DetermineChartNeighbours(pr,bif,i,parentID,a))
911  Warning("Bifurcation undetected in PostProcessNewCharts. Redude epsilon?");
912  }
913  a->npCharts=a->currentChart;
914 
915  /* If parentID is NO_UINT we are defining charts at a bifurcation (we are inside
916  ProcessBifurcation) and, thus, we have to avoid infitinte loops. */
917  if (parentID!=NO_UINT)
918  {
919  /* if bif==FALSE no new bifurcations will be detected and, thus, the code
920  below is not used (nBifurcations==npBifurcations). In some cases, though
921  bifurcations are detected externally (see AddChart2AtlasNS) and, thus
922  they are processed here. */
923  for(i=a->npBifurcations;i<a->nBifurcations;i++)
924  ProcessBifurcation(pr,i,st,a);
926  }
927 }
928 
929 void NewChartFromPoint(Tparameters *pr,unsigned int parentID,double *t,
930  Tchart **newChart,Tatlas *a)
931 {
932  /* If the vertex is already inside the ball, we are refining the approximation of the
933  domain border. Thus, we have to avoid the eventual creation of new charts.*/
934  if (Norm(a->k,t)<0.99*a->r)
935  *newChart=NULL;
936  else
937  {
938  double s;
939  boolean canContinue,chartCreated,smallError,closeEnough,wrong,outOfDomain;
940  double *pt,*ct;
941  unsigned int chartCode;
942  double epsilon;
943 
944  NEW(pt,a->m,double);
945 
946  NEW(*newChart,1,Tchart);
947 
948  /* current set of parameters */
949  NEW(ct,a->k,double);
950 
951  epsilon=GetParameter(CT_EPSILON,pr);
952 
953  s=1.0;
954  canContinue=TRUE;
955  chartCreated=FALSE;
956  closeEnough=FALSE;
957  smallError=FALSE;
958  outOfDomain=FALSE;
959 
960  do {
961  /* update the current set of paremter (ct) using the given parameters (t)
962  and the current scale factor (s) */
963  memcpy(ct,t,a->k*sizeof(double));
964  ScaleVector(s,a->k,ct);
965 
966  smallError=(Chart2Manifold(pr,&(a->J),ct,NULL,NULL,pt,a->charts[parentID])<=a->e);
967 
968  if (smallError)
969  {
970  chartCode=InitChart(pr,a->simpleChart,a->ambient,a->tp,
971  a->m,a->k,pt,a->e,a->ce,a->r,&(a->J),a->w,
972  *newChart);
973  chartCreated=(chartCode==0);
974 
975  if (chartCreated)
976  {
977  if ((CollisionChart(*newChart))||
978  (!PointInBoxTopology(NULL,TRUE,a->m,pt,epsilon,a->tp,a->ambient))||
979  (!CS_WD_SIMP_INEQUALITIES_HOLD(pr,pt,a->w)))
980  outOfDomain=TRUE;
981  else
982  closeEnough=(CloseCharts(pr,a->tp,
983  a->charts[parentID],
984  *newChart));
985  }
986  }
987 
988  if (!outOfDomain)
989  {
990  wrong=((!smallError)||(!chartCreated)||(!closeEnough));
991 
992  if (wrong)
993  {
994  canContinue=(s>MIN_SAMPLING_RADIUS);
995  if (canContinue)
996  {
998 
999  /* We will create a new chart -> delete the just generated one, if any */
1000  if (chartCreated)
1001  {
1002  DeleteChart(*newChart);
1003  chartCreated=FALSE;
1004  }
1005  }
1006  }
1007  }
1008  } while((!outOfDomain)&&(wrong)&&(canContinue));
1009 
1010  /* If we didn't manage to create the new chart, we remove any possibly created chart. */
1011  if ((outOfDomain)||(!canContinue))
1012  {
1013  if (outOfDomain)
1014  ChartIsFrontier(a->charts[parentID]);
1015  if (chartCreated)
1016  DeleteChart(*newChart);
1017  free(*newChart);
1018  *newChart=NULL;
1019  }
1020  free(ct);
1021  free(pt);
1022  }
1023 }
1024 
1025 boolean ExtendAtlasFromPoint(Tparameters *pr,unsigned int parentID,double *t,
1026  TAtlasStatistics *st,Tatlas *a)
1027 {
1028  double s;
1029  boolean canContinue,canInitChart,smallError,closeEnough,wrong;
1030  boolean searchBorder,inside;
1031  double *pt,*ct;
1032  boolean ok;
1033  unsigned int chartCode;
1034  double epsilon;
1035  #if (!SIMPLE_BORDER)
1036  boolean outOfDomain;
1037  double l,u;
1038  #endif
1039 
1040  ok=FALSE; /* No new chart is generated */
1041 
1042  NEW(pt,a->m,double);
1043 
1044  if (a->currentChart==a->maxCharts)
1045  MEM_DUP(a->charts,a->maxCharts,Tchart *);
1046 
1047  NEW(a->charts[a->currentChart],1,Tchart);
1048 
1049  /* current set of parameters */
1050  NEW(ct,a->k,double);
1051 
1052  /* If the vertex is already inside the ball, we are refining the approximation of the
1053  domain border. Thus, we have to avoid the eventual creation of new charts.*/
1054  inside=(Norm(a->k,t)<0.99*a->r);
1055 
1056  epsilon=GetParameter(CT_EPSILON,pr);
1057 
1058  s=1.0;
1059  canContinue=TRUE;
1060  canInitChart=FALSE;
1061  closeEnough=FALSE;
1062  smallError=FALSE;
1063  searchBorder=FALSE;
1064  #if (!SIMPLE_BORDER)
1065  outOfDomain=FALSE;
1066  #endif
1067 
1068  do {
1069  NewAtlasExtension(st);
1070 
1071  canInitChart=FALSE; /* Just to indicate that no chart has been created so far in this iteration */
1072 
1073  /* update the current set of paremter (ct) using the given parameters (t)
1074  and the current scale factor (s) */
1075  memcpy(ct,t,a->k*sizeof(double));
1076  ScaleVector(s,a->k,ct);
1077 
1078  smallError=(Chart2Manifold(pr,&(a->J),ct,NULL,NULL,pt,a->charts[parentID])<=a->e);
1079 
1080  if (smallError)
1081  {
1082  /* We skip the chart construction during the dichotomic search for the border.
1083  A valid chart was already been defined when triggering the search. */
1084  if (searchBorder)
1085  {
1086  #if (!SIMPLE_BORDER)
1087  outOfDomain=((!PointInBoxTopology(NULL,TRUE,a->m,pt,epsilon,a->tp,a->ambient))||
1088  (!CS_WD_SIMP_INEQUALITIES_HOLD(pr,pt,a->w)));
1089  if (!outOfDomain)
1090  CS_WD_IN_COLLISION(outOfDomain,pr,pt,NULL,a->w);
1091  #endif
1092 
1093  chartCode=NO_UINT; /* -> chart actually not created */
1094  }
1095  else
1096  {
1097  chartCode=InitChart(pr,a->simpleChart,a->ambient,a->tp,
1098  a->m,a->k,pt,a->e,a->ce,a->r,&(a->J),a->w,
1099  a->charts[a->currentChart]);
1100  canInitChart=(chartCode==0);
1101 
1102  if (canInitChart)
1103  {
1104  if ((CollisionChart(a->charts[a->currentChart]))||
1105  (!PointInBoxTopology(NULL,TRUE,a->m,pt,epsilon,a->tp,a->ambient))||
1106  (!CS_WD_SIMP_INEQUALITIES_HOLD(pr,pt,a->w)))
1107  {
1108  #if (!SIMPLE_BORDER)
1109  outOfDomain=TRUE;
1110  #endif
1111  searchBorder=TRUE;
1112  #if (!SIMPLE_BORDER)
1113  l=0;
1114  u=s;
1115  #endif
1116  }
1117  else
1118  {
1119  #if (!SIMPLE_BORDER)
1120  outOfDomain=FALSE;
1121  #endif
1122 
1123  closeEnough=(CloseCharts(pr,a->tp,
1124  a->charts[parentID],
1125  a->charts[a->currentChart]));
1126  if (!closeEnough)
1127  {
1128  NewFarFromParent(st);
1129  searchBorder=FALSE; /* if searching for border -> stop the search */
1130  }
1131  else
1132  NewGoodExtension(st);
1133  }
1134  }
1135  else
1136  {
1137  switch (chartCode)
1138  {
1139  case 1:
1140  case 2:
1141  NewNonRegularPoint(st);
1142  break;
1143  case 3:
1145  break;
1146  case 4:
1147  NewNotInManifold(st);
1148  break;
1149  default:
1150  Error("Unknown chart creation error code");
1151  }
1152  }
1153  }
1154  }
1155  else
1156  {
1157  NewLargeError(st);
1158  searchBorder=FALSE; /* if searching for border -> stop the search */
1159  }
1160 
1161  wrong=((searchBorder)||(!smallError)||(!canInitChart)||(!closeEnough));
1162 
1163  if (wrong)
1164  {
1165  /* If something when wrong but we created a chart -> delete it */
1166  if (canInitChart)
1167  {
1169  canInitChart=FALSE; /* this indicates that the chart is already deleted */
1170  }
1171 
1172  if (searchBorder)
1173  {
1174  /* dichotomic search for the border */
1175  #if (SIMPLE_BORDER)
1176  /* Simple boder -> vertices out of the domain are marked as such
1177  and no refinement is triggered. */
1178  canContinue=FALSE;
1179  #else
1180  canContinue=((u-l)>MIN_SAMPLING_RADIUS);
1181  if (canContinue)
1182  {
1183  if (outOfDomain)
1184  u=s;
1185  else
1186  l=s;
1187  s=(u+l)/2.0;
1188  }
1189  #endif
1190  }
1191  else
1192  {
1193  canContinue=(s>MIN_SAMPLING_RADIUS);
1194  if (canContinue)
1195  {
1197  NewRadiousChange(st);
1198  }
1199  }
1200  }
1201  } while((wrong)&&(canContinue));
1202 
1203  if (searchBorder)
1204  {
1205  #if (!SIMPLE_BORDER)
1206  /* Define a linear constraint to the parent chart along the border */
1207  AddBorderConstraint(pr,ct,a->tp,a->ambient,a->charts[parentID]);
1208  #endif
1209 
1210  ChartIsFrontier(a->charts[parentID]);
1211  }
1212  else
1213  {
1214  if (!inside)
1215  {
1216  if (!canContinue)
1217  {
1218  if (SingularChart(a->charts[parentID]))
1219  {
1221  printf(" Could not extend singular chart\n");
1222  }
1223  else
1224  {
1225  //Error("The impossible happened (I)");
1226  NewImpossible(st);
1227  }
1228  }
1229  else
1230  {
1231  #if (ATLAS_VERBOSE)
1232  printf(" New Chart %u [p:%u]\n",a->currentChart,parentID);
1233  #endif
1234  a->currentChart++;
1235  PostProcessNewCharts(pr,TRUE,parentID,st,a);
1236  ok=TRUE; /* We actually generated a new chart */
1237  }
1238  }
1239  }
1240 
1241  /* If no chart is actually generated, just release the allocated memory */
1242  if (!ok)
1243  {
1244  /* Just in case we cancelled the chart */
1245  if (canInitChart)
1247  free(a->charts[a->currentChart]);
1248  }
1249 
1250  free(ct);
1251  free(pt);
1252 
1253  return(ok);
1254 }
1255 
1256 boolean ExtendAtlasTowardPoint(Tparameters *pr,unsigned int parentID,double *t,
1257  boolean collisionStops,
1258  TAtlasStatistics *st,Tatlas *a)
1259 {
1260  double delta,s;
1261  double *tp,*pt,*ptGood;
1262  Tchart mTmp;
1263  boolean moved,inCollision,canInitChart,smallError,closeEnough;
1264  double r,n;
1265  unsigned int chartCode;
1266  double currentDelta;
1267  double epsilon;
1268 
1269  NEW(pt,a->m,double);
1270  NEW(tp,a->k,double);
1271  /* ptGood is the last point where we managed to generate a valid chart.
1272  Inintially, the center of the current chart but we try to move
1273  far from here. */
1274  NEW(ptGood,a->m,double);
1275  memcpy(ptGood,GetChartCenter(a->charts[parentID]),a->m*sizeof(double));
1276 
1277  n=Norm(a->k,t);
1278  r=GetChartRadius(a->charts[parentID]);
1279  epsilon=GetParameter(CT_EPSILON,pr);
1280  delta=GetParameter(CT_DELTA,pr);
1281  s=0.0; /* how much we advanced so far */
1282  currentDelta=delta; /* size of current step */
1283 
1284  inCollision=FALSE;
1285  canInitChart=TRUE;
1286  closeEnough=TRUE;
1287  smallError=TRUE;
1288  moved=FALSE;
1289 
1290  /* When extending a chart it is crucial to be able to generate at least
1291  one point in the given direction (except if there is an obstacle
1292  blocking this direction). Once we have at least one point in the
1293  given direction, we can generate a new chart on it that extends
1294  the atlas. Therefore we carefully adjust the advance step
1295  in case we are in a problematic area (singular, large curvature). */
1296  do {
1297  NewAtlasExtension(st);
1298  NewRadiousChange(st);
1299  /* See if vector t scaled by 's' is collision free and has small error */
1300  memcpy(tp,t,a->k*sizeof(double));
1301  ScaleVector((s+currentDelta)/n,a->k,tp);
1302 
1303  smallError=(Chart2Manifold(pr,&(a->J),tp,NULL,ptGood,pt,a->charts[parentID])<=a->e);
1304 
1305  if (smallError)
1306  {
1307  chartCode=InitChart(pr,a->simpleChart,a->ambient,a->tp,
1308  a->m,a->k,pt,a->e,a->ce,a->r,
1309  &(a->J),a->w,&mTmp);
1310  canInitChart=(chartCode==0);
1311 
1312  if (canInitChart)
1313  {
1314  closeEnough=(CloseCharts(pr,a->tp,a->charts[parentID],&mTmp));
1315  if (closeEnough)
1316  {
1317  if (collisionStops)
1318  inCollision=CollisionChart(&mTmp);
1319 
1320  if (!inCollision)
1321  {
1322  moved=TRUE;
1323  /* consolidate the advance */
1324  s+=currentDelta;
1325 
1326  /* If we moved beyond the chart radious-> stop here */
1327  if (s>=r)
1328  smallError=FALSE;
1329 
1330  /* Store the just generated valid point (this is how
1331  far we managed to get so far). */
1332  memcpy(ptGood,pt,sizeof(double)*a->m);
1333 
1334  NewGoodExtension(st);
1335 
1336  if (currentDelta!=delta)
1337  {
1338  /* We managed to generate a problematic
1339  initial point -> stop here */
1340  closeEnough=FALSE;
1341  }
1342  }
1343  else
1344  NewInCollision(st);
1345  }
1346  else
1347  NewFarFromParent(st);
1348  DeleteChart(&mTmp);
1349  }
1350  else
1351  {
1352  switch (chartCode)
1353  {
1354  case 1:
1355  case 2:
1356  NewNonRegularPoint(st);
1357  break;
1358  case 3:
1360  break;
1361  case 4:
1362  NewNotInManifold(st);
1363  break;
1364  default:
1365  Error("Unknown chart creation error code");
1366  }
1367  }
1368  }
1369  else
1370  NewLargeError(st);
1371 
1372  /* If not moved (i.e., we do not have a good point)
1373  for a reason different from a collision, try to
1374  adjust the avance step */
1375  if ((!moved)&&(!inCollision))
1376  {
1377  /* If we are not trying to jump over a singularity */
1378  if (currentDelta<=delta)
1379  {
1380  if (currentDelta>epsilon)
1381  {
1382  /* We are trying to generate the first point in
1383  a difficult area (singular or with very high
1384  curvature). Try to reduce the advance step with
1385  the purpose of finding a point just outside this
1386  problematic area. Note that the center of the
1387  current chart is outside this area and, thus
1388  we try to approach it.
1389  */
1390  currentDelta*=0.5;
1391  canInitChart=TRUE;
1392  smallError=TRUE;
1393  closeEnough=TRUE;
1394  }
1395  else
1396  {
1397  if (!canInitChart) /* assume charCode==1 */
1398  {
1399  /* We are in a singular area and the current
1400  chart is just at the border of this singular
1401  area (we can not create any other chart closer
1402  to the singular area). In this case we try
1403  to jump over the singular area with a large
1404  jump. Note that this can produce some
1405  collisions that are not detected. This large
1406  jump is only tried once. If it does not work
1407  the extension is declared a failure and a warning
1408  is issued.
1409 
1410  In theory, singularities are zero volum areas but
1411  in practice they have some thickness that is given
1412  by the used numerical accuracy (epsilon)
1413  */
1414  currentDelta=5*delta;
1415  canInitChart=TRUE;
1416  smallError=TRUE;
1417  closeEnough=TRUE;
1418  }
1419  }
1420  }
1421  }
1422 
1423  } while((smallError)&&(canInitChart)&&(closeEnough)&&(!inCollision));
1424 
1425  if (!moved)
1426  {
1427  /* Could not extend at all */
1428  if (!inCollision)
1429  {
1430  if ((currentDelta>delta)||(!canInitChart)||(SingularChart(a->charts[parentID])))
1431  {
1433  printf(" Could not jump over a singularity (decrease epsilon?)");
1434  }
1435  else
1436  {
1437  /* !smallError or !closeEnough */
1438  NewImpossible(st);
1439  Error(" The impossible happened (II)");
1440  }
1441  }
1442  }
1443  else
1444  {
1445  /* Generate the new chart. In the case where extending the atlas in parallel,
1446  this part has to be executed sequentially. */
1447  if (a->currentChart==a->maxCharts)
1448  MEM_DUP(a->charts,a->maxCharts,Tchart *);
1449 
1450  NEW(a->charts[a->currentChart],1,Tchart);
1451 
1452  if (InitChart(pr,a->simpleChart,a->ambient,a->tp,
1453  a->m,a->k,ptGood,a->e,a->ce,a->r,
1454  &(a->J),a->w,a->charts[a->currentChart])!=0)
1455  Error("Can not create a chart already created just above?");
1456 
1457  #if (ATLAS_VERBOSE)
1458  printf(" New Chart %u\n",a->currentChart);
1459  #endif
1460 
1461  a->currentChart++;
1462  PostProcessNewCharts(pr,TRUE,parentID,st,a);
1463  }
1464 
1465  free(pt);
1466  free(ptGood);
1467  free(tp);
1468 
1469  return(moved);
1470 }
1471 
1472 void ReconstructAtlasPath(Tparameters *pr,unsigned int *pred,
1473  unsigned int mID,double *goal,unsigned int nv,
1474  boolean *systemVars,
1475  double *pl,unsigned int *ns,double ***path,Tatlas *a)
1476 {
1477  unsigned int nvs,i,k;
1478  unsigned int ms;
1479  unsigned int *chartID;
1480  signed int s;
1481  double *t,*o;
1482  Tchart *cp,*c;
1483 
1484  *pl=0;
1485 
1486  NEW(t,a->k,double);
1487 
1488  nvs=0;
1489  for(i=0;i<nv;i++)
1490  {
1491  if (systemVars[i])
1492  nvs++;
1493  }
1494 
1495  InitSamples(&ms,ns,path);
1496 
1497  /* Count the number of charts to be visited along the path */
1498  i=mID;
1499  k=0;
1500  while (i!=NO_UINT)
1501  {
1502  k++;
1503  i=pred[i];
1504  }
1505 
1506  /* Store the charts to be visited along the path (in the correct
1507  order) */
1508  NEW(chartID,k,unsigned int);
1509  s=k-1;
1510  i=mID;
1511  while (i!=NO_UINT)
1512  {
1513  chartID[s]=i;
1514  s--;
1515  i=pred[i];
1516  }
1517 
1518  /* Reconstruct the path in each chart (from the center of the
1519  chart to the projection of the center of next chart) */
1520  cp=a->charts[chartID[0]];
1521  for(i=1;i<k;i++)
1522  {
1523  c=a->charts[chartID[i]];
1524  Manifold2Chart(GetChartCenter(c),a->tp,t,cp);
1525  #if (_DEBUG>4)
1526  printf(" Step to %u %f\n",chartID[i],Norm(a->k,t));
1527  #endif
1528  if (!PathInChart(pr,t,a->tp,&(a->J),nvs,systemVars,&ms,pl,ns,path,cp))
1529  {
1530  if (ATLAS_VERBOSE)
1531  Warning("Collision when reconstructing path in atlas");
1532  }
1533  cp=c;
1534  }
1535 
1536  /* And now the path on last chart to the goal */
1537  Manifold2Chart(goal,a->tp,t,cp);
1538  #if (_DEBUG>4)
1539  printf(" Last step %f\n",Norm(a->k,t));
1540  #endif
1541  if (!PathInChart(pr,t,a->tp,&(a->J),nvs,systemVars,&ms,pl,ns,path,cp))
1542  {
1543  if (ATLAS_VERBOSE)
1544  Warning("Collision when reconstructing path in atlas");
1545  }
1546 
1547  /* and add the goal */
1548  CS_WD_REGENERATE_ORIGINAL_POINT(pr,goal,&o,c->w);
1549  AddSample2Samples(nv,o,nvs,systemVars,&ms,ns,path);
1550  free(o);
1551 
1552  free(chartID);
1553  free(t);
1554 }
1555 
1556 boolean DetermineChartNeighbours(Tparameters *pr,boolean bif,
1557  unsigned int cmID,unsigned int parentID,
1558  Tatlas *a)
1559 {
1560  unsigned int i;
1561  unsigned int db;
1562  boolean singular;
1563 
1564  singular=FALSE;
1565 
1566  db=(unsigned int)GetParameter(CT_DETECT_BIFURCATIONS,pr);
1567 
1568  if ((a->n==0)||(db==0))
1569  /* Overide the caller setting if we do not want to detect bifurcations */
1570  bif=FALSE;
1571 
1572  if (ChartNumNeighbours(a->charts[cmID])>0)
1573  Error("DetermineChartNeighbours must be used for charts without any neighbour.");
1574 
1575  #if (USE_ATLAS_TREE)
1576  unsigned int nn=0,id;
1577  unsigned int *n=NULL;
1578  boolean intersectWithParent;
1579 
1580  SearchInBtree(a->charts[cmID],&nn,&n,&(a->tree));
1581  intersectWithParent=FALSE;
1582 
1583  for(i=0;i<nn;i++)
1584  {
1585  id=n[i];
1586 
1587  if (id==cmID)
1588  Error("The chart was not supposed to be in the tree");
1589 
1590  #if (_DEBUG>3)
1591  if (Distance(a->m,GetChartCenter(a->charts[cmID]),GetChartCenter(a->charts[id]))<1e-8)
1592  Error("Repeated chart center");
1593  #endif
1594 
1595  if (IntersectCharts(pr,a->tp,a->ambient,
1596  id,a->charts[id],cmID,a->charts[cmID]))
1597  {
1598  #if (ATLAS_VERBOSE)
1599  fprintf(stderr," Chart %u intersects with chart %u [parent %u]\n",cmID,id,parentID);
1600  #endif
1601  if ((bif)&&((db>1)||(parentID==NO_UINT)||(id==parentID)))
1602  singular|=(!DetectBifurcation(pr,cmID,id,a)); /* id=parent*/
1603 
1604  if (id==parentID)
1605  intersectWithParent=TRUE;
1606  }
1607  }
1608 
1609  if ((parentID!=NO_UINT)&&(!intersectWithParent))
1610  Error("A chart that does not intersect with its parent (1)");
1611 
1612  if (nn>0)
1613  free(n);
1614 
1615  /* We add the chart to the tree at the end to avoid self-intersection. */
1616  AddChart2Btree(cmID,a->charts[cmID],&(a->tree));
1617  #else
1618  for(i=0;i<a->currentChart;i++)
1619  {
1620  if (i!=cmID)
1621  {
1622  if (IntersectCharts(pr,a->tp,a->ambient,
1623  i,a->charts[i],cmID,a->charts[cmID]))
1624  {
1625 
1626  #if (ATLAS_VERBOSE)
1627  fprintf(stderr," Chart %u intersects with chart %u\n",cmID,i);
1628  #endif
1629  if ((bif)&&((db>1)||(parentID==NO_UINT)||(i==parentID)))
1630  singular|=(!DetectBifurcation(pr,cmID,i,a));
1631  }
1632  else
1633  {
1634  if (i==parentID)
1635  Error("A chart that does not intersect with its parent (2)");
1636  }
1637  }
1638  }
1639  #endif
1640 
1641  return(!singular);
1642 }
1643 
1644 double GeodesicDistance(Tparameters *pr,unsigned int parentID,unsigned int childID,
1645  Tatlas *a)
1646 {
1647  double d;
1648 
1649  if (a->n==0)
1650  d=DistanceTopology(a->m,a->tp,
1651  GetChartCenter(a->charts[parentID]),
1652  GetChartCenter(a->charts[childID]));
1653  else
1654  {
1655  double *v,*pt,*ptPrev;
1656  Tchart *c;
1657  double *start,*goal;
1658  double dStep;
1659  double delta;
1660  boolean projectionOk,inCollision,reached;
1661  unsigned int step;
1662  #if (PROJECT_WITH_PLANE)
1663  double *ptp;
1664  #endif
1665 
1666  NEW(v,a->m,double);
1667  NEW(pt,a->m,double);
1668  NEW(ptPrev,a->m,double);
1669  #if (PROJECT_WITH_PLANE)
1670  NEW(ptp,a->m,double);
1671  #endif
1672 
1673  c=a->charts[parentID];
1674  start=GetChartCenter(c);
1675  goal=GetChartCenter(a->charts[childID]);
1676 
1677  DifferenceVectorTopology(a->m,a->tp,goal,start,v);
1678 
1679  delta=GetParameter(CT_DELTA,pr);
1680  d=0.0;
1681  step=1;
1682  memcpy(ptPrev,start,a->m*sizeof(double));
1683 
1684  projectionOk=TRUE;
1685  inCollision=FALSE;
1686  reached=FALSE;
1687 
1688  while((projectionOk)&&(!inCollision)&&(!reached)&&(d<INF))
1689  {
1690  SumVectorScale(a->m,start,(double)step*delta,v,pt);
1691 
1692  #if (PROJECT_WITH_PLANE)
1693  memcpy(ptp,pt,a->m*sizeof(double));
1694  projectionOk=Newton2ManifoldPlane(pr,ptp,v,ptPrev,pt,a);
1695  #else
1696  projectionOk=(CS_WD_NEWTON_IN_SIMP(pr,pt,a->w)!=DIVERGED);
1697  #endif
1698 
1699  if (projectionOk)
1700  {
1701  CS_WD_IN_COLLISION(inCollision,pr,pt,ptPrev,a->w);
1702 
1703  if (!inCollision)
1704  {
1705  dStep=DistanceTopology(a->m,a->tp,ptPrev,pt);
1706  if (dStep<(delta/100.0))
1707  d=INF; /* The advance is stalled-> declare impossible path */
1708  else
1709  {
1710  d+=dStep;
1711  memcpy(ptPrev,pt,a->m*sizeof(double));
1712  reached=(DistanceTopology(a->m,a->tp,pt,goal)<delta);
1713  }
1714  }
1715  else
1716  {
1717  d=INF;
1718  //printf("d[%u,%u]=INF due to collision (%u)\n",parentID,childID,step);
1719  }
1720  }
1721  else
1722  {
1723  /* This should never happen. We print a message to warn */
1724  d=INF;
1725  //printf("d[%u,%u]=INF due to not convergence (%u)\n",parentID,childID,step);
1726  }
1727 
1728  step++;
1729  }
1730 
1731  //if (d<INF)
1732  // printf("d[%u,%u]=%g\n",parentID,childID,d);
1733 
1734  free(v);
1735  free(pt);
1736  free(ptPrev);
1737  #if (PROJECT_WITH_PLANE)
1738  free(ptp);
1739  #endif
1740  }
1741  return(d);
1742 }
1743 
1744 /******************************************************************/
1745 /******************************************************************/
1746 /******************************************************************/
1747 
1748 boolean DetectBifurcation(Tparameters *pr,unsigned int mID1,unsigned int mID2,Tatlas *a)
1749 {
1750  double *T;
1751  Tchart *mp1,*mp2;
1752  unsigned int d1,d2;
1753  boolean singular,singular1,singular2;
1754 
1755  singular=FALSE;
1756 
1757  mp1=a->charts[mID1];
1758  mp2=a->charts[mID2];
1759 
1760  if ((!SingularChart(mp1))&&(!SingularChart(mp2)))
1761  {
1762  T=GetChartTangentSpace(mp1);
1763  d1=GetChartDegree(pr,T,&(a->J),&singular1,mp1);
1764  d2=GetChartDegree(pr,T,&(a->J),&singular2,mp2);
1765 
1766  singular=((singular1)||(singular2));
1767 
1768  #if (_DEBUG>4)
1769  printf(" *Degree of chart %u -> %u [%u]\n",mID1,d1,singular1);
1770  printf(" -Degree of chart %u -> %u [%u]\n",mID2,d2,singular2);
1771  #endif
1772 
1773  /* When very close to a singularity, the chart might be declared
1774  non singular in creation but be singular in practice when
1775  computing it degree. */
1776  if ((!singular1)&&(!singular2)&&(d1!=d2))
1777  {
1778  if (a->nBifurcations==a->mBifurcations)
1780 
1782  a->bifurcation[a->nBifurcations]->mID1=mID1;
1783  a->bifurcation[a->nBifurcations]->d1=d1;
1784  a->bifurcation[a->nBifurcations]->mID2=mID2;
1785  a->bifurcation[a->nBifurcations]->d2=d2;
1786  a->bifurcation[a->nBifurcations]->p=NULL;
1787  a->nBifurcations++;
1788  }
1789  }
1790  return(!singular);
1791 }
1792 
1793 boolean FindSingularPoint(Tparameters *pr,unsigned int bID,Tatlas *a)
1794 {
1795  /* Detect the singularity point */
1796  unsigned int degreeLow,degreeUp,degree;
1797  double *d,*tg1,*tg2,*p,*T;
1798  boolean done,error;
1799  Tchart tmpM,*m1,*m2;
1800  double epsilon;
1801  unsigned int nm;
1802  double t,tLow,tUp;
1803  double c1,c2;
1804  boolean singular;
1805  double *p1,*p2,*tg;
1806 
1807  epsilon=GetParameter(CT_EPSILON,pr);
1808 
1809  degreeLow=a->bifurcation[bID]->d1;
1810  degreeUp =a->bifurcation[bID]->d2;
1811 
1812  if (degreeLow==degreeUp)
1813  Error("Degrees must be different at FindSingularPoint");
1814 
1815  m1=a->charts[a->bifurcation[bID]->mID1];
1816  m2=a->charts[a->bifurcation[bID]->mID2];
1817 
1818  NEW(tg1,a->k,double);
1819  NEW(tg2,a->k,double);
1820 
1821  NEW(p1,a->m,double);
1822  memcpy(p1,GetChartCenter(m1),a->m*sizeof(double));
1823  Manifold2Chart(p1,a->tp,tg1,m1); /*tg1 is zero*/
1824 
1825  NEW(p2,a->m,double);
1826  memcpy(p2,GetChartCenter(m2),a->m*sizeof(double));
1827  Manifold2Chart(p2,a->tp,tg2,m1);
1828 
1829  T=GetChartTangentSpace(m1);
1830 
1831  NEW(d,a->k,double);
1832  NEW(tg,a->k,double);
1833  NEW(p,a->m,double);
1834  memcpy(p,p2,a->m*sizeof(double));
1835 
1836  done=FALSE;
1837  error=FALSE;
1838  if (CompareTangentSpaces(m1,m2))
1839  error=FALSE;
1840  else
1841  {
1842  printf(" Incompatible initial charts in FindSingularPoint\n");
1843  error=TRUE;
1844  }
1845 
1846  DifferenceVector(a->k,tg2,tg1,d);
1847  tLow=0.0;
1848  tUp=1.0;
1849 
1850  while((!done)&&(!error))
1851  {
1852  t=tLow+(tUp-tLow)*0.5;
1853 
1854  SumVectorScale(a->k,tg1,t,d,tg);
1855 
1856  if (Chart2Manifold(pr,&(a->J),tg,NULL,p,p,m1)>a->e)
1857  error=TRUE;
1858 
1859  if ((!done)&&(!error))
1860  {
1861  /* Some of the chart generated in the search might be almost singular. We
1862  do not trigger an error if they are singular but we do not force the
1863  chart to be singular anyway. Just use the information from the numerical
1864  procedure without pre-defining if the point is regular or not. */
1866  a->m,a->k,p,a->e,a->ce,a->r,&(a->J),a->w,&tmpM);
1867 
1868  if (nm<2) /* 0: no error 1: singular chart */
1869  {
1870  if (SingularChart(&tmpM))
1871  done=TRUE;
1872  else
1873  {
1874  c1=MinCosinusBetweenCharts(m1,&tmpM);
1875  c2=MinCosinusBetweenCharts(&tmpM,m2);
1876 
1877  if ((c1<(1-a->ce))||(c2<(1-a->ce)))
1878  {
1879  /* This is typically the case where, accidentally, we ended up
1880  in the other branch */
1881  fprintf(stderr," Could not find singular point. Large tangent error %f (%f %f)\n",tUp-tLow,c1,c2);
1882  error=TRUE;
1883  }
1884  else
1885  {
1886  degree=GetChartDegree(pr,T,&(a->J),&singular,&tmpM);
1887 
1888  if (singular)
1889  done=TRUE;
1890  else
1891  {
1892  if (degree==degreeLow)
1893  {
1894  tLow=t;
1895  memcpy(p1,p,a->m*sizeof(double));
1896  }
1897  else
1898  {
1899  if (degree==degreeUp)
1900  {
1901  tUp=t;
1902  memcpy(p2,p,a->m*sizeof(double));
1903  }
1904  else
1905  Error("Incoherent degree change");
1906  }
1907 
1908  done=((tUp-tLow)<100*epsilon);
1909  }
1910  }
1911  }
1912  DeleteChart(&tmpM);
1913  }
1914  else
1915  Error("Error initializing a new chart in FindSingularPoint");
1916  }
1917  }
1918  if (!error)
1919  {
1920  NEW(a->bifurcation[bID]->p,a->m,double);
1921  memcpy(a->bifurcation[bID]->p,p,a->m*sizeof(double));
1922 
1923  /* Try to improve the singular point estimation */
1924  //RefineSingularPoint(pr,bID,a);
1925  }
1926 
1927  free(tg);
1928  free(p1);
1929  free(p2);
1930  free(tg1);
1931  free(tg2);
1932  free(p);
1933  free(d);
1934 
1935  return(!error);
1936 }
1937 
1938 boolean RefineSingularPoint(Tparameters *pr,unsigned int bID,Tatlas *a)
1939 {
1940  double epsilon,nullSingularValue;
1941  unsigned int maxIterations;
1942  unsigned int i,j,k;
1943  double *y,*x,*lambda;
1944  unsigned int s,c,r;
1945  Tchart *c1;
1946  double *p1;
1947  double *phi;
1948  unsigned int it;
1949  boolean converged;
1950  double dif,d1,d2,d3;
1951 
1952  TNewton newton;
1953  double *J;
1954  double *bData;
1955  double *aData;
1956  double *ptr; /* used to access bData */
1957 
1958  int err;
1959 
1960  double ***h;
1961 
1962  /* This routine requires the Hessian, compute it if no
1963  already computed */
1964  if (a->H==NULL)
1965  {
1966  NEW(a->H,1,THessian);
1967  InitHessian(&(a->J),a->H);
1968  }
1969 
1970  epsilon=GetParameter(CT_EPSILON,pr);
1971  maxIterations=(unsigned int)GetParameter(CT_MAX_NEWTON_ITERATIONS,pr);
1972  nullSingularValue=epsilon/100;
1973 
1974  c1=a->charts[a->bifurcation[bID]->mID1];
1975  p1=GetChartCenter(c1);
1976  phi=GetChartTangentSpace(c1); /*This is m x k = ncJ x k*/
1977 
1978  /* As an improvement we could use an interpolation between the
1979  tangent spaces for c1 and c2 */
1980 
1981  /* Number of variables/columns of the system adjusted via Newton*/
1982  c=a->ncJ+a->ncJ; /* The original variables plus lambda */
1983  /* Number of equations/rows of the system adjusted via Newton */
1984  r=(a->nrJ+a->nrJ+a->k+1); /*F + J*lambda + phi*lambda + 1*/
1985 
1986  /* Space for the current estimation */
1987  NEW(y,c,double);
1988  /* Direct pointers to the two components of 'y' */
1989  x=y;
1990  lambda=&(y[a->ncJ]);
1991 
1992  /* Set up the initial value for 'y' */
1993 
1994  /* Initialize x to the current estimation of the singular point */
1995  if (a->bifurcation[bID]->p!=NULL)
1996  {
1997  /* We have an estimation of the singular point and want to
1998  refine it*/
1999  memcpy(x,a->bifurcation[bID]->p,sizeof(double)*a->ncJ);
2000  }
2001  else
2002  {
2003  /* Search the bifurcation from scratch. Depart from the
2004  center of the first chart */
2005  memcpy(x,p1,sizeof(double)*a->ncJ);
2006  }
2007 
2008  /* Space for the Jacobian evaluation */
2009  NEW(J,a->nrJ*a->ncJ,double); /* ncJ==m */
2010 
2011  #if (0)
2012  if (a->bifurcation[bID]->p!=NULL)
2013  {
2014  /* If we have an inintial estimation of the singular point, initialize lambda
2015  with the eigenvector for the smaller non-null eigenvalue.
2016  For this vector J*lambda is close to zero. */
2017 
2018  double *K;
2019 
2020  NEW(K,a->ncJ*(a->k+1),double);
2021 
2022  /* Re-use vector 'J' to store J^t */
2023  EvaluateTransposedJacobianInVector(a->bifurcation[bID]->p,a->ncJ,a->nrJ,J,&(a->J));
2024 
2025  FindKernel(a->nrJ,a->ncJ,J,a->k+1,FALSE,epsilon,&K);
2026 
2027  /* The kernel is returned from largest eigen value to smaller */
2028  GetColumn(0,a->ncJ,a->k+1,K,lambda);
2029 
2030  free(K);
2031  }
2032  else
2033  #else
2034  {
2035  lambda[0]=1;
2036  for(i=1;i<a->ncJ;i++)
2037  lambda[i]=0;
2038  }
2039  #endif
2040 
2041  /* Allocate space for the matrices to be used at each Newton step */
2042  InitNewton(r,c,&newton);
2043  aData=GetNewtonMatrixBuffer(&newton);
2044  /* set all entries to zero (many blocks remain zero all along the process) */
2045  s=r*c;
2046  for(i=0;i<s;i++)
2047  aData[i]=0.0;
2048 
2049  bData=GetNewtonRHBuffer(&newton); /* r entries */
2050 
2052 
2053  it=0;
2054  converged=FALSE;
2055  while((!converged)&&(it<maxIterations))
2056  {
2057  /* Set up the matrix */
2058 
2059  /* Get the Jacobian, we will use it in different steps below */
2060  EvaluateJacobianInVector(x,a->nrJ,a->ncJ,J,&(a->J));
2061 
2062  /* We first set up part of the matrix and then the residual since the
2063  residual evaluation needs the Jacobian, included in the matrix.*/
2064 
2065  /* The first block of the matrix comes from
2066  rows of the Jacobian (and a block of zeros at the end of each row) */
2067  SubMatrixFromMatrix(a->nrJ,a->ncJ,J,0,0,r,c,aData);
2068 
2069  /* Set up part of the residual (the one for 'x'). */
2070  /*F(x)=0*/
2071  CS_WD_EVALUATE_SIMP_EQUATIONS(pr,x,bData,a->w);
2072 
2073  /* Set up the rest of the residual (the one for 'lambda' that uses
2074  J just stored in aData) */
2075  /* J*lambda=0 */
2076  ptr=&(bData[a->nrJ]);
2077  MatrixVectorProduct(a->nrJ,a->ncJ,J,lambda,ptr);
2078 
2079  /* Now force lambda to be different from the vectors in the known
2080  tangent space (approximatted by the tangent space at the initial
2081  point, p1)
2082  phi' * lambda = 0 */
2083  TMatrixVectorProduct(a->m,a->k,phi,lambda,&(bData[a->nrJ+a->nrJ]));
2084 
2085  /* last element in the residual is lambda' lambda -1 =0 */
2086  bData[r-1]=GeneralDotProduct(a->ncJ,lambda,lambda)-1.0;
2087 
2088  d1=Norm(a->nrJ,bData);
2089  d2=Norm(a->nrJ,&(bData[a->nrJ]));
2090  d3=Norm(a->k,&(bData[a->nrJ+a->nrJ]));
2091  //d4=fabs(bData[r-1]);
2092  //if ((d1<epsilon)&&(d2<epsilon)&&(d3<epsilon)&&(d4<epsilon))
2093  if ((d1<10*epsilon)&&(d2<10*epsilon)&&(d3<10*epsilon))
2094  converged=TRUE;
2095  else
2096  {
2097  /* The Hessian part*/
2098  EvaluateHessian(x,h,a->H);
2099 
2100  /* The second block of the matrix comes from the Hessian */
2101  for(i=0;i<a->nrJ;i++)
2102  {
2103  for(j=0;j<a->ncJ;j++)
2104  {
2105  aData[RC2INDEX(a->nrJ+i,j,r,c)]=0.0;
2106  for(k=0;k<a->ncJ;k++)
2107  aData[RC2INDEX(a->nrJ+i,j,r,c)]+=(h[i][k][j]*lambda[k]);
2108  }
2109  }
2110 
2111  /* now the Jacobian part (take the already computed one) */
2112  SubMatrixFromMatrix(a->nrJ,a->ncJ,J,a->nrJ,a->ncJ,r,c,aData);
2113 
2114  /* The known tangent space part (transposed tangent) */
2115  SubMatrixFromTMatrix(a->m,a->k,phi,a->nrJ+a->nrJ,a->ncJ,r,c,aData);
2116 
2117  /* The last row of the matrix only inclues a block of zeros and 2*lambda*/
2118  for(i=0;i<a->ncJ;i++)
2119  aData[RC2INDEX(r-1,a->ncJ+i,r,c)]=(2.0*lambda[i]);
2120 
2121  /* Improve the solution */
2122  err=NewtonStep(nullSingularValue,y,&dif,&newton);
2123 
2124  if (err)
2125  it=maxIterations;
2126  else
2127  it++;
2128  }
2129  }
2130 
2131  if (converged)
2132  {
2133  if (a->tp!=NULL)
2134  ArrayPi2Pi(a->m,a->tp,x);
2135 
2136  /* If we do not have an estimation for the singular point we
2137  initialize it, oherwise we improve the estimation. */
2138  if (a->bifurcation[bID]->p==NULL)
2139  NEW(a->bifurcation[bID]->p,a->m,double);
2140 
2141  /* Singular point found. Update the information about the bifurcation */
2142  memcpy(a->bifurcation[bID]->p,x,a->m*sizeof(double));
2143  }
2144 
2145  /* release used memory */
2146  DeleteNewton(&newton);
2147  FreeHessianEvaluation(h,a->H);
2148  free(J);
2149  free(y);
2150 
2151  return(it<maxIterations);
2152 }
2153 
2154 unsigned int FindRightNullVector(Tparameters *pr,unsigned int bID,
2155  double **phi,Tatlas *a)
2156 {
2157  double *JTData;
2158  double *K=NULL;
2159  double s,sMin,*p;
2160  unsigned int it,itMin,ck;
2161  unsigned int out;
2162  double *T;
2163  double eps;
2164 
2165  //eps=sqrt(GetParameter(CT_EPSILON,pr)); /* typically 1e-3 */
2166  /* We use a large threshold just to avoid errors. This basically gets
2167  the k+1 vectors with smaller eigenvalues, irrespectively of the
2168  value of these eigenvalues. */
2169  eps=0.01;
2170 
2171  /* Number of columns of the matrix K defined below */
2172  ck=a->k+1;
2173 
2174  /*Use the tangent space at mp1 as an approximation of the tangent space at the
2175  bifurcation*/
2176  T=GetChartTangentSpace(a->charts[a->bifurcation[bID]->mID1]);
2177 
2178  if (a->bifurcation[bID]->p==NULL)
2179  Error("FindRightNullVector needs a singular point");
2180 
2181  /* The (almost) singular point */
2182  p=a->bifurcation[bID]->p;
2183 
2184  /* Space for the Jacobian */
2185  NEW(JTData,a->ncJ*a->nrJ,double);
2186  EvaluateTransposedJacobianInVector(p,a->ncJ,a->nrJ,JTData,&(a->J));
2187  #if (_DEBUG>3)
2188  PrintTMatrix(stdout,"J",a->ncJ,a->nrJ,JTData);
2189  #endif
2190 
2191  /* Now we retrive the k+1 vectors defining the kernel at the singularity.
2192  This is the same to that of \ref InitChart where we compute the
2193  kernel at a non-singular point. The difference is that here we
2194  have k+1 vector (instead of k) and that we have to be more generous with the
2195  criteria to consider eigen value as zero (the input point might not
2196  be exactly singular). In the extreme we can set the 'check' parameter
2197  to FALSE and then we just get the k+1 vectors for the smaller eigenvalues,
2198  irrespectively of their actual value. */
2199  out=FindKernel(a->nrJ,a->ncJ,JTData,ck,TRUE,eps,&K);
2200 
2201  #if (_DEBUG>3)
2202  PrintTMatrix(stdout,"T",a->m,a->k,T);
2203  PrintTMatrix(stdout,"K",a->m,ck,K);
2204  #endif
2205 
2206  /* Look for the vector more different from those in T.
2207  Note that we just get the vector that is more different
2208  for those in T, without any minimal dissimilarity.
2209  We could define a threshold and return only a valid
2210  vector it is different 'enough' from those in T */
2211 
2212  /* Space for the output vector (not used if out!=0) */
2213 
2214  if (out==0)
2215  {
2216  double *Proj;
2217 
2218  NEW((*phi),a->m,double);
2219  NEW(Proj,a->k*ck,double);
2220 
2221  TMatrixMatrixProduct(a->m,a->k,T,ck,K,Proj);
2222 
2223  #if (_DEBUG>3)
2224  PrintMatrix(stdout,"Proj",a->k,ck,Proj);
2225  #endif
2226 
2227  #if (_DEBUG>3)
2228  printf(" Proj(T):[ ");
2229  #endif
2230 
2231  /* Compute the norm of the columns of Proj */
2232  sMin=INF;
2233  itMin=0; /* dummy value */
2234  for(it=0;it<=a->k;it++)
2235  {
2236  s=ColumnSquaredNorm(it,a->k,ck,Proj);
2237  #if (_DEBUG>3)
2238  printf("%g ",s);
2239  #endif
2240  if (s<sMin)
2241  {
2242  sMin=s;
2243  itMin=it;
2244  }
2245  }
2246  #if (_DEBUG>3)
2247  printf("]\n");
2248  #endif
2249  free(Proj);
2250 
2251  /* Get the column of K corresponding to the smaller
2252  projection on T */
2253  GetColumn(itMin,a->m,ck,K,(*phi));
2254  }
2255  else
2256  *phi=NULL;
2257 
2258  /* Release allocated space */
2259  if (K!=NULL)
2260  free(K);
2261 
2262  free(JTData);
2263 
2264  return(out);
2265 }
2266 
2267 boolean Newton2ManifoldPlane(Tparameters *pr,double *point,double *vector,
2268  double *pInit,double *p,Tatlas *a)
2269 {
2270  if (a->n==0)
2271  {
2272  memcpy(p,point,sizeof(double)*a->m);
2273  return(TRUE);
2274  }
2275  else
2276  {
2277  double epsilon,nullSingularValue;
2278  unsigned int j,it,maxIterations;
2279  boolean converged;
2280 
2281  TNewton newton;
2282  double *bData;
2283  double *aData;
2284  double *ptr;
2285 
2286  double errorVal;
2287  int err;
2288 
2289  epsilon=GetParameter(CT_EPSILON,pr);
2290  maxIterations=(unsigned int)GetParameter(CT_MAX_NEWTON_ITERATIONS,pr);
2291  nullSingularValue=epsilon/100;
2292 
2293  if (maxIterations==0)
2294  Error("MAX_NEWTON_ITERATIONS must be larger than 0 to use Newton2ManifoldPlane");
2295 
2296  InitNewton(a->nrJ+1,a->ncJ,&newton);
2297  aData=GetNewtonMatrixBuffer(&newton);
2298  bData=GetNewtonRHBuffer(&newton);
2299 
2300  if (pInit==NULL)
2301  memcpy(p,point,sizeof(double)*a->m);
2302  else
2303  memcpy(p,pInit,sizeof(double)*a->m);
2304 
2305  /* Iterate from this point to a point on the manifold */
2306  it=0;
2307  converged=FALSE;
2308  while((!converged)&&(it<maxIterations))
2309  {
2310  /* Define the residual (right-had side of the system) */
2311  CS_WD_EVALUATE_SIMP_EQUATIONS(pr,p,bData,a->w);
2312 
2313  /* Complete the residual with the equation defining the
2314  plane that might intersect with the other branch */
2315  ptr=&(bData[a->nrJ]);
2316  *ptr=0;
2317  for(j=0;j<a->ncJ;j++) /* ncJ=m */
2318  (*ptr)+=(vector[j]*(p[j]-point[j]));
2319 
2320  errorVal=Norm(a->nrJ+1,bData);
2321 
2322  if (errorVal<epsilon)
2323  converged=TRUE;
2324  else
2325  {
2326  /* Fill in the part of the 'A' corresponding to the Jacobian */
2327  EvaluateJacobianInVector(p,a->nrJ+1,a->ncJ,aData,&(a->J));
2328 
2329  /* Now the part of the 'A' matrix corresponding to the plane
2330  that might intersect with the manifold. */
2331  SetRow(vector,a->nrJ,a->nrJ+1,a->ncJ,aData); /*ncJ==m*/
2332 
2333  /* Define the residual (right-had side of the system) */
2334  CS_WD_EVALUATE_SIMP_EQUATIONS(pr,p,bData,a->w);
2335 
2336  /* Complete the residual with the equation defining the
2337  plane that might intersect with the other branch */
2338  ptr=&(bData[a->nrJ]);
2339  *ptr=0;
2340  for(j=0;j<a->ncJ;j++) /* ncJ=m */
2341  (*ptr)+=(vector[j]*(p[j]-point[j]));
2342 
2343  err=NewtonStep(nullSingularValue,p,&errorVal,&newton);
2344 
2345  if (err)
2346  it=maxIterations;
2347  else
2348  {
2349  if(errorVal<epsilon)
2350  converged=TRUE;
2351  it++;
2352  }
2353  }
2354  }
2355 
2356  if ((converged)&&(a->tp!=NULL))
2357  ArrayPi2Pi(a->m,a->tp,p);
2358 
2359  /* release used memory */
2360  DeleteNewton(&newton);
2361 
2362  return(it<maxIterations);
2363  }
2364 }
2365 
2366 boolean FindPointInOtherBranch(Tparameters *pr,unsigned int bID,
2367  double *phi,double **p,Tatlas *a)
2368 {
2369  double d;
2370  double *p0;
2371  boolean converged;
2372 
2373  if (a->bifurcation[bID]->p==NULL)
2374  Error("FindPointInOtherBranch needs a singular point");
2375 
2376  /* Displace a bit along phi to get a point outside the manifold */
2377  /* To increase robustness, we may iterate decresing 0.01 until
2378  the jump is succesful */
2379  NEW(p0,a->m,double);
2380  SumVectorScale(a->m,a->bifurcation[bID]->p,0.01*a->r,phi,p0);
2381 
2382  /* Search for the intersection of a plane defined by
2383  the new vector of the kernel at the bifurcation found using
2384  \ref FindRightNullVector passing by a point just out
2385  of the variety. This point is also determined using
2386  the new vector of the kernel. */
2387 
2388  NEW((*p),a->m,double);
2389  converged=Newton2ManifoldPlane(pr,p0,phi,NULL,*p,a);
2390 
2391  if (converged)
2392  {
2393  d=DistanceTopology(a->m,a->tp,a->bifurcation[bID]->p,*p);
2394  if (d>a->r)
2395  {
2396  converged=FALSE;
2397  printf(" Converged too far from singularity\n");
2398  }
2399  }
2400  else
2401  {
2402  printf(" Could not jump to the other branch\n");
2403  free(*p);
2404  }
2405 
2406  free(p0);
2407 
2408  return(converged);
2409 }
2410 
2411 void DefineChartsAtBifurcation(Tparameters *pr,unsigned int bID,
2412  double *v,TAtlasStatistics *ast,Tatlas *a)
2413 {
2414  double c;
2415 
2416  if (a->bifurcation[bID]->p==NULL)
2417  Error("DefineChartsAtBifurcation needs a singular point");
2418 
2419  /* 3.1.- We define a new chart on the singularity */
2420  if (a->currentChart==a->maxCharts)
2421  MEM_DUP(a->charts,a->maxCharts,Tchart *);
2422 
2423  NEW(a->charts[a->currentChart],1,Tchart);
2424 
2425  if (InitChartWithTangent(pr,FALSE,a->ambient,a->tp,a->m,a->k,
2426  a->bifurcation[bID]->p,
2428  a->e,a->ce,a->r,
2429  &(a->J),a->w,a->charts[a->currentChart])>1)
2430  Warning("Can not create a chart on the singular point");
2431  else
2432  {
2433  a->currentChart++;
2435 
2436  /* 3.2.- Define a new chart in the other branch */
2437  if (a->currentChart==a->maxCharts)
2438  MEM_DUP(a->charts,a->maxCharts,Tchart *);
2439 
2440  NEW(a->charts[a->currentChart],1,Tchart);
2441 
2442  if (InitSingularChart(pr,FALSE,a->ambient,a->tp,a->m,a->k,v,a->e,a->ce,a->r,
2443  &(a->J),a->w,a->charts[a->currentChart])>1)
2444  Warning("Can not create a chart on the other branch");
2445  else
2446  {
2448  if (c>(1-a->ce))
2450 
2451  printf(" New Bifurcation Chart %u (%f)\n",a->currentChart,c);
2452 
2453  a->currentChart++;
2455 
2456  /* 3.3.- Link the two charts together */
2458  a->currentChart-1,a->charts[a->currentChart-1]);
2459  }
2460  }
2461 }
2462 
2463 void ProcessBifurcation(Tparameters *pr,unsigned int bID,TAtlasStatistics *ast,Tatlas *a)
2464 {
2465  if ((bID>=a->npBifurcations)&&(bID<a->nBifurcations))
2466  {
2467  NewBifurcation(ast);
2468  /*
2469  Now we have to detect a point in the "other" branch of the manifold,
2470  start a chart there (IntChart) and search for neighbours
2471  (DetectChartNeighbours).
2472  */
2473  double *phi,*v;
2474 
2475  printf(" Searching for bifurcation\n");
2476 
2477  /* 1.- Determine the bifurcation point. This is an approximation since
2478  all our processes are epsilon accurate. The result is that the
2479  singular point is actually close to singular but not singular */
2480 
2481  if (FindSingularPoint(pr,bID,a))
2482  {
2483  /* 2.- Find the right null vector (the vector for the smallest
2484  eigenvalue (it sould be zero but is not due to numerical
2485  problems) */
2486  if (FindRightNullVector(pr,bID,&phi,a)==0)
2487  {
2488  /* 3.- Find a point in the other branch */
2489  if (FindPointInOtherBranch(pr,bID,phi,&v,a))
2490  {
2491  /* Define on chart at the current branch of the singularity,
2492  another at the new branch and link them.*/
2493  DefineChartsAtBifurcation(pr,bID,v,ast,a);
2494 
2495  /* Release intermediate variables */
2496  free(v);
2497  }
2498  else
2499  NewNoJumpBranch(ast);
2500 
2501  /*Release other intermediate variables*/
2502  free(phi);
2503  }
2504  else
2505  NewNoSingularEnough(ast);
2506  }
2507  else
2509  }
2510 }
2511 
2512 void LoadBifurcations(FILE *f,Tatlas *a)
2513 {
2514  unsigned int i,j,p;
2515 
2516  fscanf(f,"%u",&(a->mBifurcations));
2517  fscanf(f,"%u",&(a->nBifurcations));
2518  fscanf(f,"%u",&(a->npBifurcations));
2519 
2521 
2522 
2523  for(i=0;i<a->nBifurcations;i++)
2524  {
2525  NEW(a->bifurcation[i],1,Tbifurcation);
2526  fscanf(f,"%u",&(a->bifurcation[i]->mID1));
2527  fscanf(f,"%u",&(a->bifurcation[i]->d1));
2528  fscanf(f,"%u",&(a->bifurcation[i]->mID2));
2529  fscanf(f,"%u",&(a->bifurcation[i]->d2));
2530  fscanf(f,"%u",&p);
2531  if (p!=0)
2532  {
2533  NEW(a->bifurcation[i]->p,a->m,double);
2534  for(j=0;j<a->m;j++)
2535  fscanf(f,"%lf",&(a->bifurcation[i]->p[j]));
2536  }
2537  else
2538  a->bifurcation[i]->p=NULL;
2539  }
2540 }
2541 
2542 void SaveBifurcations(FILE *f,Tatlas *a)
2543 {
2544  unsigned int i,j;
2545 
2546  fprintf(f,"%u\n",a->mBifurcations);
2547  fprintf(f,"%u\n",a->nBifurcations);
2548  fprintf(f,"%u\n",a->npBifurcations);
2549 
2550  for(i=0;i<a->nBifurcations;i++)
2551  {
2552  fprintf(f,"%u %u %u %u %u\n",
2553  a->bifurcation[i]->mID1,a->bifurcation[i]->d1,
2554  a->bifurcation[i]->mID2,a->bifurcation[i]->d2,
2555  (a->bifurcation[i]->p!=NULL));
2556  if (a->bifurcation[i]->p!=NULL)
2557  {
2558  for(j=0;j<a->m;j++)
2559  fprintf(f,"%.12f ",a->bifurcation[i]->p[j]);
2560  fprintf(f,"\n");
2561  }
2562  }
2563 }
2564 
2566  unsigned int xID,unsigned int yID,unsigned int zID,Tatlas *a)
2567 {
2568  unsigned int i;
2569  double *p;
2570  double x[2],y[2],z[2];
2571  double *o;
2572  Tchart *m;
2573  Tcolor color;
2574 
2575  NewColor(1,0,0,&color); /* red */
2576  StartNew3dObject(&color,p3d);
2577 
2578  for(i=0;i<a->nBifurcations;i++)
2579  {
2580  m=a->charts[a->bifurcation[i]->mID1];
2581  p=GetChartCenter(m);
2582  CS_WD_REGENERATE_ORIGINAL_POINT(pr,p,&o,a->w);
2583  x[0]=o[xID];
2584  y[0]=o[yID];
2585  z[0]=o[zID];
2586  free(o);
2587 
2588  m=a->charts[a->bifurcation[i]->mID2];
2589  p=GetChartCenter(m);
2590  CS_WD_REGENERATE_ORIGINAL_POINT(pr,p,&o,a->w);
2591  x[1]=o[xID];
2592  y[1]=o[yID];
2593  z[1]=o[zID];
2594  free(o);
2595 
2596  PlotVect3d(2,x,y,z,p3d);
2597  }
2598  Close3dObject(p3d);
2599  DeleteColor(&color);
2600 }
2601 
2603 {
2604  unsigned int i;
2605 
2606  for(i=0;i<a->nBifurcations;i++)
2607  {
2608  if (a->bifurcation[i]->p!=NULL)
2609  free(a->bifurcation[i]->p);
2610  free(a->bifurcation[i]);
2611  }
2612  free(a->bifurcation);
2613 
2614  a->mBifurcations=0;
2615  a->nBifurcations=0;
2616  a->npBifurcations=0;
2617 }
2618 
2619 void InitAtlasHeapElement(unsigned int mID,double c,double beta,TAtlasHeapElement *he)
2620 {
2621  he->chartID=mID;
2622  he->cost=c;
2623  if (beta<1)
2624  Error("The heap element penalty factor must be >1");
2625  he->beta=beta;
2626  he->nPenalized=1;
2627 }
2628 
2629 void CopyAtlasHeapElement(void *he1,void *he2)
2630 {
2631  ((TAtlasHeapElement *)he1)->chartID=((TAtlasHeapElement *)he2)->chartID;
2632  ((TAtlasHeapElement *)he1)->cost=((TAtlasHeapElement *)he2)->cost;
2633  ((TAtlasHeapElement *)he1)->beta=((TAtlasHeapElement *)he2)->beta;
2634  ((TAtlasHeapElement *)he1)->nPenalized=((TAtlasHeapElement *)he2)->nPenalized;
2635 }
2636 
2638 {
2639  return(he->chartID);
2640 }
2641 
2643 {
2644  return(he->cost);
2645 }
2646 
2647 boolean LessThanAtlasHeapElement(void *he1,void *he2,void *userData)
2648 {
2649  double t,b1,b2,c1,c2;
2650 
2651  t=((TAtlasHeapElement *)he1)->nPenalized;
2652  b1=((TAtlasHeapElement *)he1)->beta;
2653  c1=pow(b1,t-1)*((TAtlasHeapElement *)he1)->cost;
2654 
2655  t=((TAtlasHeapElement *)he2)->nPenalized;
2656  b2=((TAtlasHeapElement *)he2)->beta;
2657  c2=pow(b2,t-1)*((TAtlasHeapElement *)he2)->cost;
2658 
2659  return(c1<=c2);
2660 }
2661 
2663 {
2664  he->nPenalized++;
2665 }
2666 
2668 {
2669 }
2670 
2672 {
2673  boolean hasS;
2674  unsigned int i;
2675 
2676  if (CS_WD_GET_SIMP_TOPOLOGY(pr,&(a->tp),a->w)!=a->m)
2677  Error("Missmatch number of variables in SetAtlasTopology");
2678 
2679  /* Search for a non-real variable */
2680  hasS=FALSE;
2681  i=0;
2682  while((i<a->m)&&(!hasS))
2683  {
2684  hasS=(a->tp[i]==TOPOLOGY_S);
2685  i++;
2686  }
2687  if (!hasS)
2688  {
2689  /* if all variables are real no need to consider topology */
2690  free(a->tp);
2691  a->tp=NULL;
2692  }
2693 }
2694 
2695 void InitAtlas(Tparameters *pr,boolean parallel,boolean simpleChart,
2696  unsigned int k,double e,double ce, double r,TAtlasBase *w,
2697  Tatlas *a)
2698 {
2699  a->w=w;
2700 
2702  a->currentChart=0;
2703  a->npCharts=0;
2704 
2705  NEW(a->charts,a->maxCharts,Tchart *);
2706 
2707  NEW(a->ambient,1,Tbox);
2708 
2709  /* Since atlas are defined on the simplified system we get the
2710  corresponding Jacobian. */
2711  CS_WD_GET_SIMP_JACOBIAN(pr,&(a->J),a->w);
2712  GetJacobianSize(&(a->nrJ),&(a->ncJ),&(a->J));
2714 
2715  /* differ the Hessian computation */
2716  a->H=NULL;
2717 
2718  a->k=k;
2719  a->m=a->ncJ;
2720  a->n=a->m-a->k;
2721  a->r=r;
2722  a->e=e;
2723  a->ce=ce;
2724 
2726  a->nBifurcations=0;
2727  a->npBifurcations=0;
2729 
2730  a->simpleChart=simpleChart;
2731 
2732  SetAtlasTopology(pr,a);
2733 
2734  /* The openMP parallel execution is only possible if OpenMP is active and
2735  it is only worth if the problem is large (in number of variables or
2736  dimension of the solution set). Moreover, collision detection
2737  is typically not re-entrant. Do not use parallel execution in
2738  this case (if operating on a world instead than on a cuik file). */
2739 
2740  a->parallel=FALSE; /* The default is not to execute in parallel */
2741 
2742  #ifdef _OPENMP
2743  if (parallel)
2744  {
2745  a->nCores=omp_get_max_threads();
2746  /* even if having many cores and OpenMP we only execute in parallel
2747  large problems. */
2748  a->parallel=((a->nCores>1)&&((a->m>10)||(a->k>2)));
2749  }
2750  #endif
2751  //a->parallel=FALSE;
2752  if (!a->parallel)
2753  a->nCores=1;
2754 
2755  fprintf(stderr,"Number of computing cores (atlas) : %u\n",a->nCores);
2756 
2757  /* When using world, collisions are considered (if defined) */
2758  CS_WD_INIT_CD(pr,a->nCores,a->w);
2759 }
2760 
2761 boolean InitAtlasFromPoint(Tparameters *pr,boolean parallel,boolean simpleChart,double *p,
2762  TAtlasBase *w,Tatlas *a)
2763 {
2764  unsigned int chartCode;
2765  boolean initOK;
2766  double *ps,*pWithDummies;
2767  unsigned int k;
2768  double e,ce,r;
2769 
2770  k=(unsigned int)GetParameter(CT_N_DOF,pr);
2771  r=GetParameter(CT_R,pr);
2772  e=GetParameter(CT_E,pr);
2773  ce=GetParameter(CT_CE,pr);
2774 
2775  InitAtlas(pr,parallel,simpleChart,k,e,ce,r,w,a);
2776 
2777  /* We have to recover the full solution point from the values of the system
2778  variables in sample 'p' and then define the a point in the simplified system
2779  that is where the atlas is defined.
2780  Note that the actual dimension of the ambient space is that of the number
2781  of variables in the simplified system. Moreover, note that both the simplified
2782  and the original system describe the same manifold (k is the same is the to of
2783  them)
2784  */
2785  CS_WD_REGENERATE_SOLUTION_POINT(pr,p,&pWithDummies,a->w);
2786 
2787  if (CS_WD_ORIGINAL_IN_COLLISION(pr,pWithDummies,NULL,a->w))
2788  Error("Starting point for the atlas is in collision");
2789 
2790  a->m=CS_WD_GENERATE_SIMPLIFIED_POINT(pr,pWithDummies,&ps,a->w);
2791  free(pWithDummies);
2792 
2793  if (a->k==0)
2794  {
2795  /* We have to determine the dof assuming that the given point is regular */
2796  Warning("N_DOF parameter set to 0. Assuming that the initial point is regular");
2797 
2798  a->k=CS_WD_MANIFOLD_DIMENSION(pr,p,a->w);
2799 
2800  if (a->k==0)
2801  Error("System with mobility 0");
2802 
2803  fprintf(stderr,"Setting N_DOF=%u\n\n",a->k);
2804 
2805  /* Change the parameter !! */
2806  ChangeParameter(CT_N_DOF,(double)a->k,pr);
2807  }
2808 
2809  NEW(a->charts[0],1,Tchart);
2810  chartCode=InitChart(pr,a->simpleChart,a->ambient,a->tp,a->m,a->k,ps,a->e,a->ce,a->r,
2811  &(a->J),a->w,a->charts[0]);
2812 
2813  switch (chartCode)
2814  {
2815  case 1:
2816  Error("The expected mobility is too low (increase N_DOF)");
2817  break;
2818  case 2:
2819  Error("The expected mobility is too high (decrease N_DOF)");
2820  break;
2821  case 3:
2822  Error("There is a numerical error when computing the tangent space");
2823  break;
2824  case 4:
2825  Error("The initial point is not on the manifold");
2826  break;
2827  }
2828 
2829  initOK=(chartCode==0);
2830 
2831  free(ps);
2832 
2833  if (initOK)
2834  {
2835  if (FrontierChart(a->charts[0]))
2836  Error("The initial chart is out of the ambient space domain");
2837 
2838  a->currentChart=1;
2839  a->npCharts=1; /* No need to post-process the first chart. */
2840  #if (USE_ATLAS_TREE)
2841  InitBTree(0,a->charts[0],a->ambient,a->tp,&(a->tree));
2842  #endif
2843  }
2844  else
2845  free(a->charts[0]);
2846 
2847  return(initOK);
2848 }
2849 
2850 unsigned int AddChart2Atlas(Tparameters *pr,double *ps,unsigned int parentID,boolean *singular,Tatlas *a)
2851 {
2852  boolean initOK;
2853  unsigned int mID;
2854 
2855  *singular=FALSE;
2856 
2857  /* Generate the new chart */
2858  if (a->currentChart==a->maxCharts)
2859  MEM_DUP(a->charts,a->maxCharts,Tchart *);
2860 
2861  NEW(a->charts[a->currentChart],1,Tchart);
2862 
2863  initOK=(InitChart(pr,a->simpleChart,a->ambient,a->tp,a->m,a->k,ps,a->e,a->ce,a->r,
2864  &(a->J),a->w,a->charts[a->currentChart])==0);
2865  if (initOK)
2866  {
2867  #if (ATLAS_VERBOSE)
2868  printf(" New Chart %u [parent: %u]\n",a->currentChart,parentID);
2869  #endif
2870 
2871  fprintf(stderr,"nn: %u\n",ChartNumNeighbours(a->charts[parentID]));
2872 
2873  mID=a->currentChart;
2874  a->currentChart++;
2875  PostProcessNewCharts(pr,TRUE,parentID,NULL,a);
2876 
2877  fprintf(stderr,"nn: %u\n",ChartNumNeighbours(a->charts[parentID]));
2878  }
2879  else
2880  {
2881  mID=NO_UINT;
2882  free(a->charts[a->currentChart]);
2883  }
2884 
2885  return(mID);
2886 }
2887 
2888 unsigned int AddTrustedChart2Atlas(Tparameters *pr,double *ps,unsigned int parentID,boolean *singular,Tatlas *a)
2889 {
2890  boolean initOK;
2891  unsigned int mID;
2892  unsigned int db;
2893 
2894  *singular=FALSE;
2895 
2896  /* Generate the new chart */
2897  if (a->currentChart==a->maxCharts)
2898  MEM_DUP(a->charts,a->maxCharts,Tchart *);
2899 
2900  NEW(a->charts[a->currentChart],1,Tchart);
2901 
2902  initOK=(InitTrustedChart(pr,a->simpleChart,a->ambient,a->tp,a->m,a->k,ps,a->e,a->ce,a->r,
2903  &(a->J),a->w,a->charts[a->currentChart])==0);
2904 
2905  if (initOK)
2906  {
2907  #if (ATLAS_VERBOSE)
2908  printf(" New Chart %u (%p)\n",a->currentChart,a->charts[a->currentChart]);
2909  #endif
2910 
2911  mID=a->currentChart;
2912  a->currentChart++;
2913 
2914  if (a->n>0)
2915  {
2916  /* and now detect (and process) bifurcation from parent to child, even
2917  if they are not neighbours yet. */
2918  db=(unsigned int)GetParameter(CT_DETECT_BIFURCATIONS,pr);
2919 
2920  if ((db>0)&&(parentID!=NO_UINT))
2921  *singular=DetectBifurcation(pr,parentID,mID,a);
2922  }
2923  /* detect neighbours and deal with the bifurcations if any */
2924  /* Intersect with the rest of charts (but without concern about singularities
2925  and without enforcing intersection with parent). */
2926  PostProcessNewCharts(pr,FALSE,NO_UINT,NULL,a);
2927  }
2928  else
2929  {
2930  mID=NO_UINT;
2931  free(a->charts[a->currentChart]);
2932  }
2933 
2934  return(mID);
2935 }
2936 
2937 void BuildAtlasFromPoint(Tparameters *pr,double *p,boolean simpleChart,
2938  TAtlasBase *w,Tatlas *a)
2939 {
2940  Theap h;
2941  TAtlasHeapElement he,he2;
2942  unsigned int mID;
2943  double *t;
2944  TAtlasStatistics *st;
2945  unsigned int cm,cmPrev;
2946  double d;
2947  unsigned int nv,k;
2948  double beta;
2949  unsigned int maxCharts;
2950  /* just in case parallel=TRUE */
2951  unsigned int i,*cornerID,*chartID,maxInProcess,ncInProcess;
2952  double **tv;
2953  Tchart **newCharts;
2954  TAtlasHeapElement *heInProcess;
2955 
2956  /* Init the atlas trying to exploit parallelism, if available and worth */
2957  if (!InitAtlasFromPoint(pr,TRUE,simpleChart,p,w,a))
2958  Error("Can not start atlas from the given point (BuildAtlasFromPoint)");
2959 
2960  k=(unsigned int)GetParameter(CT_N_DOF,pr);
2961 
2962  maxCharts=(unsigned int)GetParameter(CT_MAX_CHARTS,pr);
2963 
2964  InitHeap(sizeof(TAtlasHeapElement),
2969 
2970  beta=GetParameter(CT_ATLASGBF_BETA,pr);
2971  /* one-dim solution sets (k==1) -> process charts in sequence */
2972  InitAtlasHeapElement(0,(k==1?1:0),beta,&he);
2973  AddElement2Heap(NO_UINT,(void *)(&he),&h);
2974 
2975  if (a->parallel)
2976  {
2977  fprintf(stderr,"Executing in %u parallel threads\n",a->nCores);
2978  /* some charts are difficult to process it's better to have more
2979  charts in queue... let the other threads to process the simple
2980  ones */
2981  maxInProcess=(unsigned int)(1.5*a->nCores);
2982  NEW(chartID,maxInProcess,unsigned int);
2983  NEW(cornerID,maxInProcess,unsigned int);
2984  NEW(tv,maxInProcess,double *);
2985  for(i=0;i<maxInProcess;i++)
2986  NEWZ(tv[i],a->k,double); /* if kino equations some elements of t not used (keep to 0) */
2987  NEW(heInProcess,maxInProcess,TAtlasHeapElement);
2988  NEW(newCharts,maxInProcess,Tchart*);
2989  st=NULL;
2990  }
2991  else
2992  {
2993  NEWZ(t,a->k,double); /* if kino equations some elements of t not used (keep to 0) */
2994  NEW(st,1,TAtlasStatistics);
2995  InitAtlasStatistics(st);
2996  }
2997 
2998  while((!HeapEmpty(&h))&&(a->currentChart<maxCharts))
2999  {
3000  cmPrev=a->currentChart;
3001 
3002  if (!a->parallel)
3003  {
3004  ExtractMinElement((void *)(&he),&h);
3005  mID=GetAtlasHeapElementID(&he);
3006 
3007  //if (ExpandibleChart(a->charts[mID]))
3008  if (OpenChart(a->charts[mID]))
3009  {
3010  printf("Extending chart %u\n",mID);
3011 
3012  NewBoundaryAttempt(st);
3013 
3014  /* Treat one external corner at a time */
3016  {
3017  /* This generates a new chart on the direction of 't', if possible. */
3018  ExtendAtlasFromPoint(pr,mID,t,st,a);
3019 
3020  /* Just in case the selected vertex is not actually used, we eliminate it
3021  from the list of expandible vetexes. In general this has no effect since
3022  the extension already eliminated the vertex (and created new vertexes) */
3023  WrongCorner(nv,a->charts[mID]);
3024  }
3025  else
3026  NewNotInBoundary(st);
3027 
3028  /* Just in case the chart still has external corners (still open) */
3029  AddElement2Heap(NO_UINT,(void *)(&he),&h);
3030  }
3031  }
3032  else
3033  {
3034  /* Select several open charts, and a corner of each chart */
3035  ncInProcess=0;
3036  while((!HeapEmpty(&h))&&(ncInProcess<maxInProcess))
3037  {
3038  ExtractMinElement((void *)(&(heInProcess[ncInProcess])),&h);
3039  chartID[ncInProcess]=GetAtlasHeapElementID(&(heInProcess[ncInProcess]));
3040  if (OpenChart(a->charts[chartID[ncInProcess]]))
3041  ncInProcess++;
3042  }
3043 
3044  #pragma omp parallel for private(i) schedule(dynamic)
3045  for(i=0;i<ncInProcess;i++)
3046  {
3047  if (BoundaryPointFromExternalCorner(RANDOMNESS,&(cornerID[i]),
3048  tv[i],a->charts[chartID[i]]))
3049  {
3050  #ifdef _OPENMP
3051  printf("Extending chart %u (%u)\n",chartID[i],omp_get_thread_num());
3052  #else
3053  printf("Extending chart %u\n",chartID[i]);
3054  #endif
3055  newCharts[i]=NULL;
3056  NewChartFromPoint(pr,chartID[i],tv[i],&(newCharts[i]),a);
3057  }
3058  /* We selected ncInProcess *different* charts, we can do the
3059  'WrongCorner' in parallel too */
3060  WrongCorner(cornerID[i],a->charts[chartID[i]]);
3061  }
3062 
3063  /* The post process of the generated charts is serialized */
3064  /* Add the charts to the atlas one at a time. */
3065  for(i=0;i<ncInProcess;i++)
3066  {
3067  if (newCharts[i]!=NULL)
3068  {
3069  if (HaveChartAtPoint(1e-6,GetChartCenter(newCharts[i]),a))
3070  {
3071  /* We generated a redundant chart -> remove it
3072  (the nasty side-effect of executing in parallel and
3073  selecting nearby charts for expansion).
3074  1e-6 is hard-coded in the kd-tree */
3075  DeleteChart(newCharts[i]);
3076  newCharts[i]=NULL;
3077  }
3078  else
3079  {
3080  if (a->currentChart==a->maxCharts)
3081  MEM_DUP(a->charts,a->maxCharts,Tchart *);
3082 
3083  /* We directly re-use the charts to safe one copy. */
3084  a->charts[a->currentChart]=newCharts[i];
3085  a->currentChart++;
3086 
3087  /* Now detect neighbours and the possible bifurcations */
3088  PostProcessNewCharts(pr,TRUE,chartID[i],st,a);
3089  }
3090  }
3091  }
3092 
3093  /* Add the charts just processed to the heap, just in case they are still open */
3094  for(i=0;i<ncInProcess;i++)
3095  AddElement2Heap(NO_UINT,(void *)(&(heInProcess[i])),&h);
3096  }
3097 
3098  /* The above can generate several charts (when not using OpenMP or due to bifurcations) */
3099  /* Now we add them to the heap */
3100  for(cm=cmPrev;cm<a->currentChart;cm++)
3101  {
3102  /* Now add the new chart to the heap */
3103  if (k==1) /* one-dim solution sets -> process charts in sequence */
3104  d=1/(double)(cm+1);
3105  else
3106  {
3107  /* when executing in parallel we assign the expansion priority at random
3108  to minimize the prob. of expanding close charts in parallel. This produces
3109  more charts than those really necessary. */
3110  if (a->parallel)
3111  d=randomDouble();
3112  else
3113  d=DistanceTopology(a->m,a->tp,p,GetChartCenter(a->charts[cm]));
3114  }
3115  InitAtlasHeapElement(cm,d,beta,&he2);
3116  AddElement2Heap(NO_UINT,(void *)(&he2),&h);
3117  }
3118  }
3119 
3120  if (a->parallel)
3121  {
3122  free(chartID);
3123  free(cornerID);
3124  for(i=0;i<a->nCores;i++)
3125  free(tv[i]);
3126  free(tv);
3127  free(newCharts);
3128  free(heInProcess);
3129  }
3130  else
3131  {
3132  PrintAtlasStatistics(pr,st);
3133  free(st);
3134  free(t);
3135  }
3136 
3137  DeleteHeap(&h);
3138 }
3139 
3140 boolean MinimizeOnAtlas(Tparameters *pr,char *fname,double *p,TAtlasBase *w,
3141  unsigned int maxSteps,
3142  double (*costF)(Tparameters*,boolean,double*,void*),
3143  void (*costG)(Tparameters*,boolean,double*,double**,void*),
3144  void *costData,
3145  Tatlas *a)
3146 {
3147  unsigned int i,j,k,l,nv,nvs,nt,mt,pnc;
3148  TMinTrace **t;
3149  boolean *systemVars,done;
3150  double *o,*currentPoint;
3151  double cost,cost1;
3152  double *g,*newPoint,*d,ng,*gFull;
3153  double delta,epsilon,e;
3154  Tchart *currentChart;
3155  unsigned int db;
3156  boolean sing,ok;
3157  boolean retraction;
3158  double stepSize;
3159 
3160  db=(unsigned int)GetParameter(CT_DETECT_BIFURCATIONS,pr);
3161 
3162  if (db>1)
3164 
3165  delta=GetParameter(CT_DELTA,pr);
3166  epsilon=GetParameter(CT_EPSILON,pr);
3167  e=GetParameter(CT_E,pr);
3168 
3169  /* Init the atlas */
3170  if (!InitAtlasFromPoint(pr,FALSE,FALSE,p,w,a))
3171  Error("Can not start atlas from the given point (MinimizeOnAtlas)");
3172 
3173  k=(unsigned int)GetParameter(CT_N_DOF,pr);
3174 
3175  /* Get the system varibles */
3176  nv=CS_WD_GET_SYSTEM_VARS(&systemVars,a->w);
3177  nvs=0;
3178  for(i=0;i<nv;i++)
3179  {
3180  if (systemVars[i])
3181  nvs++;
3182  }
3183 
3184  /* Init the set of traces */
3185  mt=5; /* In general only one trace will be followed */
3186  NEW(t,mt,TMinTrace*);
3187  nt=1; /* So far we only have one trace */
3188  /* Init the first trace */
3189  NEW(t[0],1,TMinTrace);
3190  t[0]->st=0;
3191  t[0]->nc=0; /* Start the minimization from the first chart. */
3192  InitSamples(&(t[0]->ms),&(t[0]->ns),&(t[0]->path));
3193 
3194  NEW(g,k,double); /* gradient (in tangent space) */
3195  NEW(d,k,double); /* displacement */
3196  NEW(newPoint,a->m,double); /* new temptative point */
3197 
3198  /* Start by tracing the path from the given point */
3199  l=0;
3200 
3201  /* Add the first point to the path */
3202  currentPoint=GetChartCenter(a->charts[t[l]->nc]);
3203  CS_WD_REGENERATE_ORIGINAL_POINT(pr,currentPoint,&o,a->w);
3204  AddSample2Samples(nv,o,nvs,systemVars,&(t[l]->ms),&(t[l]->ns),&(t[l]->path));
3205  free(o);
3206 
3207  /* Compute the initial cost (debug purposes only) */
3208  cost=costF(pr,TRUE,currentPoint,costData);
3209  fprintf(stderr," Initial cost: %g\n",cost);
3210 
3211 
3212  stepSize=delta;
3213  ok=TRUE; /* if false at the end, indicates that we defined a chart at a singularity */
3214 
3215  while(l<nt)
3216  {
3217  done=FALSE;
3218 
3219  while (!done)
3220  {
3221  /* Point from where to continue the minimization */
3222  currentChart=a->charts[t[l]->nc];
3223  currentPoint=GetChartCenter(currentChart);
3224 
3225  /* Evaluation of -gradient */
3226  if (costG==NULL)
3227  {
3228  /* Numerical */
3229  cost=costF(pr,TRUE,currentPoint,costData);
3230 
3231  for(i=0;i<k;i++)
3232  d[i]=0;
3233 
3234  for(i=0;i<k;i++)
3235  {
3236  d[i]=100*epsilon;
3237  if (Chart2Manifold(pr,&(a->J),d,NULL,currentPoint,newPoint,currentChart)<INF)
3238  {
3239  cost1=costF(pr,TRUE,newPoint,costData);
3240  g[i]=-(cost1-cost)/(100*epsilon);
3241  }
3242  else
3243  Error("Can not converge to the manifold in MinimizeOnAtlas");
3244  d[i]=0.0;
3245  }
3246  }
3247  else
3248  {
3249  /* using a user-provided function */
3250  costG(pr,TRUE,currentPoint,&gFull,costData);
3251 
3252  if (a->k==a->m)
3253  memcpy(g,gFull,a->k*sizeof(double));
3254  else
3255  TMatrixVectorProduct(a->m,a->k,GetChartTangentSpace(currentChart),gFull,g);
3256 
3257  free(gFull);
3258 
3259  ScaleVector(-1,a->k,g);
3260  }
3261  ng=Norm(k,g);
3262  done=(Norm(k,g)<epsilon);
3263 
3264  if (!done)
3265  {
3266  /* start with a temptative step sizer of twice
3267  the size of last step */
3268  stepSize*=2;
3269  if (stepSize>delta)
3270  stepSize=delta;
3271 
3272  if (ng<stepSize)
3273  ScaleVector(stepSize/ng,k,g);
3274 
3275  pnc=a->currentChart; /* charts in the atlas before adding the new one */
3276 
3277  do {
3278  retraction=FALSE;
3279 
3280  if (Chart2Manifold(pr,&(a->J),g,NULL,currentPoint,newPoint,currentChart)>e)
3281  retraction=TRUE;
3282  else
3283  {
3284  cost1=costF(pr,TRUE,newPoint,costData);
3285  if (cost1>cost)
3286  retraction=TRUE;
3287  else
3288  {
3289  //AddChart2Atlas(pr,newPoint,t[l]->nc,&sing,a);
3290  AddChart2Atlas(pr,newPoint,NO_UINT,&sing,a);
3291  if (pnc==a->currentChart)
3292  retraction=TRUE;
3293  else
3294  {
3295  /* at least one chart created -> check it */
3296  done=FrontierChart(a->charts[pnc]);
3297  ok&=(!sing);
3298  }
3299  }
3300  }
3301 
3302  if (retraction)
3303  {
3304  ScaleVector(0.5,k,g);
3305  done=(Norm(k,g)<epsilon);
3306  stepSize*=0.5;
3307  }
3308  } while((retraction)&&(!done));
3309 
3310  if ((maxSteps<150)||(t[l]->st%100==1))
3311  {
3312  fprintf(stderr," Branch %u step %u: point: [%g %g ...]\n",l,t[l]->st,newPoint[0],newPoint[1]);
3313  fprintf(stderr," cost: %g\n",cost1);
3314  fprintf(stderr," norm gradient: %g\n",ng);
3315  fprintf(stderr," norm disp.: %g\n",Norm(k,g));
3316  }
3317 
3318  if (!done)
3319  {
3320  if (a->currentChart>pnc+1)
3321  {
3322  fprintf(stderr," ******* BIFURCATION *******\n");
3323  /* We stepped over a singularity -> bifurcate the path */
3324  /* duplicate the path */
3325  if (nt==mt)
3326  { MEM_DUP(t,mt,TMinTrace*); }
3327 
3328  NEW(t[nt],1,TMinTrace);
3329 
3330  InitSamples(&(t[nt]->ms),&(t[nt]->ns),&(t[nt]->path));
3331  for(j=0;j<t[l]->ns;j++)
3332  AddSample2Samples(nvs,t[l]->path[j],nvs,NULL,
3333  &(t[nt]->ms),&(t[nt]->ns),&(t[nt]->path));
3334  t[nt]->st=t[l]->st;
3335 
3336  /* Now extend the current path */
3337  currentPoint=GetChartCenter(a->charts[pnc+1]); /* point at bifurcation */
3338  CS_WD_REGENERATE_ORIGINAL_POINT(pr,currentPoint,&o,a->w);
3339  AddSample2Samples(nv,o,nvs,systemVars,&(t[l]->ms),&(t[l]->ns),&(t[l]->path));
3340  free(o);
3341  currentPoint=GetChartCenter(a->charts[pnc+0]); /* point at current branch (== newPoint) */
3342  CS_WD_REGENERATE_ORIGINAL_POINT(pr,currentPoint,&o,a->w);
3343  AddSample2Samples(nv,o,nvs,systemVars,&(t[l]->ms),&(t[l]->ns),&(t[l]->path));
3344  free(o);
3345  t[l]->nc=pnc+0;
3346 
3347  /* And extend the new path */
3348  currentPoint=GetChartCenter(a->charts[pnc+1]); /* point at bifurcation */
3349  CS_WD_REGENERATE_ORIGINAL_POINT(pr,currentPoint,&o,a->w);
3350  AddSample2Samples(nv,o,nvs,systemVars,&(t[nt]->ms),&(t[nt]->ns),&(t[nt]->path));
3351  free(o);
3352  currentPoint=GetChartCenter(a->charts[pnc+2]); /* point in new brach */
3353  CS_WD_REGENERATE_ORIGINAL_POINT(pr,currentPoint,&o,a->w);
3354  AddSample2Samples(nv,o,nvs,systemVars,&(t[nt]->ms),&(t[nt]->ns),&(t[nt]->path));
3355  free(o);
3356  t[nt]->nc=pnc+2;
3357 
3358  /* We have a new path already stareted */
3359  nt++;
3360  }
3361  else
3362  {
3363  /* Add the point to the path */
3364  currentPoint=GetChartCenter(a->charts[pnc]); /* == newPoint */
3365  CS_WD_REGENERATE_ORIGINAL_POINT(pr,currentPoint,&o,a->w);
3366  AddSample2Samples(nv,o,nvs,systemVars,&(t[l]->ms),&(t[l]->ns),&(t[l]->path));
3367  free(o);
3368  t[l]->nc=pnc;
3369  }
3370 
3371  t[l]->st++;
3372  done=(t[l]->st>maxSteps);
3373  }
3374  }
3375  }
3376 
3377  /* Continue next pending minimization path */
3378  l++;
3379  }
3380 
3381  free(d);
3382  free(g);
3383  free(newPoint);
3384 
3385  if (!ok)
3386  Warning("A singularity was detected during the minimization but it could not be determined if it was a bifurcation. Try a smaller epsilon or a larger delta?");
3387 
3388  /* Save the stored paths */
3389  if (nt==1)
3390  SaveSamples(fname,FALSE,nvs,t[0]->ns,t[0]->path);
3391  else
3392  {
3393  for(l=0;l<nt;l++)
3394  SaveSamplesN(fname,FALSE,l,nvs,t[l]->ns,t[l]->path);
3395  }
3396 
3397  free(systemVars);
3398 
3399  return(ok);
3400 }
3401 
3403 {
3404  return(a->r);
3405 }
3406 
3408 {
3409  return(a->e);
3410 }
3411 
3413 {
3414  return(a->ce);
3415 }
3416 
3418 {
3419  return(a->w);
3420 }
3421 
3422 unsigned int GetAtlasAmbientDim(Tatlas *a)
3423 {
3424  return(a->m);
3425 }
3426 
3427 unsigned int GetAtlasManifoldDim(Tatlas *a)
3428 {
3429  return(a->k);
3430 }
3431 
3432 boolean AtlasAStar(Tparameters *pr,double *p,double *time,
3433  double *pl,unsigned int *ns,double ***path,Tatlas *a)
3434 {
3435  Theap h;
3436  unsigned int i;
3437  TAtlasHeapElement he,he2,*hePtr;
3438  unsigned int *chartID;
3439  unsigned int mID;
3440  TAStarInfo *info,*infoID,*infoParent;
3441  /* The 'pred' must be stored apart to re-use the path reconstruction function */
3442  unsigned int *pred;
3443  boolean found;
3444  double *t;
3445  double epsilon;
3446  unsigned int nn,id;
3447  double c,dst;
3448  double *pID,*pmID;
3449  double *ps,*pWithDummies;
3450  double er;
3451  unsigned int nv;
3452  boolean *systemVars;
3453  unsigned int cm,cmPrev,mmPrev;
3454  TAtlasStatistics *st;
3455  unsigned int nc;
3456  unsigned int it;
3457  Tstatistics stime;
3458  double beta;
3459  boolean collision=FALSE;
3460  double maxTime;
3461  unsigned int maxCharts;
3462  unsigned int nce;
3463  unsigned int *vs; /* set of vertex indices (only used in parallel execution). */
3464  double **ts; /* set of vertex coordinates (only used in parallel execution). */
3465  Tchart **newCharts; /* set of generated charts (only used in parallel execution). */
3466 
3467  if (a->currentChart!=1)
3468  Error("AtlasAStar assumes an initial atlas with only one local chart");
3469 
3470  epsilon=GetParameter(CT_EPSILON,pr);
3471  beta=GetParameter(CT_ATLASGBF_BETA,pr);
3472  maxTime=GetParameter(CT_MAX_PLANNING_TIME,pr);
3473  maxCharts=(unsigned int)GetParameter(CT_MAX_CHARTS,pr);
3474 
3475  nv=CS_WD_GET_SYSTEM_VARS(&systemVars,a->w);
3476  CS_WD_REGENERATE_SOLUTION_POINT(pr,p,&pWithDummies,a->w);
3477  if (CS_WD_GENERATE_SIMPLIFIED_POINT(pr,pWithDummies,&ps,a->w)!=a->m)
3478  Error("Dimension missmatch in AtlasAStar");
3479  free(pWithDummies);
3480  if (a->n==0)
3481  er=0.0;
3482  else
3483  er=CS_WD_ERROR_IN_SIMP_EQUATIONS(pr,ps,a->w);
3484  if (er>epsilon)
3485  Error("Target point for the AtlasAStar is not on the manifold");
3486 
3487  collision=CS_WD_ORIGINAL_IN_COLLISION(pr,pWithDummies,NULL,a->w);
3488  if (collision)
3489  Warning("Target point for the AtlasAStar is in collision");
3490 
3491  InitHeap(sizeof(TAtlasHeapElement),
3496 
3497  NEW(t,a->k,double);
3498 
3499  NEW(info,a->maxCharts,TAStarInfo);
3500  NEW(pred,a->maxCharts,unsigned int);
3501 
3502  info[0].cost=0;
3503  info[0].heuristic=DistanceTopology(a->m,a->tp,ps,GetChartCenter(a->charts[0]));
3504  info[0].status=1; /*open*/
3505  pred[0]=NO_UINT;
3506 
3507  if (a->parallel)
3508  {
3509  st=NULL;
3510  NEW(chartID,a->nCores,unsigned int);
3511  NEW(newCharts,a->nCores,Tchart *);
3512  NEW(vs,a->nCores,unsigned int);
3513  NEW(ts,a->nCores,double*);
3514  for(i=0;i<a->nCores;i++)
3515  NEW(ts[i],a->k,double);
3516  }
3517  else
3518  {
3519  NEW(st,1,TAtlasStatistics);
3520  InitAtlasStatistics(st);
3521  }
3522 
3523  InitAtlasHeapElement(0,info[0].cost+info[0].heuristic,beta,&he);
3524  AddElement2Heap(NO_UINT,(void *)(&he),&h);
3525 
3526  found=FALSE;
3527 
3528  it=0;
3529 
3530  InitStatistics(a->nCores,0,&stime);
3531  *time=0.0;
3532 
3533  while ((!found)&&(!HeapEmpty(&h))&&(*time<maxTime)&&(a->currentChart<maxCharts))
3534  {
3535  if ((ATLAS_VERBOSE)||((it%1000)==0))
3536  {
3537  printf("Iteration %u (c:%u t:%g)\n",it,a->currentChart,*time);
3538  fflush(stdout);
3539  }
3540 
3541  ExtractMinElement((void *)(&he),&h);
3542  mID=GetAtlasHeapElementID(&he);
3543  infoParent=&(info[mID]);
3544 
3545  /* If the current chart already includes the goal we are done */
3546  if ((PointOnChart(pr,&(a->J),ps,a->tp,t,a->charts[mID]))&&
3547  (DistanceOnChart(pr,t,a->tp,&(a->J),a->charts[mID])<INF))
3548  found=TRUE;
3549  else
3550  {
3551  /* already closed element? The heap can hold alternative paths to
3552  the same node that have been improved over time. Instead of
3553  removing them from the heap as better paths are found we leave
3554  them as just ignore them when extracted.
3555  Moreover, we do not expand nodes whose cost is INF
3556  */
3557  if ((infoParent->status!=2)&&(infoParent->cost<INF))
3558  {
3559  cmPrev=a->currentChart;
3560  mmPrev=a->maxCharts;
3561 
3562  if (a->parallel)
3563  {
3564  while(ExpandibleChart(a->charts[mID]))
3565  {
3566  /* We have to genere new neighbors for chart 'mID'.
3567  Select up to 'nCores' other expandible charts and generate neighbours
3568  in parallel with the aim of saving time in future interations. */
3569  chartID[0]=mID;
3570  nce=1;
3571  i=0;
3572  while((i<HeapSize(&h))&&(nce<a->nCores))
3573  {
3574  hePtr=(TAtlasHeapElement*)GetHeapElement(i,&h); /* does not remove from heap */
3575 
3576  chartID[nce]=GetAtlasHeapElementID(hePtr);
3577  if (ExpandibleChart(a->charts[chartID[nce]]))
3578  nce++;
3579  i++;
3580  }
3581  #pragma omp parallel for private(i) schedule(static)
3582  for(i=0;i<nce;i++)
3583  {
3584  newCharts[i]=NULL;
3585  if (BoundaryPointFromExternalCorner(FALSE,&(vs[i]),ts[i],a->charts[chartID[i]]))
3586  {
3587  NewChartFromPoint(pr,chartID[i],ts[i],&(newCharts[i]),a);
3588 
3589  /* ensure that the selected corner is maked as "already used" */
3590  WrongCorner(vs[i],a->charts[chartID[i]]);
3591  }
3592  }
3593 
3594  /* Add the new charts to the atlas */
3595  for(i=0;i<nce;i++)
3596  {
3597  if (newCharts[i]!=NULL)
3598  {
3599  if (a->currentChart==a->maxCharts)
3600  MEM_DUP(a->charts,a->maxCharts,Tchart *);
3601 
3602  /* We directly re-use the charts to safe one copy. */
3603  a->charts[a->currentChart]=newCharts[i];
3604  a->currentChart++;
3605 
3606  /* Now detect neighbours and the possible bifurcations */
3607  PostProcessNewCharts(pr,TRUE,chartID[i],st,a);
3608  }
3609  }
3610  }
3611  }
3612  else
3613  {
3614  /* Generating all neighbours for this chart: one for each external vertex */
3615  while(ExpandibleChart(a->charts[mID]))
3616  {
3617  NewBoundaryAttempt(st);
3618  if (!BoundaryPointFromExternalCorner(FALSE,&nc,t,a->charts[mID]))
3619  {
3620  NewNotInBoundary(st);
3621  Error("Can not generate neighbouring charts");
3622  }
3623  else
3624  {
3625  ExtendAtlasFromPoint(pr,mID,t,st,a);
3626 
3627  /* ensure that the selected corner is maked as "already used" */
3628  WrongCorner(nc,a->charts[mID]);
3629  }
3630  } /* end of generate all neighbours */
3631  }
3632 
3633  /* set the A*-related information for the new charts */
3634  if (mmPrev<a->maxCharts)
3635  {
3636  MEM_EXPAND(info,a->maxCharts,TAStarInfo);
3637  MEM_EXPAND(pred,a->maxCharts,unsigned int);
3638  }
3639 
3640  for(cm=cmPrev;cm<a->currentChart;cm++)
3641  {
3642  /*Mark the new charts as un-visited*/
3643  info[cm].status=0;/* not open nor closed*/
3644  info[cm].heuristic=0;
3645  info[cm].cost=0;
3646  pred[cm]=NO_UINT;
3647  }
3648 
3649  /* Now that we have all the neighbours explicited proceed with
3650  the A* */
3651  pmID=GetChartCenter(a->charts[mID]);
3652 
3653  nn=ChartNumNeighbours(a->charts[mID]);
3654  for(i=0;i<nn;i++)
3655  {
3656  id=ChartNeighbourID(i,a->charts[mID]);
3657  if (id!=NO_UINT)
3658  {
3659  infoID=&(info[id]);
3660 
3661  #if (_DEBUG>3)
3662  printf(" N[%u->%u][%u] : ",mID,id,infoID->status);
3663  #endif
3664 
3665  if (infoID->status!=2) /*not closed (closed can not be improved)*/
3666  {
3667  pID=GetChartCenter(a->charts[id]);
3668 
3669  /* Geodesic distance is more accurate than euclidean and
3670  includes the presence of obstacles, if any. If obstacles
3671  are for sure not present, we just use the Euclidean
3672  distance.
3673 
3674  Caution: The GeodesicDistance function is not always
3675  able to find the path when it exists. This can induce
3676  sub-optimatility in the search. Moreover, the returned
3677  path is not the true geodesic, but at least is a path
3678  on the manifold. Use with caution.
3679  */
3680  if (ON_CUIKSYSTEM(a->w))
3681  dst=DistanceTopology(a->m,a->tp,pmID,pID);
3682  else
3683  dst=GeodesicDistance(pr,mID,id,a); /* This might be parallelized */
3684 
3685  c=infoParent->cost+dst;
3686 
3687  if ((infoID->status==0)|| /* 1st time we see this node */
3688  (c<infoID->cost)) /* status must be 1 (open) */
3689  {
3690  #if (_DEBUG>3)
3691  if (infoID->status==0)
3692  printf("new %g -> %g\n",dst,c);
3693  else
3694  printf("cheaper %g -> %g<%g\n",dst,c,infoID->cost);
3695  #endif
3696  /*not open not closed (1st time we see this node) */
3697  pred[id]=mID;
3698  infoID->cost=c;
3699  infoID->heuristic=DistanceTopology(a->m,a->tp,pID,ps);
3700 
3701  /* if open we are re-adding it to the heap. The cheapest
3702  path will have higher priority in the heap. */
3703  InitAtlasHeapElement(id,infoID->cost+infoID->heuristic,beta,
3704  &he2);
3705  AddElement2Heap(NO_UINT,(void *)(&he2),&h);
3706 
3707  infoID->status=1; /*open*/
3708  }
3709  #if (_DEBUG>3)
3710  else
3711  printf("%g > %g\n",c,infoID->cost);
3712  #endif
3713  }
3714  #if (_DEBUG>3)
3715  else
3716  printf("closed (%g)\n",infoID->cost);
3717  #endif
3718  }
3719  }
3720 
3721  infoParent->status=2; /*we close the current node node (all neighbors already explored) */
3722 
3723  } /*alrady closed element*/
3724  } /*if objective found*/
3725 
3726  it++;
3727  *time=GetElapsedTime(&stime);
3728  } /*loop until objective found*/
3729 
3730  DeleteStatistics(&stime);
3731 
3732  /* Use the pred to reconstruct the path */
3733  if (found)
3734  ReconstructAtlasPath(pr,pred,mID,ps,nv,systemVars,pl,ns,path,a);
3735  else
3736  {
3737  *ns=0;
3738  path=NULL;
3739  }
3740 
3741  if (a->parallel)
3742  {
3743  free(chartID);
3744  free(newCharts);
3745  free(vs);
3746  for(i=0;i<a->nCores;i++)
3747  free(ts[i]);
3748  free(ts);
3749  }
3750 
3751  if (st!=NULL)
3752  {
3753  PrintAtlasStatistics(pr,st);
3754  free(st);
3755  }
3756 
3757  free(info);
3758  free(pred);
3759 
3760  free(t);
3761  free(ps);
3762  DeleteHeap(&h);
3763  free(systemVars);
3764 
3765  return(found);
3766 }
3767 
3768 boolean AtlasGBF(Tparameters *pr,double *p,double *time,
3769  double *pl,unsigned int *ns,double ***path,Tatlas *a)
3770 {
3771  Theap h;
3772  TAtlasHeapElement he,he2;
3773  unsigned int mID;
3774  double heuristic;
3775  unsigned int *pred;
3776  boolean found;
3777  double *t;
3778  double epsilon;
3779  double *ps,*pWithDummies;
3780  double er;
3781  unsigned int nv;
3782  boolean *systemVars;
3783  unsigned int cm,cmPrev,mmPrev;
3784  TAtlasStatistics st;
3785  unsigned int it;
3786  Tstatistics stime;
3787  double beta;
3788  boolean collision=FALSE;
3789  double maxTime;
3790  unsigned int maxCharts;
3791 
3792  if (a->currentChart!=1)
3793  Error("Connect2Atlas assumes an initial atlas with only one local chart");
3794 
3795  epsilon=GetParameter(CT_EPSILON,pr);
3796  beta=GetParameter(CT_ATLASGBF_BETA,pr);
3797  maxTime=GetParameter(CT_MAX_PLANNING_TIME,pr);
3798  maxCharts=(unsigned int)GetParameter(CT_MAX_CHARTS,pr);
3799 
3800  nv=CS_WD_GET_SYSTEM_VARS(&systemVars,a->w);
3801 
3802  CS_WD_REGENERATE_SOLUTION_POINT(pr,p,&pWithDummies,a->w);
3803  if (CS_WD_GENERATE_SIMPLIFIED_POINT(pr,pWithDummies,&ps,a->w)!=a->m)
3804  Error("Dimension missmatch in AtlasGBF");
3805  if (a->n==0)
3806  er=0.0;
3807  else
3808  er=CS_WD_ERROR_IN_SIMP_EQUATIONS(pr,ps,a->w);
3809  if (er>epsilon)
3810  Error("Target point for the AtlasGBF is not on the manifold");
3811 
3812  collision=CS_WD_ORIGINAL_IN_COLLISION(pr,pWithDummies,NULL,a->w);
3813  if (collision)
3814  Warning("Target point for the AtlasGBF is in collision");
3815  free(pWithDummies);
3816 
3817  InitHeap(sizeof(TAtlasHeapElement),
3822 
3823  NEW(t,a->k,double);
3824 
3825  NEW(pred,a->maxCharts,unsigned int);
3826 
3827  heuristic=DistanceTopology(a->m,a->tp,GetChartCenter(a->charts[0]),ps);
3828  pred[0]=NO_UINT;
3829 
3830  InitAtlasStatistics(&st);
3831 
3832  InitAtlasHeapElement(0,heuristic,beta,&he);
3833  AddElement2Heap(NO_UINT,(void *)(&he),&h);
3834 
3835  found=FALSE;
3836 
3837  it=0;
3838  InitStatistics(a->nCores,0,&stime);
3839  *time=0.0;
3840 
3841  while ((!found)&&(!HeapEmpty(&h))&&(*time<maxTime)&&(a->currentChart<maxCharts))
3842  {
3843  ExtractMinElement((void *)(&he),&h);
3844  mID=GetAtlasHeapElementID(&he);
3845 
3846  if ((ATLAS_VERBOSE)||((it%1000)==0))
3847  {
3848  printf("Iteration %u (c:%u t:%g)\n",it,a->currentChart,*time);
3849  fflush(stdout);
3850  }
3851 
3852  if ((PointOnChart(pr,&(a->J),ps,a->tp,t,a->charts[mID]))&&
3853  (DistanceOnChart(pr,t,a->tp,&(a->J),a->charts[mID])<INF))
3854  found=TRUE;
3855  else
3856  {
3857  if (ExpandibleChart(a->charts[mID]))
3858  {
3859  NewBoundaryAttempt(&st);
3860 
3861  if (!RandomPointOnBoundary(t,a->charts[mID]))
3862  {
3863  NewNotInBoundary(&st);
3865  }
3866  else
3867  {
3868  /*printf(" New random point: ");PrintVector(stdout,a->k,t);*/
3869 
3870  cmPrev=a->currentChart;
3871  mmPrev=a->maxCharts;
3872  if (ExtendAtlasTowardPoint(pr,mID,t,TRUE,&st,a))
3873  {
3874  /* If we extended the room for charts, we have to
3875  extend the associated information accordingly*/
3876  if (mmPrev<a->maxCharts)
3877  MEM_EXPAND(pred,a->maxCharts,unsigned int);
3878 
3879  for(cm=cmPrev;cm<a->currentChart;cm++)
3880  {
3881  pred[cm]=mID;
3882  heuristic=DistanceTopology(a->m,a->tp,
3883  GetChartCenter(a->charts[cm]),
3884  ps);
3885  InitAtlasHeapElement(cm,heuristic,beta,&he2);
3886  AddElement2Heap(NO_UINT,(void *)(&he2),&h);
3887  }
3888  }
3889  else
3891  }
3892 
3893  AddElement2Heap(NO_UINT,(void *)(&he),&h);
3894  } /* if ExpandibleChart() = chart that can be expanded*/
3895  } /*if objective found*/
3896 
3897  it++;
3898  *time=GetElapsedTime(&stime);
3899  } /*loop until objective found*/
3900  DeleteStatistics(&stime);
3901 
3902  /* Use the pred to reconstruct the path */
3903  if (found)
3904  ReconstructAtlasPath(pr,pred,mID,ps,nv,systemVars,pl,ns,path,a);
3905  else
3906  {
3907  *ns=0;
3908  path=NULL;
3909  }
3910 
3911  PrintAtlasStatistics(pr,&st);
3912 
3913  free(pred);
3914  free(t);
3915  free(ps);
3916  DeleteHeap(&h);
3917  free(systemVars);
3918 
3919  return(found);
3920 }
3921 
3922 unsigned int AtlasMemSize(Tatlas *a)
3923 {
3924  unsigned int b,i;
3925 
3926  b=0;
3927  for(i=0;i<a->currentChart;i++)
3928  b+=ChartMemSize(a->charts[i]); /* charts[][] */
3929 
3930  return(b);
3931 }
3932 
3934 {
3935  FILE *f;
3936  unsigned int i;
3937 
3938  f=fopen(GetFileFullName(fname),"w");
3939  if (!f)
3940  Error("Could not open fiel to store atlas");
3941 
3942  fprintf(f,"%u\n",a->m);
3943  fprintf(f,"%u\n",a->k);
3944  fprintf(f,"%u\n",a->n);
3945  fprintf(f,"%.12f\n",a->e);
3946  fprintf(f,"%.12f\n",a->ce);
3947  fprintf(f,"%.12f\n",a->r);
3948  fprintf(f,"%u\n",a->simpleChart);
3949 
3950  fprintf(f,"%u\n",a->maxCharts);
3951  fprintf(f,"%u\n",a->currentChart);
3952  for(i=0;i<a->currentChart;i++)
3953  SaveChart(f,a->charts[i]);
3954 
3955  SaveBifurcations(f,a);
3956 
3957  fclose(f);
3958 }
3959 
3961 {
3962  FILE *f;
3963  unsigned int i;
3964 
3965  f=fopen(GetFileFullName(fname),"r");
3966  if (!f)
3967  Error("Could not open file to read atlas");
3968 
3969  fscanf(f,"%u",&(a->m));
3970  fscanf(f,"%u",&(a->k));
3971  fscanf(f,"%u",&(a->n));
3972  fscanf(f,"%lf",&(a->e));
3973  fscanf(f,"%lf",&(a->ce));
3974  fscanf(f,"%lf",&(a->r));
3975  fscanf(f,"%u",&(a->simpleChart));
3976 
3977  a->w=w;
3978 
3979  NEW(a->ambient,1,Tbox);
3981 
3982  SetAtlasTopology(pr,a);
3983 
3984  fscanf(f,"%u",&(a->maxCharts));
3985  fscanf(f,"%u",&(a->currentChart));
3986  NEW(a->charts,a->maxCharts,Tchart *);
3987  for(i=0;i<a->currentChart;i++)
3988  {
3989  NEW(a->charts[i],1,Tchart);
3990  LoadChart(f,a->w,a->charts[i]);
3991 
3992  #if (USE_ATLAS_TREE)
3993  if (i==0)
3994  InitBTree(i,a->charts[i],a->ambient,a->tp,&(a->tree));
3995  else
3996  AddChart2Btree(i,a->charts[i],&(a->tree));
3997  #endif
3998  }
3999 
4000  LoadBifurcations(f,a);
4001 
4002  fclose(f);
4003 
4004  /* The Jacobian is not saved but re-computed */
4005  CS_WD_GET_SIMP_JACOBIAN(pr,&(a->J),a->w);
4006  GetJacobianSize(&(a->nrJ),&(a->ncJ),&(a->J));
4007 
4008  /* delay the Hessian computation */
4009  a->H=NULL;
4010 
4011  /* The parallelism information is not stored! */
4012  #ifdef _OPENMP
4013  a->nCores=omp_get_max_threads();
4014  a->parallel=((a->nCores>1)&&((a->m>25)||(a->k>2)));
4015  #else
4016  a->parallel=FALSE;
4017  #endif
4018 
4019  if (!a->parallel)
4020  a->nCores=1;
4021 }
4022 
4023 unsigned int GetAtlasNumCharts(Tatlas *a)
4024 {
4025  return(a->currentChart);
4026 }
4027 
4028 Tchart *GetAtlasChart(unsigned int id,Tatlas *a)
4029 {
4030  if (id<a->currentChart)
4031  return(a->charts[id]);
4032  else
4033  return(NULL);
4034 }
4035 
4036 boolean RandomPointInAtlas(Tparameters *pr,double scale,double *w,
4037  unsigned int *nm,
4038  double *t,double *p,Tatlas *a)
4039 {
4040  boolean havePoint;
4041 
4042  if (w==NULL)
4043  {
4044  /* Uniform distribution on charts*/
4045  *nm=randomMax(a->currentChart-1);
4046  }
4047  else
4048  {
4049  /* Select the charts from the given distribution */
4051  }
4052  /* Get a point from the selected chart */
4053  havePoint=RandomPointInChart(pr,scale,a->tp,t,p,a->charts[*nm]);
4054 
4055  return(havePoint);
4056 }
4057 
4058 double AtlasVolume(Tparameters *pr,boolean collisionFree,Tatlas *a)
4059 {
4060  unsigned int i;
4061  double v,vc;
4062 
4063  v=0.0;
4064  for(i=0;i<a->currentChart;i++)
4065  {
4066  if (!FrontierChart(a->charts[i]))
4067  {
4068  vc=ChartVolume(pr,collisionFree,a->tp,&(a->J),a->charts[i]);
4069  #if (ATLAS_VERBOSE)
4070  printf(" Volume of chart %u: %g\n",i,vc);
4071  #endif
4072  v+=vc;
4073  }
4074  }
4075 
4076  return(v);
4077 }
4078 
4079 void SaveAtlasGraph(char *fname,Tatlas *a)
4080 {
4081  Tfilename fg;
4082  FILE *f;
4083  unsigned int i,j,n;
4084 
4085  CreateFileName(NULL,fname,NULL,ATLAS_GRAPH_EXT,&fg);
4086  f=fopen(GetFileFullName(&fg),"w");
4087  if (!f)
4088  Error("Could not open the file to store the atlas graph in SaveAtlasGraph");
4089  fprintf(stderr,"Writing atlas graph to : %s\n",GetFileFullName(&fg));
4090 
4091  fprintf(f,"%u\n",a->currentChart);
4092  for(i=0;i<a->currentChart;i++)
4093  {
4094  n=ChartNumNeighbours(a->charts[i]);
4095  fprintf(f,"%u ",n);
4096  for(j=0;j<n;j++)
4097  fprintf(f,"%u ",ChartNeighbourID(j,a->charts[i]));
4098  fprintf(f,"\n");
4099  }
4100 
4101  fclose(f);
4102  DeleteFileName(&fg);
4103 }
4104 
4105 void SaveChartCenters(Tparameters *pr,char *fname,
4106  boolean saveWithDummies,Tatlas *a)
4107 {
4108  double *o;
4109  unsigned int i,j,nv,nvs;
4110  boolean *systemVars;
4111  double *c;
4112  FILE *fo;
4113  Tfilename fsol;
4114 
4115  if (saveWithDummies)
4116  CreateFileName(NULL,fname,"_center",SOL_WITH_DUMMIES_EXT,&fsol);
4117  else
4118  CreateFileName(NULL,fname,"_center",SOL_EXT,&fsol);
4119  fprintf(stderr,"Writing boxes to : %s\n",GetFileFullName(&fsol));
4120  fo=fopen(GetFileFullName(&fsol),"w");
4121  if (!fo)
4122  Error("Could not open the file to store the boxes in GetChartCenters");
4123 
4124  nv=CS_WD_GET_SYSTEM_VARS(&systemVars,a->w);
4125  nvs=0;
4126  for(j=0;j<nv;j++)
4127  {
4128  if (systemVars[j])
4129  nvs++;
4130  }
4131 
4132  for(i=0;i<a->currentChart;i++)
4133  {
4134  c=GetChartCenter(a->charts[i]);
4135 
4136  CS_WD_REGENERATE_ORIGINAL_POINT(pr,c,&o,a->w);
4137 
4138  if (saveWithDummies)
4139  fprintf(fo,"%u { %u ",i,nv);
4140  else
4141  fprintf(fo,"%u { %u ",i,nvs);
4142  for(j=0;j<nv;j++)
4143  {
4144  if ((saveWithDummies)||(systemVars[j]))
4145  fprintf(fo,"[%.12g,%.12g] ",o[j],o[j]);
4146  }
4147  fprintf(fo,"}\n");
4148 
4149  free(o);
4150  }
4151 
4152  fclose(fo);
4153 
4154  free(systemVars);
4155 
4156  DeleteFileName(&fsol);
4157 }
4158 
4159 void SaveSingularCharts(Tparameters *pr,char *fname,
4160  boolean saveWithDummies,Tatlas *a)
4161 {
4162  double *o;
4163  unsigned int i,j,nv,nvs;
4164  boolean *systemVars;
4165  double *c;
4166  FILE *fo;
4167  Tfilename fsol;
4168 
4169  if (saveWithDummies)
4170  CreateFileName(NULL,fname,"_singular",SOL_WITH_DUMMIES_EXT,&fsol);
4171  else
4172  CreateFileName(NULL,fname,"_singular",SOL_EXT,&fsol);
4173  fprintf(stderr,"Writing boxes to : %s\n",GetFileFullName(&fsol));
4174  fo=fopen(GetFileFullName(&fsol),"w");
4175  if (!fo)
4176  Error("Could not open the file to store the boxes in GetChartCenters");
4177 
4178  nv=CS_WD_GET_SYSTEM_VARS(&systemVars,a->w);
4179  nvs=0;
4180  for(j=0;j<nv;j++)
4181  {
4182  if (systemVars[j])
4183  nvs++;
4184  }
4185 
4186  for(i=0;i<a->currentChart;i++)
4187  {
4188  if (SingularChart(a->charts[i]))
4189  {
4190  c=GetChartCenter(a->charts[i]);
4191 
4192  CS_WD_REGENERATE_ORIGINAL_POINT(pr,c,&o,a->w);
4193 
4194  if (saveWithDummies)
4195  fprintf(fo,"%u { %u ",i,nv);
4196  else
4197  fprintf(fo,"%u { %u ",i,nvs);
4198  for(j=0;j<nv;j++)
4199  {
4200  if ((saveWithDummies)||(systemVars[j]))
4201  fprintf(fo,"[%.12g,%.12g] ",o[j],o[j]);
4202  }
4203  fprintf(fo,"}\n");
4204 
4205  free(o);
4206  }
4207  }
4208  fclose(fo);
4209 
4210  free(systemVars);
4211 
4212  DeleteFileName(&fsol);
4213 }
4214 
4215 void PlotAtlas(char *fname,int argc,char **arg,Tparameters *pr,FILE *fcost,
4216  unsigned int xID,unsigned int yID,unsigned int zID,Tatlas *a)
4217 {
4218  Tplot3d p3d;
4219  unsigned int i;
4220  Tcolor color;
4221  unsigned int obj,np;
4222 
4223  InitPlot3d(fname,FALSE,argc,arg,&p3d);
4224 
4225  /* When plotting as polytopes all charts are plotted in blue and not
4226  bifurcation info is plotted */
4227 
4228  NewColor(0.5,0.5,1,&color); /*default color :blue*/
4229  obj=StartNew3dObject(&color,&p3d);
4230  np=0;
4231  for(i=0;i<a->currentChart;i++)
4232  {
4233  if ((fcost!=NULL)||(a->simpleChart)||
4235  (!SingularChart(a->charts[i])&&(!FrontierChart(a->charts[i])))))
4236  {
4237  PlotChart(pr,fcost,&(a->J),xID,yID,zID,&p3d,a->charts[i]);
4238  //PrintVector(stderr,NULL,a->m,a->charts[i]->center);
4239  np++;
4240  }
4241  }
4242  if ((a->k==2)&&(fcost!=NULL))
4243  Close3dObjectNoColor(&p3d); /* the cost already gave the color when plotting */
4244  else
4245  Close3dObject(&p3d);
4246  if (np==0)
4247  Delete3dObject(obj,&p3d);
4248  DeleteColor(&color);
4249 
4250  if ((PLOT_ATLAS_IN_COLORS)&&(fcost==NULL)&&(!a->simpleChart))
4251  {
4252  /* Singular charts in green */
4253  NewColor(0,1,0,&color); /*green*/
4254  obj=StartNew3dObject(&color,&p3d);
4255  np=0;
4256  for(i=0;i<a->currentChart;i++)
4257  {
4258  if ((!ExpandibleChart(a->charts[i]))&&(SingularChart(a->charts[i])&&(!FrontierChart(a->charts[i]))))
4259  {
4260  np++;
4261  PlotChart(pr,NULL,&(a->J),xID,yID,zID,&p3d,a->charts[i]);
4262  //PrintVector(stderr,NULL,a->m,a->charts[i]->center);
4263  }
4264  }
4265 
4266  Close3dObject(&p3d);
4267  DeleteColor(&color);
4268  if (np==0)
4269  Delete3dObject(obj,&p3d);
4270 
4271  /* Open charts if red (Open = expansion is still possible) */
4272  NewColor(1,0.5,0.5,&color); /*red*/
4273  obj=StartNew3dObject(&color,&p3d);
4274  np=0;
4275  for(i=0;i<a->currentChart;i++)
4276  {
4277  if ((ExpandibleChart(a->charts[i]))&&(!SingularChart(a->charts[i])&&(!FrontierChart(a->charts[i]))))
4278  {
4279  np++;
4280  PlotChart(pr,NULL,&(a->J),xID,yID,zID,&p3d,a->charts[i]);
4281  }
4282  }
4283 
4284  Close3dObject(&p3d);
4285  DeleteColor(&color);
4286  if (np==0)
4287  Delete3dObject(obj,&p3d);
4288 
4289  /* Expandible singular charts in yellow */
4290  NewColor(1,1,0,&color); /*yellow*/
4291  obj=StartNew3dObject(&color,&p3d);
4292  np=0;
4293  for(i=0;i<a->currentChart;i++)
4294  {
4295  if ((ExpandibleChart(a->charts[i]))&&(SingularChart(a->charts[i])&&(!FrontierChart(a->charts[i]))))
4296  {
4297  np++;
4298  PlotChart(pr,NULL,&(a->J),xID,yID,zID,&p3d,a->charts[i]);
4299  }
4300  }
4301 
4302  Close3dObject(&p3d);
4303  DeleteColor(&color);
4304  if (np==0)
4305  Delete3dObject(obj,&p3d);
4306 
4307  /* Frontier charts in dark red */
4308  NewColor(0.25,0,0,&color); /* */
4309  obj=StartNew3dObject(&color,&p3d);
4310  np=0;
4311  for(i=0;i<a->currentChart;i++)
4312  {
4313  //if ((!ExpandibleChart(a->charts[i]))&&(!SingularChart(a->charts[i])&&(FrontierChart(a->charts[i]))))
4314  if (FrontierChart(a->charts[i]))
4315  {
4316  np++;
4317  PlotChart(pr,NULL,&(a->J),xID,yID,zID,&p3d,a->charts[i]);
4318  }
4319  }
4320 
4321  Close3dObject(&p3d);
4322  DeleteColor(&color);
4323  if (np==0)
4324  Delete3dObject(obj,&p3d);
4325 
4326  /* Now plot a line connecting chart at the two sides of a singularity */
4327  //PlotBifurcations(pr,&p3d,xID,yID,zID,a);
4328  }
4329 
4330  /*line for the neighbouring relations*/
4331 #if (0)
4332  {
4333  unsigned int j;
4334  double *pi,*pj;
4335  double x[2],y[2],z[2];
4336  unsigned int nn,nj;
4337  double *o;
4338 
4339  NewColor(1,1,0,&color);
4340  StartNew3dObject(&color,&p3d);
4341  for(i=0;i<a->currentChart;i++)
4342  {
4343  pi=GetChartCenter(a->charts[i]);
4344  CS_WD_REGENERATE_ORIGINAL_POINT(pr,pi,&o,a->w);
4345  x[0]=o[xID];
4346  y[0]=o[yID];
4347  z[0]=o[zID];
4348  free(o);
4349 
4350  nn=ChartNumNeighbours(a->charts[i]);
4351  if (nn==0)
4352  fprintf(stderr,"Chart %u has no neighbours",i);
4353  for(j=0;j<nn;j++)
4354  {
4355  nj=ChartNeighbourID(j,a->charts[i]);
4356  if ((nj!=NO_UINT)&&(nj>i))
4357  {
4358  pj=GetChartCenter(a->charts[nj]);
4359  CS_WD_REGENERATE_ORIGINAL_POINT(pr,pj,&o,a->w);
4360  x[1]=o[xID];
4361  y[1]=o[yID];
4362  z[1]=o[zID];
4363  free(o);
4364  PlotVect3d(2,x,y,z,&p3d);
4365  }
4366  }
4367  }
4368  Close3dObject(&p3d);
4369  DeleteColor(&color);
4370  }
4371 #endif
4372 
4373  ClosePlot3d(FALSE,&p3d);
4374 }
4375 
4376 void TriangulateAtlas(char *fname,int argc,char **arg,Tparameters *pr,FILE *fcost,
4377  unsigned int xID,unsigned int yID,unsigned int zID,Tatlas *a)
4378 {
4379  Tplot3d p3d;
4380  unsigned int i,j,k;
4381  Tcolor color;
4382  double *p,*o;
4383  double cost;
4384  double **v; /* Vertices */
4385  Tcolor *c; /* One color per vertex (might not be used) */
4386  unsigned int mf,nf; /* Max faces (space allocated for faces) and current number
4387  of faces */
4388  unsigned int *nvf,**fv; /* Vertex per face, and vertices in each face. */
4389  unsigned int nTmp;
4390  double v1[3],v2[3],cosAngle;
4391  boolean *corrected,*used;
4392  double **normal;
4393  unsigned int nc;
4394  boolean correctionDone;
4395  unsigned int nn,*nID1,*nID2;
4396  boolean found;
4397  unsigned int *tp;
4398  unsigned int rep;
4399  double cx,cy,cz;
4400 
4401  if (a->k!=2)
4402  Error("TriangulateAtlas only operates on surfaces (manifold dim=2)");
4403 
4404  NEW(tp,3,unsigned int);
4405  tp[0]=CS_WD_GET_VAR_TOPOLOGY(xID,a->w);
4406  tp[1]=CS_WD_GET_VAR_TOPOLOGY(yID,a->w);
4407  tp[2]=CS_WD_GET_VAR_TOPOLOGY(zID,a->w);
4408 
4409  if ((tp[0]==TOPOLOGY_R)&&(tp[1]==TOPOLOGY_R)&&(tp[2]==TOPOLOGY_R))
4410  {
4411  free(tp);
4412  tp=NULL;
4413  }
4414 
4415  InitPlot3d(fname,FALSE,argc,arg,&p3d);
4416 
4417  /* Now store the vertices, one per chart (i.e., the center), possibly
4418  with associated colors */
4419  NEW(v,a->currentChart,double*);
4420  if (fcost!=NULL)
4421  NEW(c,a->currentChart,Tcolor);
4422 
4423  cx=GetParameter(CT_CUT_X,pr);
4424  cy=GetParameter(CT_CUT_Y,pr);
4425  cz=GetParameter(CT_CUT_Z,pr);
4426  rep=(unsigned int)(GetParameter(CT_REPRESENTATION,pr));
4427 
4428  for(i=0;i<a->currentChart;i++)
4429  {
4430  NEW(v[i],3,double);
4431  p=GetChartCenter(a->charts[i]);
4432  CS_WD_REGENERATE_ORIGINAL_POINT(pr,p,&o,a->w);
4433  v[i][0]=o[xID];
4434  v[i][1]=o[yID];
4435  v[i][2]=o[zID];
4436  if (rep==REP_JOINTS)
4437  {
4438  if ((cx<0)&&(v[i][0]<cx))
4439  v[i][0]+=M_2PI;
4440  if ((cx>0)&&(v[i][0]>cx))
4441  v[i][0]-=M_2PI;
4442  if ((cy<0)&&(v[i][1]<cy))
4443  v[i][1]+=M_2PI;
4444  if ((cy>0)&&(v[i][1]>cy))
4445  v[i][1]-=M_2PI;
4446  if ((cz<0)&&(v[i][2]<cz))
4447  v[i][2]+=M_2PI;
4448  if ((cz>0)&&(v[i][2]>cz))
4449  v[i][2]-=M_2PI;
4450  }
4451  free(o);
4452  if (fcost!=NULL)
4453  {
4454  /* Set up the color for this vertex */
4455  if (fscanf(fcost,"%lf",&cost)!=1)
4456  Error("No enough data in the cost file");
4457 
4458  CostColor(cost,1e-1,&(c[i]));
4459  }
4460  }
4461 
4462  /* Now set up the faces */
4463  mf=a->currentChart;
4464  nf=0;
4465  NEW(fv,mf,unsigned int*);
4466  for(i=0;i<a->currentChart;i++)
4467  {
4468  GetChartNeighboursFromVertices(pr,&nn,&nID1,&nID2,a->charts[i]);
4469  for(j=0;j<nn;j++)
4470  {
4471  /* Vertices corresponding to the border of the atlas still
4472  have the default faces with NO_UINT as ID -> not use these
4473  vertices*/
4474  if ((nID1[j]!=NO_UINT)&&(nID2[j]!=NO_UINT))
4475  {
4476  if (nf==mf)
4477  MEM_DUP(fv,mf,unsigned int*);
4478  NEW(fv[nf],3,unsigned int);
4479 
4480  fv[nf][0]=i;
4481  fv[nf][1]=nID1[j];
4482  fv[nf][2]=nID2[j];
4483 
4484  /* Triangles that cross the borders imposed by the topology
4485  should not be considered. */
4486  if (tp==NULL)
4487  found=FALSE;
4488  else
4489  {
4490  /*
4491  found=((CrossTopologyBorder(a->m,a->tp,
4492  GetChartCenter(a->charts[i]),
4493  GetChartCenter(a->charts[nID1[j]])))||
4494  (CrossTopologyBorder(a->m,a->tp,
4495  GetChartCenter(a->charts[i]),
4496  GetChartCenter(a->charts[nID2[j]])))||
4497  (CrossTopologyBorder(a->m,a->tp,
4498  GetChartCenter(a->charts[nID1[j]]),
4499  GetChartCenter(a->charts[nID1[j]]))));
4500  */
4501  found=((CrossTopologyBorder(3,tp,
4502  v[i],
4503  v[nID1[j]]))||
4504  (CrossTopologyBorder(3,tp,
4505  v[i],
4506  v[nID2[j]]))||
4507  (CrossTopologyBorder(3,tp,
4508  v[nID1[j]],
4509  v[nID2[j]])));
4510  }
4511 
4512  k=0;
4513  while ((!found)&&(k<nf))
4514  {
4515  found=SameTriangle(fv[nf],fv[k]);
4516  k++;
4517  }
4518  if (!found)
4519  nf++;
4520  }
4521  }
4522  free(nID1);
4523  free(nID2);
4524  }
4525  if (tp!=NULL)
4526  free(tp);
4527 
4528  /* All faces have 3 vertices */
4529  NEW(nvf,nf,unsigned int);
4530  for(i=0;i<nf;i++)
4531  nvf[i]=3;
4532  /* Fix the orientation for the triangles */
4533  NEW(used,nf,boolean);
4534  NEW(corrected,nf,boolean);
4535  NEW(normal,nf,double*);
4536  for(i=0;i<nf;i++)
4537  {
4538  used[i]=FALSE;
4539  corrected[i]=FALSE;
4540  NEW(normal[i],3,double);
4541  }
4542  /* Start from the first triangle */
4543  corrected[0]=TRUE;
4544  DifferenceVector(3,v[fv[0][1]],v[fv[0][0]],v1);
4545  DifferenceVector(3,v[fv[0][2]],v[fv[0][0]],v2);
4546  CrossProduct(v1,v2,normal[0]);
4547  nc=1;
4548  correctionDone=FALSE;
4549  while((!correctionDone)&&(nc<nf))
4550  {
4551  /* Search for a corrected no used face */
4552  i=0;
4553  while ((i<nf)&&((used[i])||(!corrected[i])))
4554  i++;
4555  if (i==nf)
4556  correctionDone=TRUE;
4557 
4558  if (!correctionDone)
4559  {
4560  /* Align all neighbours with the normal at this face */
4561  j=0;
4562  while(j<nf)
4563  {
4564  if (!corrected[j])
4565  {
4566  if (NeighbouringTriangles(fv[i],fv[j]))
4567  {
4568  DifferenceVector(3,v[fv[j][1]],v[fv[j][0]],v1);
4569  DifferenceVector(3,v[fv[j][2]],v[fv[j][0]],v2);
4570  CrossProduct(v1,v2,normal[j]);
4571 
4572  cosAngle=DotProduct(normal[i],normal[j]);
4573  if (cosAngle<0)
4574  {
4575  /* Swap the orientation of face j */
4576  nTmp=fv[j][1];
4577  fv[j][1]=fv[j][2];
4578  fv[j][2]=nTmp;
4579  ScaleVector(-1.0,3,normal[j]);
4580  }
4581  corrected[j]=TRUE;
4582  nc++;
4583  }
4584  }
4585  j++;
4586  }
4587  used[i]=TRUE;
4588  }
4589  }
4590  free(used);
4591  free(corrected);
4592  for(i=0;i<nf;i++)
4593  free(normal[i]);
4594  free(normal);
4595 
4596  /* Define the object */
4597  /* Normal charts in blue */
4598  NewColor(-1,-1,-1,&color); /*blue*/
4599  StartNew3dObject(&color,&p3d);
4600 
4601  if (fcost==NULL)
4602  Plot3dObject(a->currentChart,nf,1,v,nvf,fv,&p3d);
4603  else
4604  Plot3dObjectWithColors(a->currentChart,nf,1,v,c,nvf,fv,&p3d);
4605 
4606  Close3dObject(&p3d);
4607  ClosePlot3d(FALSE,&p3d);
4608 
4609  /* Release memory */
4610  for(i=0;i<a->currentChart;i++)
4611  free(v[i]);
4612  free(v);
4613 
4614  if (fcost!=NULL)
4615  free(c);
4616 
4617  for(i=0;i<nf;i++)
4618  free(fv[i]);
4619  free(fv);
4620  free(nvf);
4621 }
4622 
4624 {
4625  double nn;
4626  unsigned int i;
4627 
4628  nn=0.0;
4629  for(i=0;i<a->currentChart;i++)
4630  nn+=(double)ChartNumNeighbours(a->charts[i]);
4631 
4632  return(nn/(double)a->currentChart);
4633 }
4634 
4635 void PrintAtlasDefines(FILE *f)
4636 {
4637  PrintChartDefines(f);
4638  fprintf(f,"\n %% Atlas defines\n");
4639  fprintf(f," ATLAS_VERBOSE %u\n",ATLAS_VERBOSE);
4640  fprintf(f," PLOT_ATLAS_IN_COLORS %u\n",PLOT_ATLAS_IN_COLORS);
4641  fprintf(f," PROJECT_WITH_PLANE %u\n",PROJECT_WITH_PLANE);
4642  fprintf(f," USE_ATLAS_TREE %u\n",USE_ATLAS_TREE);
4643  fprintf(f," SAMPLING_RADIUS_REDUCTION_FACTOR %.2f\n",SAMPLING_RADIUS_REDUCTION_FACTOR);
4644  fprintf(f," SIMPLE_BORDER %u\n",SIMPLE_BORDER);
4645  fprintf(f," W_BTREE %u\n",W_BTREE); // This is defined in btree
4646 }
4647 
4649 {
4650  unsigned int i;
4651 
4652  DeleteJacobian(&(a->J));
4653 
4654  if (a->H!=NULL)
4655  {
4656  DeleteHessian(a->H);
4657  free(a->H);
4658  }
4659 
4660  for(i=0;i<a->currentChart;i++)
4661  {
4662  DeleteChart(a->charts[i]);
4663  free(a->charts[i]);
4664  }
4665 
4666  free(a->charts);
4667 
4668  if (a->ambient!=NULL)
4669  {
4670  DeleteBox(a->ambient);
4671  free(a->ambient);
4672  }
4673 
4674  if (a->tp!=NULL)
4675  free(a->tp);
4676 
4677  DeleteBifurcations(a);
4678 
4679  #if (USE_ATLAS_TREE)
4680  if (a->currentChart>0)
4681  DeleteBTree(&(a->tree));
4682  #endif
4683 }