void LKH::LKHAlg::GenerateCandidates(int MaxCandidates, GainType MaxAlpha, int Symmetric) { Node *From, *To; Candidate *NFrom, *NN; int a, d, Count; if (TraceLevel >= 2) printff("Generating candidates ... "); if (MaxAlpha < 0 || MaxAlpha > INT_MAX) MaxAlpha = INT_MAX; /* Initialize CandidateSet for each node */ FreeCandidateSets(); From = FirstNode; do From->Mark = 0; while ((From = From->Suc) != FirstNode); if (MaxCandidates > 0) { do { assert(From->CandidateSet = (Candidate *) malloc((MaxCandidates + 1) * sizeof(Candidate))); From->CandidateSet[0].To = 0; } while ((From = From->Suc) != FirstNode); } else { AddTourCandidates(); do { if (!From->CandidateSet) eprintf("MAX_CANDIDATES = 0: No candidates"); } while ((From = From->Suc) != FirstNode); return; } /* Loop for each node, From */ do { NFrom = From->CandidateSet; if (From != FirstNode) { From->Beta = INT_MIN; for (To = From; To->Dad != 0; To = To->Dad) { To->Dad->Beta = !FixedOrCommon(To, To->Dad) ? Max(To->Beta, To->Cost) : To->Beta; To->Dad->Mark = From; } } Count = 0; /* Loop for each node, To */ To = FirstNode; do { if (To == From) continue; d = c && !FixedOrCommon(From, To) ? (this->*c)(From, To) : (this->*D)(From, To); if (From == FirstNode) a = To == From->Dad ? 0 : d - From->NextCost; else if (To == FirstNode) a = From == To->Dad ? 0 : d - To->NextCost; else { if (To->Mark != From) To->Beta = !FixedOrCommon(To, To->Dad) ? Max(To->Dad->Beta, To->Cost) : To->Dad->Beta; a = d - To->Beta; } if (FixedOrCommon(From, To)) a = INT_MIN; else { if (From->FixedTo2 || To->FixedTo2 || Forbidden(From, To)) continue; if (InInputTour(From, To)) { a = 0; if (c) d = (this->*D)(From, To); } else if (c) { if (a > MaxAlpha || (Count == MaxCandidates && (a > (NFrom - 1)->Alpha || (a == (NFrom - 1)->Alpha && d >= (NFrom - 1)->Cost)))) continue; if (To == From->Dad) { d = From->Cost; a = 0; } else if (From == To->Dad) { d = To->Cost; a = 0; } else { a -= d; a += (d = (this->*D)(From, To)); } } } if (a <= MaxAlpha && IsPossibleCandidate(From, To)) { /* Insert new candidate edge in From->CandidateSet */ NN = NFrom; while (--NN >= From->CandidateSet) { if (a > NN->Alpha || (a == NN->Alpha && d >= NN->Cost)) break; *(NN + 1) = *NN; } NN++; NN->To = To; NN->Cost = d; NN->Alpha = a; if (Count < MaxCandidates) { Count++; NFrom++; } NFrom->To = 0; } } while ((To = To->Suc) != FirstNode); } while ((From = From->Suc) != FirstNode); AddTourCandidates(); if (Symmetric) SymmetrizeCandidateSet(); if (TraceLevel >= 2) printff("done\n"); }
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 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 CreateDelaunayCandidateSet() { Node *From, *To; point *u, *v; edge *e_start, *e; int d, i, Count; if (TraceLevel >= 2) printff("Creating Delaunay candidate set ... "); if (Level == 0 && MaxCandidates == 0) { AddTourCandidates(); From = FirstNode; do { if (!From->CandidateSet) eprintf("MAX_CANDIDATES = 0: No candidates"); } while ((From = From->Suc) != FirstNode); if (TraceLevel >= 2) printff("done\n"); return; } /* Find the Delaunay edges */ delaunay(Dimension); /* Add the Delaunay edges to the candidate set */ for (i = 0; i < Dimension; i++) { u = &p_array[i]; From = &NodeSet[u->id]; e_start = e = u->entry_pt; Count = 0; do { v = Other_point(e, u); if (u < v) { To = &NodeSet[v->id]; d = D(From, To); AddCandidate(From, To, d, 1); AddCandidate(To, From, d, 1); } } while ((e = Next(e, u)) != e_start && ++Count < Dimension); } free_memory(); if (Level == 0 && (WeightType == GEO || WeightType == GEOM || WeightType == GEO_MEEUS || WeightType == GEOM_MEEUS)) { 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 { 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++; CreateDelaunayCandidateSet(); Level--; From = FirstNode; do From->Y = From->Zc; while ((From = From->Suc) != FirstNode); } } if (Level == 0) { AddTourCandidates(); /* Add quadrant neighbors if any node has less than two candidates. That is, if it should happen that delaunay_edges fails. */ From = FirstNode; do { if (From->CandidateSet == 0 || From->CandidateSet[0].To == 0 || From->CandidateSet[1].To == 0) { if (TraceLevel >= 2) printff("*** Not complete ***\n"); AddExtraCandidates(CoordType == THREED_COORDS ? 8 : 4, QUADRANT, 1); break; } } while ((From = From->Suc) != FirstNode); if (TraceLevel >= 2) printff("done\n"); } }