int ReadCandidates(int MaxCandidates) { FILE *CandidateFile = 0; Node *From, *To; int Dimension, i, j, f, Id, Alpha, Count; if (CandidateFiles == 0 || (CandidateFiles == 1 && !(CandidateFile = fopen(CandidateFileName[0], "r")))) return 0; Dimension = ProblemType != ATSP ? DimensionSaved : 2 * DimensionSaved; for (f = 0; f < CandidateFiles; f++) { if (CandidateFiles >= 2 && !(CandidateFile = fopen(CandidateFileName[f], "r"))) eprintf("Cannot open CANDIDATE_FILE: \"%s\"", CandidateFileName[f]); if (TraceLevel >= 1) printff("Reading CANDIDATE_FILE: \"%s\" ... ", CandidateFileName[f]); fscanint(CandidateFile, &i); if (i != Dimension) eprintf("CANDIDATE_FILE \"%s\" does not match problem", CandidateFileName[f]); for (i = 1; i <= Dimension; i++) { fscanint(CandidateFile, &Id); assert(Id >= 1 && Id <= Dimension); From = &NodeSet[Id]; fscanint(CandidateFile, &Id); assert(Id >= 0 && Id <= Dimension); if (Id > 0) From->Dad = &NodeSet[Id]; assert(From != From->Dad); fscanint(CandidateFile, &Count); assert(Count >= 0 && Count < Dimension); if (!From->CandidateSet) assert(From->CandidateSet = (Candidate *) calloc(Count + 1, sizeof(Candidate))); for (j = 0; j < Count; j++) { fscanint(CandidateFile, &Id); assert(Id >= 1 && Id <= Dimension); To = &NodeSet[Id]; fscanint(CandidateFile, &Alpha); AddCandidate(From, To, D(From, To), Alpha); } } fclose(CandidateFile); if (TraceLevel >= 1) printff("done\n"); } ResetCandidateSet(); if (MaxCandidates > 0) TrimCandidateSet(MaxCandidates); return 1; }
void SymmetrizeCandidateSet() { Node *From, *To; Candidate *NFrom; From = FirstNode; do { for (NFrom = From->CandidateSet; NFrom && (To = NFrom->To); NFrom++) AddCandidate(To, From, NFrom->Cost, NFrom->Alpha); } while ((From = From->Suc) != FirstNode); ResetCandidateSet(); }
void CreateQuadrantCandidateSet(int K) { Node *From, *To; Candidate *NFrom; int L, Q, CandPerQ, Added, Count, i; if (K <= 0) return; if (TraceLevel >= 2) printff("Creating quadrant candidate set ... "); KDTree = BuildKDTree(1); assert(XMin = (double *) malloc((1 + DimensionSaved) * sizeof(double))); assert(XMax = (double *) malloc((1 + DimensionSaved) * sizeof(double))); assert(YMin = (double *) malloc((1 + DimensionSaved) * sizeof(double))); assert(YMax = (double *) malloc((1 + DimensionSaved) * sizeof(double))); if (CoordType == THREED_COORDS) { assert(ZMin = (double *) malloc((1 + DimensionSaved) * sizeof(double))); assert(ZMax = (double *) malloc((1 + DimensionSaved) * sizeof(double))); } ComputeBounds(0, Dimension - 1); Contains = CoordType == THREED_COORDS ? Contains3D : Contains2D; BoxOverlaps = CoordType == THREED_COORDS ? BoxOverlaps3D : BoxOverlaps2D; L = CoordType == THREED_COORDS ? 8 : 4; CandPerQ = K / L; assert(CandidateSet = (Candidate *) malloc((K + 1) * sizeof(Candidate))); From = FirstNode; do { Count = 0; for (NFrom = From->CandidateSet; NFrom && NFrom->To; NFrom++) if (FixedOrCommon(From, NFrom->To) && ++Count == 2) break; if (Count == 2) continue; Added = 0; for (Q = 1; Q <= L; Q++) { NearestQuadrantNeighbors(From, Q, CandPerQ); for (i = 0; i < Candidates; i++) { To = CandidateSet[i].To; if (AddCandidate(From, To, D(From, To), 1)) Added++; } } if (K > Added) { NearestQuadrantNeighbors(From, 0, K - Added); for (i = 0; i < Candidates; i++) { To = CandidateSet[i].To; AddCandidate(From, To, D(From, To), 2); } } } while ((From = From->Suc) != FirstNode); free(CandidateSet); free(KDTree); free(XMin); free(XMax); free(YMin); free(YMax); if (CoordType == THREED_COORDS) { free(ZMin); free(ZMax); } if (Level == 0 && (WeightType == GEO || WeightType == GEOM || WeightType == GEO_MEEUS || WeightType == GEOM_MEEUS)) { Candidate **SavedCandidateSet; assert(SavedCandidateSet = (Candidate **) malloc((1 + DimensionSaved) * sizeof(Candidate *))); if (TraceLevel >= 2) printff("done\n"); From = FirstNode; while ((From = From->Suc) != FirstNode) if ((From->Y > 0) != (FirstNode->Y > 0)) break; if (From != FirstNode) { /* Transform longitude (180 and -180 map to 0) */ From = FirstNode; do { SavedCandidateSet[From->Id] = From->CandidateSet; From->CandidateSet = 0; From->Zc = From->Y; if (WeightType == GEO || WeightType == GEO_MEEUS) From->Y = (int) From->Y + 5.0 * (From->Y - (int) From->Y) / 3.0; From->Y += From->Y > 0 ? -180 : 180; if (WeightType == GEO || WeightType == GEO_MEEUS) From->Y = (int) From->Y + 3.0 * (From->Y - (int) From->Y) / 5.0; } while ((From = From->Suc) != FirstNode); Level++; CreateQuadrantCandidateSet(K); Level--; From = FirstNode; do From->Y = From->Zc; while ((From = From->Suc) != FirstNode); do { Candidate *QCandidateSet = From->CandidateSet; From->CandidateSet = SavedCandidateSet[From->Id]; for (NFrom = QCandidateSet; (To = NFrom->To); NFrom++) AddCandidate(From, To, NFrom->Cost, NFrom->Alpha); free(QCandidateSet); } while ((From = From->Suc) != FirstNode); free(SavedCandidateSet); } } if (Level == 0) { ResetCandidateSet(); AddTourCandidates(); if (CandidateSetSymmetric) SymmetrizeCandidateSet(); if (TraceLevel >= 2) printff("done\n"); } }
void CreateNearestNeighborCandidateSet(int K) { Node *From, *To; int i; if (TraceLevel >= 2) printff("Creating nearest neighbor candidate set ... "); KDTree = BuildKDTree(1); assert(XMin = (double *) malloc((1 + DimensionSaved) * sizeof(double))); assert(XMax = (double *) malloc((1 + DimensionSaved) * sizeof(double))); assert(YMin = (double *) malloc((1 + DimensionSaved) * sizeof(double))); assert(YMax = (double *) malloc((1 + DimensionSaved) * sizeof(double))); if (CoordType == THREED_COORDS) { assert(ZMin = (double *) malloc((1 + DimensionSaved) * sizeof(double))); assert(ZMax = (double *) malloc((1 + DimensionSaved) * sizeof(double))); } ComputeBounds(0, Dimension - 1); Contains = CoordType == THREED_COORDS ? Contains3D : Contains2D; BoxOverlaps = CoordType == THREED_COORDS ? BoxOverlaps3D : BoxOverlaps2D; assert(CandidateSet = (Candidate *) malloc((K + 1) * sizeof(Candidate))); From = FirstNode; do { NearestQuadrantNeighbors(From, 0, K); for (i = 0; i < Candidates; i++) { To = CandidateSet[i].To; AddCandidate(From, To, D(From, To), 1); } } while ((From = From->Suc) != FirstNode); free(CandidateSet); free(KDTree); free(XMin); free(XMax); free(YMin); free(YMax); if (CoordType == THREED_COORDS) { free(ZMin); free(ZMax); } if (Level == 0 && (WeightType == GEOM || WeightType == GEOM_MEEUS)) { Candidate **SavedCandidateSet; assert(SavedCandidateSet = (Candidate **) malloc((1 + DimensionSaved) * sizeof(Candidate *))); if (TraceLevel >= 2) printff("done\n"); /* Transform longitude (180 and -180 map to 0) */ From = FirstNode; do { SavedCandidateSet[From->Id] = From->CandidateSet; From->CandidateSet = 0; From->Yc = From->Y; From->Y += From->Y > 0 ? -180 : 180; } while ((From = From->Suc) != FirstNode); Level++; CreateNearestNeighborCandidateSet(K); Level--; From = FirstNode; do From->Y = From->Yc; while ((From = From->Suc) != FirstNode); do { Candidate *QCandidateSet = From->CandidateSet; Candidate *NFrom; From->CandidateSet = SavedCandidateSet[From->Id]; for (NFrom = QCandidateSet; (To = NFrom->To); NFrom++) AddCandidate(From, To, NFrom->Cost, NFrom->Alpha); free(QCandidateSet); } while ((From = From->Suc) != FirstNode); free(SavedCandidateSet); } if (Level == 0) { ResetCandidateSet(); AddTourCandidates(); if (CandidateSetSymmetric) SymmetrizeCandidateSet(); if (TraceLevel >= 2) printff("done\n"); } }
void LKH::LKHAlg::CreateCandidateSet() { GainType Cost, MaxAlpha, A; Node *Na; int CandidatesRead = 0, i; double EntryTime = GetTime(); Norm = 9999; if (C == &LKH::LKHAlg::C_EXPLICIT) { Na = FirstNode; do { for (i = 1; i < Na->Id; i++) Na->C[i] *= Precision; } while ((Na = Na->Suc) != FirstNode); } if (Distance == &LKH::LKHAlg::Distance_1 || (MaxTrials == 0 && (FirstNode->InitialSuc || InitialTourAlgorithm == SIERPINSKI || InitialTourAlgorithm == MOORE))) { ReadCandidates(MaxCandidates); AddTourCandidates(); if (ProblemType == HCP || ProblemType == HPP) Ascent(); goto End_CreateCandidateSet; } if (TraceLevel >= 2) printff("Creating candidates ...\n"); if (MaxCandidates > 0 && (CandidateSetType == QUADRANT || CandidateSetType == NN)) { ReadPenalties(); if (!(CandidatesRead = ReadCandidates(MaxCandidates)) && MaxCandidates > 0) { if (CandidateSetType == QUADRANT) CreateQuadrantCandidateSet(MaxCandidates); else if (CandidateSetType == NN) CreateNearestNeighborCandidateSet(MaxCandidates); } else { AddTourCandidates(); if (CandidateSetSymmetric) SymmetrizeCandidateSet(); } goto End_CreateCandidateSet; } if (!ReadPenalties()) { /* No PiFile specified or available */ Na = FirstNode; do Na->Pi = 0; while ((Na = Na->Suc) != FirstNode); CandidatesRead = ReadCandidates(MaxCandidates); Cost = Ascent(); if (Subgradient && SubproblemSize == 0) { WritePenalties(); PiFile = 0; } } else if ((CandidatesRead = ReadCandidates(MaxCandidates)) || MaxCandidates == 0) { AddTourCandidates(); if (CandidateSetSymmetric) SymmetrizeCandidateSet(); goto End_CreateCandidateSet; } else { if (CandidateSetType != DELAUNAY && MaxCandidates > 0) { if (TraceLevel >= 2) printff("Computing lower bound ... "); Cost = Minimum1TreeCost(0); if (TraceLevel >= 2) printff("done\n"); } else { CreateDelaunayCandidateSet(); Na = FirstNode; do { Na->BestPi = Na->Pi; Na->Pi = 0; } while ((Na = Na->Suc) != FirstNode); if (TraceLevel >= 2) printff("Computing lower bound ... "); Cost = Minimum1TreeCost(1); if (TraceLevel >= 2) printff("done\n"); Na = FirstNode; do { Na->Pi = Na->BestPi; Cost -= 2 * Na->Pi; } while ((Na = Na->Suc) != FirstNode); } } LowerBound = (double) Cost / Precision; if (TraceLevel >= 1) { /* printff("Lower bound = %0.1f", LowerBound); if (Optimum != MINUS_INFINITY && Optimum != 0) printff(", Gap = %0.2f%%", 100.0 * (Optimum - LowerBound) / Optimum); if (!PiFile) printff(", Ascent time = %0.2f sec.", fabs(GetTime() - EntryTime)); printff("\n"); */ if (Optimum != MINUS_INFINITY && Optimum != 0) m_Gap=100.0 * (Optimum - LowerBound) / Optimum; if (!PiFile) m_AscentTime=fabs(GetTime() - EntryTime); } MaxAlpha = (GainType) fabs(Excess * Cost); if ((A = Optimum * Precision - Cost) > 0 && A < MaxAlpha) MaxAlpha = A; if (CandidateSetType == DELAUNAY || MaxCandidates == 0) OrderCandidateSet(MaxCandidates, MaxAlpha, CandidateSetSymmetric); else GenerateCandidates(MaxCandidates, MaxAlpha, CandidateSetSymmetric); End_CreateCandidateSet: if (ExtraCandidates > 0) { AddExtraCandidates(ExtraCandidates, ExtraCandidateSetType, ExtraCandidateSetSymmetric); AddTourCandidates(); } ResetCandidateSet(); Na = FirstNode; do { if (!Na->CandidateSet || !Na->CandidateSet[0].To) { if (MaxCandidates == 0) eprintf("MAX_CANDIDATES = 0: Node %d has no candidates", Na->Id); else eprintf("Node %d has no candidates", Na->Id); } } while ((Na = Na->Suc) != FirstNode); if (!CandidatesRead && SubproblemSize == 0) WriteCandidates(); if (C == &LKH::LKHAlg::C_EXPLICIT) { Na = FirstNode; do for (i = 1; i < Na->Id; i++) Na->C[i] += Na->Pi + NodeSet[i].Pi; while ((Na = Na->Suc) != FirstNode); } if (TraceLevel >= 1) { CandidateReport(); // printff("Preprocessing time = %0.2f sec.\n", // fabs(GetTime() - EntryTime)); } }
GainType LKH::LKHAlg::FindTour() { GainType Cost; Node *t; int i; double EntryTime = GetTime(); if(!OrdinalTourCost.get()) OrdinalTourCost.reset(new GainType(0)); t = FirstNode; do t->OldPred = t->OldSuc = t->NextBestSuc = t->BestSuc = 0; while ((t = t->Suc) != FirstNode); if (Run == 1 && Dimension == DimensionSaved) { *OrdinalTourCost = 0; for (i = 1; i < Dimension; i++) *OrdinalTourCost += (this->*C)(&NodeSet[i], &NodeSet[i + 1]) - NodeSet[i].Pi - NodeSet[i + 1].Pi; *OrdinalTourCost += (this->*C)(&NodeSet[Dimension], &NodeSet[1]) - NodeSet[Dimension].Pi - NodeSet[1].Pi; *OrdinalTourCost /= Precision; } BetterCost = PLUS_INFINITY; if (MaxTrials > 0) HashInitialize(HTable); else { Trial = 1; ChooseInitialTour(); } for (Trial = 1; Trial <= MaxTrials; Trial++) { if (GetTime() - EntryTime >= TimeLimit) { if (TraceLevel >= 1) printff("*** Time limit exceeded ***\n"); break; } /* Choose FirstNode at random */ if (Dimension == DimensionSaved) FirstNode = &NodeSet[1 + Random() % Dimension]; else for (i = Random() % Dimension; i > 0; i--) FirstNode = FirstNode->Suc; ChooseInitialTour(); Cost = LinKernighan(); if (FirstNode->BestSuc) { /* Merge tour with current best tour */ t = FirstNode; while ((t = t->Next = t->BestSuc) != FirstNode); Cost = MergeWithTour(); } if (Dimension == DimensionSaved && Cost >= *OrdinalTourCost && BetterCost > *OrdinalTourCost) { /* Merge tour with ordinal tour */ for (i = 1; i < Dimension; i++) NodeSet[i].Next = &NodeSet[i + 1]; NodeSet[Dimension].Next = &NodeSet[1]; Cost = MergeWithTour(); } if (Cost < BetterCost) { if (TraceLevel >= 1) { /* printff("* %d: Cost = " GainFormat, Trial, Cost); if (Optimum != MINUS_INFINITY && Optimum != 0) printff(", Gap = %0.4f%%", 100.0 * (Cost - Optimum) / Optimum); printff(", Time = %0.2f sec. %s\n", fabs(GetTime() - EntryTime), Cost < Optimum ? "<" : Cost == Optimum ? "=" : ""); */ } BetterCost = Cost; RecordBetterTour(); if (Dimension == DimensionSaved && BetterCost < BestCost) WriteTour(OutputTourFileName, BetterTour, BetterCost); if (StopAtOptimum && BetterCost == Optimum) break; AdjustCandidateSet(); HashInitialize(HTable); HashInsert(HTable, Hash, Cost); } else if (TraceLevel >= 2) printff(" %d: Cost = " GainFormat ", Time = %0.2f sec.\n", Trial, Cost, fabs(GetTime() - EntryTime)); /* Record backbones if wanted */ if (Trial <= BackboneTrials && BackboneTrials < MaxTrials) { SwapCandidateSets(this); AdjustCandidateSet(); if (Trial == BackboneTrials) { if (TraceLevel >= 1) { printff("# %d: Backbone candidates ->\n", Trial); CandidateReport(); } } else SwapCandidateSets(this); } } if (BackboneTrials > 0 && BackboneTrials < MaxTrials) { if (Trial > BackboneTrials || (Trial == BackboneTrials && (!StopAtOptimum || BetterCost != Optimum))) SwapCandidateSets(this); t = FirstNode; do { free(t->BackboneCandidateSet); t->BackboneCandidateSet = 0; } while ((t = t->Suc) != FirstNode); } t = FirstNode; if (Norm == 0) { do t = t->BestSuc = t->Suc; while (t != FirstNode); } do (t->Suc = t->BestSuc)->Pred = t; while ((t = t->BestSuc) != FirstNode); if (Trial > MaxTrials) Trial = MaxTrials; ResetCandidateSet(); return BetterCost; }