GainType Ascent() { Node *t; GainType BestW, W, W0, Alpha, MaxAlpha = INT_MAX; int T, Period, P, InitialPhase, BestNorm; Start: /* Initialize Pi and BestPi */ t = FirstNode; do t->Pi = t->BestPi = 0; while ((t = t->Suc) != FirstNode); if (CandidateSetType == DELAUNAY) CreateDelaunayCandidateSet(); else AddTourCandidates(); /* Compute the cost of a minimum 1-tree */ W = Minimum1TreeCost(CandidateSetType == DELAUNAY || MaxCandidates == 0); /* Return this cost if either (1) subgradient optimization is not wanted, or (2) the norm of the tree (its deviation from a tour) is zero (in that case the true optimum has been found). */ if (!Subgradient || !Norm) return W; if (Optimum != MINUS_INFINITY && (Alpha = Optimum * Precision - W) > 0) MaxAlpha = Alpha; if (MaxCandidates > 0) { /* Generate symmetric candididate sets for all nodes */ if (CandidateSetType != DELAUNAY) GenerateCandidates(AscentCandidates, MaxAlpha, 1); else { OrderCandidateSet(AscentCandidates, MaxAlpha, 1); W = Minimum1TreeCost(1); if (!Norm || W / Precision == Optimum) return W; } } if (ExtraCandidates > 0) AddExtraCandidates(ExtraCandidates, ExtraCandidateSetType, ExtraCandidateSetSymmetric); if (TraceLevel >= 2) { CandidateReport(); printff("Subgradient optimization ...\n"); } /* Set LastV of every node to V (the node's degree in the 1-tree) */ t = FirstNode; do t->LastV = t->V; while ((t = t->Suc) != FirstNode); BestW = W0 = W; BestNorm = Norm; InitialPhase = 1; /* Perform subradient optimization with decreasing period length and decreasing step size */ for (Period = InitialPeriod, T = InitialStepSize * Precision; Period > 0 && T > 0 && Norm != 0; Period /= 2, T /= 2) { /* Period and step size are halved at each iteration */ if (TraceLevel >= 2) printff (" T = %d, Period = %d, BestW = %0.1f, Norm = %d\n", T, Period, (double) BestW / Precision, Norm); for (P = 1; T && P <= Period && Norm != 0; P++) { /* Adjust the Pi-values */ t = FirstNode; do { if (t->V != 0) { t->Pi += T * (7 * t->V + 3 * t->LastV) / 10; if (t->Pi > INT_MAX / 4) t->Pi = INT_MAX / 4; else if (t->Pi < -INT_MAX / 4) t->Pi = -INT_MAX / 4; } t->LastV = t->V; } while ((t = t->Suc) != FirstNode); /* Compute a minimum 1-tree in the sparse graph */ W = Minimum1TreeCost(1); /* Test if an improvement has been found */ if (W > BestW || (W == BestW && Norm < BestNorm)) { /* If the lower bound becomes greater than twice its initial value it is taken as a sign that the graph might be too sparse */ if (W - W0 > (W0 >= 0 ? W0 : -W0) && AscentCandidates > 0 && AscentCandidates < Dimension) { W = Minimum1TreeCost(CandidateSetType == DELAUNAY || MaxCandidates == 0); if (W < W0) { /* Double the number of candidate edges and start all over again */ if (TraceLevel >= 2) printff("Warning: AscentCandidates doubled\n"); if ((AscentCandidates *= 2) > Dimension) AscentCandidates = Dimension; goto Start; } W0 = W; } BestW = W; BestNorm = Norm; /* Update the BestPi-values */ t = FirstNode; do t->BestPi = t->Pi; while ((t = t->Suc) != FirstNode); if (TraceLevel >= 2) printff ("* T = %d, Period = %d, P = %d, BestW = %0.1f, Norm = %d\n", T, Period, P, (double) BestW / Precision, Norm); /* If in the initial phase, the step size is doubled */ if (InitialPhase && T * sqrt((double) Norm) > 0) T *= 2; /* If the improvement was found at the last iteration of the current period, then double the period */ if (CandidateSetType != DELAUNAY && P == Period && (Period *= 2) > InitialPeriod) Period = InitialPeriod; } else { if (TraceLevel >= 3) printff (" T = %d, Period = %d, P = %d, W = %0.1f, Norm = %d\n", T, Period, P, (double) W / Precision, Norm); if (InitialPhase && P > Period / 2) { /* Conclude the initial phase */ InitialPhase = 0; P = 0; T = 3 * T / 4; } } } } t = FirstNode; do { t->Pi = t->BestPi; t->BestPi = 0; } while ((t = t->Suc) != FirstNode); /* Compute a minimum 1-tree */ W = BestW = Minimum1TreeCost(CandidateSetType == DELAUNAY || MaxCandidates == 0); if (MaxCandidates > 0) { FreeCandidateSets(); if (CandidateSetType == DELAUNAY) CreateDelaunayCandidateSet(); } else { Candidate *Nt; t = FirstNode; do { for (Nt = t->CandidateSet; Nt && Nt->To; Nt++) Nt->Cost += t->Pi + Nt->To->Pi; } while ((t = t->Suc) != FirstNode); } if (TraceLevel >= 2) printff("Ascent: BestW = %0.1f, Norm = %d\n", (double) BestW / Precision, Norm); return W; }
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; }