void FreeStructures() { FreeCandidateSets(); FreeSegments(); if (NodeSet) { int i; for (i = 1; i <= Dimension; i++) { Node *N = &NodeSet[i]; Free(N->MergeSuc); N->C = 0; } Free(NodeSet); } Free(CostMatrix); Free(BestTour); Free(BetterTour); Free(SwapStack); Free(HTable); Free(Rand); Free(CacheSig); Free(CacheVal); Free(Name); Free(Type); Free(EdgeWeightType); Free(EdgeWeightFormat); Free(EdgeDataFormat); Free(NodeCoordType); Free(DisplayDataType); Free(Heap); Free(t); Free(T); Free(tSaved); Free(p); Free(q); Free(incl); Free(cycle); Free(G); FreePopulation(); }
int SolveSubproblem(int CurrentSubproblem, int Subproblems, GainType * GlobalBestCost) { Node *FirstNodeSaved = FirstNode, *N, *Next, *Last = 0; GainType OptimumSaved = Optimum, Cost, Improvement, GlobalCost; double LastTime, Time, ExcessSaved = Excess; int NewDimension = 0, OldDimension = 0, Number, i, InitialTourEdges = 0, AscentCandidatesSaved = AscentCandidates, InitialPeriodSaved = InitialPeriod, MaxTrialsSaved = MaxTrials; BestCost = PLUS_INFINITY; FirstNode = 0; N = FirstNodeSaved; do { if (N->Subproblem == CurrentSubproblem) { if (SubproblemsCompressed && (((N->SubproblemPred == N->SubBestPred || FixedOrCommon(N, N->SubproblemPred) || (N->SubBestPred && (N->FixedTo1Saved == N->SubBestPred || N->FixedTo2Saved == N->SubBestPred))) && (N->SubproblemSuc == N->SubBestSuc || FixedOrCommon(N, N->SubproblemSuc) || (N->SubBestSuc && (N->FixedTo1Saved == N->SubBestSuc || N->FixedTo2Saved == N->SubBestSuc)))) || ((N->SubproblemPred == N->SubBestSuc || FixedOrCommon(N, N->SubproblemPred) || (N->SubBestSuc && (N->FixedTo1Saved == N->SubBestSuc || N->FixedTo2Saved == N->SubBestSuc))) && (N->SubproblemSuc == N->SubBestPred || FixedOrCommon(N, N->SubproblemSuc) || (N->SubBestPred && (N->FixedTo1Saved == N->SubBestPred || N->FixedTo2Saved == N->SubBestPred)))))) N->Subproblem = -CurrentSubproblem; else { if (!FirstNode) FirstNode = N; NewDimension++; } N->Head = N->Tail = 0; if (N->SubBestSuc) OldDimension++; } N->SubBestPred = N->SubBestSuc = 0; N->FixedTo1Saved = N->FixedTo1; N->FixedTo2Saved = N->FixedTo2; } while ((N = N->SubproblemSuc) != FirstNodeSaved); if ((Number = CurrentSubproblem % Subproblems) == 0) Number = Subproblems; if (NewDimension <= 3 || NewDimension == OldDimension) { if (TraceLevel >= 1 && NewDimension <= 3) printff ("\nSubproblem %d of %d: Dimension = %d (too small)\n", Number, Subproblems, NewDimension); FirstNode = FirstNodeSaved; return 0; } if (AscentCandidates > NewDimension - 1) AscentCandidates = NewDimension - 1; if (InitialPeriod < 0) { InitialPeriod = NewDimension / 2; if (InitialPeriod < 100) InitialPeriod = 100; } if (Excess < 0) Excess = 1.0 / NewDimension; if (MaxTrials == -1) MaxTrials = NewDimension; N = FirstNode; do { Next = N->SubproblemSuc; if (N->Subproblem == CurrentSubproblem) { N->Pred = N->Suc = N; if (N != FirstNode) Follow(N, Last); Last = N; } else if (Next->Subproblem == CurrentSubproblem && !Fixed(Last, Next)) { if (!Last->FixedTo1 || Last->FixedTo1->Subproblem != CurrentSubproblem) Last->FixedTo1 = Next; else Last->FixedTo2 = Next; if (!Next->FixedTo1 || Next->FixedTo1->Subproblem != CurrentSubproblem) Next->FixedTo1 = Last; else Next->FixedTo2 = Last; if (C == C_EXPLICIT) { if (Last->Id > Next->Id) Last->C[Next->Id] = 0; else Next->C[Last->Id] = 0; } } } while ((N = Next) != FirstNode); Dimension = NewDimension; AllocateSegments(); InitializeStatistics(); if (CacheSig) for (i = 0; i <= CacheMask; i++) CacheSig[i] = 0; OptimumSaved = Optimum; Optimum = 0; N = FirstNode; do { if (N->SubproblemSuc == N->InitialSuc || N->SubproblemPred == N->InitialSuc) InitialTourEdges++; if (!Fixed(N, N->Suc)) Optimum += Distance(N, N->Suc); if (N->FixedTo1 && N->Subproblem != N->FixedTo1->Subproblem) eprintf("Illegal fixed edge (%d,%d)", N->Id, N->FixedTo1->Id); if (N->FixedTo2 && N->Subproblem != N->FixedTo2->Subproblem) eprintf("Illegal fixed edge (%d,%d)", N->Id, N->FixedTo2->Id); } while ((N = N->Suc) != FirstNode); if (TraceLevel >= 1) printff ("\nSubproblem %d of %d: Dimension = %d, Upper bound = " GainFormat "\n", Number, Subproblems, Dimension, Optimum); FreeCandidateSets(); CreateCandidateSet(); for (Run = 1; Run <= Runs; Run++) { LastTime = GetTime(); Cost = Norm != 0 ? FindTour() : Optimum; /* Merge with subproblem tour */ Last = 0; N = FirstNode; do { if (N->Subproblem == CurrentSubproblem) { if (Last) Last->Next = N; Last = N; } } while ((N = N->SubproblemSuc) != FirstNode); Last->Next = FirstNode; Cost = MergeWithTour(); if (MaxPopulationSize > 1) { /* Genetic algorithm */ for (i = 0; i < PopulationSize; i++) Cost = MergeTourWithIndividual(i); if (!HasFitness(Cost)) { if (PopulationSize < MaxPopulationSize) { AddToPopulation(Cost); if (TraceLevel >= 1) PrintPopulation(); } else if (Cost < Fitness[PopulationSize - 1]) { ReplaceIndividualWithTour(PopulationSize - 1, Cost); if (TraceLevel >= 1) PrintPopulation(); } } } if (Cost < BestCost) { N = FirstNode; do { N->SubBestPred = N->Pred; N->SubBestSuc = N->Suc; } while ((N = N->Suc) != FirstNode); BestCost = Cost; } if (Cost < Optimum || (Cost != Optimum && OutputTourFileName)) { Improvement = Optimum - Cost; if (Improvement > 0) { BestCost = GlobalCost = *GlobalBestCost -= Improvement; Optimum = Cost; } else GlobalCost = *GlobalBestCost - Improvement; N = FirstNode; do N->Mark = 0; while ((N = N->SubproblemSuc) != FirstNode); do { N->Mark = N; if (!N->SubproblemSuc->Mark && (N->Subproblem != CurrentSubproblem || N->SubproblemSuc->Subproblem != CurrentSubproblem)) N->BestSuc = N->SubproblemSuc; else if (!N->SubproblemPred->Mark && (N->Subproblem != CurrentSubproblem || N->SubproblemPred->Subproblem != CurrentSubproblem)) N->BestSuc = N->SubproblemPred; else if (!N->Suc->Mark) N->BestSuc = N->Suc; else if (!N->Pred->Mark) N->BestSuc = N->Pred; else N->BestSuc = FirstNode; } while ((N = N->BestSuc) != FirstNode); Dimension = DimensionSaved; i = 0; do { if (ProblemType != ATSP) BetterTour[++i] = N->Id; else if (N->Id <= Dimension / 2) { i++; if (N->BestSuc->Id != N->Id + Dimension / 2) BetterTour[i] = N->Id; else BetterTour[Dimension / 2 - i + 1] = N->Id; } } while ((N = N->BestSuc) != FirstNode); BetterTour[0] = BetterTour[ProblemType != ATSP ? Dimension : Dimension / 2]; WriteTour(OutputTourFileName, BetterTour, GlobalCost); if (Improvement > 0) { do if (N->Subproblem != CurrentSubproblem) break; while ((N = N->SubproblemPred) != FirstNode); if (N->SubproblemSuc == N->BestSuc) { N = FirstNode; do { N->BestSuc->SubproblemPred = N; N = N->SubproblemSuc = N->BestSuc; } while (N != FirstNode); } else { N = FirstNode; do (N->SubproblemPred = N->BestSuc)->SubproblemSuc = N; while ((N = N->BestSuc) != FirstNode); } RecordBestTour(); WriteTour(TourFileName, BestTour, GlobalCost); } Dimension = NewDimension; if (TraceLevel >= 1) { printff("*** %d: Cost = " GainFormat, Number, GlobalCost); if (OptimumSaved != MINUS_INFINITY && OptimumSaved != 0) printff(", Gap = %04f%%", 100.0 * (GlobalCost - OptimumSaved) / OptimumSaved); printff(", Time = %0.2f sec. %s\n", fabs(GetTime() - LastTime), GlobalCost < OptimumSaved ? "<" : GlobalCost == OptimumSaved ? "=" : ""); } } Time = fabs(GetTime() - LastTime); UpdateStatistics(Cost, Time); if (TraceLevel >= 1 && Cost != PLUS_INFINITY) printff("Run %d: Cost = " GainFormat ", Time = %0.2f sec.\n\n", Run, Cost, Time); if (PopulationSize >= 2 && (PopulationSize == MaxPopulationSize || Run >= 2 * MaxPopulationSize) && Run < Runs) { Node *N; int Parent1, Parent2; Parent1 = LinearSelection(PopulationSize, 1.25); do Parent2 = LinearSelection(PopulationSize, 1.25); while (Parent1 == Parent2); ApplyCrossover(Parent1, Parent2); N = FirstNode; do { int d = C(N, N->Suc); AddCandidate(N, N->Suc, d, INT_MAX); AddCandidate(N->Suc, N, d, INT_MAX); N = N->InitialSuc = N->Suc; } while (N != FirstNode); } SRandom(++Seed); if (Norm == 0) break; } if (TraceLevel >= 1) PrintStatistics(); if (C == C_EXPLICIT) { N = FirstNode; do { for (i = 1; i < N->Id; i++) { N->C[i] -= N->Pi + NodeSet[i].Pi; N->C[i] /= Precision; } if (N->FixedTo1 && N->FixedTo1 != N->FixedTo1Saved) { if (N->Id > N->FixedTo1->Id) N->C[N->FixedTo1->Id] = Distance(N, N->FixedTo1); else N->FixedTo1->C[N->Id] = Distance(N, N->FixedTo1); } if (N->FixedTo2 && N->FixedTo2 != N->FixedTo2Saved) { if (N->Id > N->FixedTo2->Id) N->C[N->FixedTo2->Id] = Distance(N, N->FixedTo2); else N->FixedTo2->C[N->Id] = Distance(N, N->FixedTo2); } } while ((N = N->Suc) != FirstNode); } FreeSegments(); FreeCandidateSets(); FreePopulation(); if (InitialTourEdges == Dimension) { do N->InitialSuc = N->SubproblemSuc; while ((N = N->SubproblemSuc) != FirstNode); } else { do N->InitialSuc = 0; while ((N = N->SubproblemSuc) != FirstNode); } Dimension = ProblemType != ATSP ? DimensionSaved : 2 * DimensionSaved; N = FirstNode = FirstNodeSaved; do { N->Suc = N->BestSuc = N->SubproblemSuc; N->Suc->Pred = N; Next = N->FixedTo1; N->FixedTo1 = N->FixedTo1Saved; N->FixedTo1Saved = Next; Next = N->FixedTo2; N->FixedTo2 = N->FixedTo2Saved; N->FixedTo2Saved = Next; } while ((N = N->Suc) != FirstNode); Optimum = OptimumSaved; Excess = ExcessSaved; AscentCandidates = AscentCandidatesSaved; InitialPeriod = InitialPeriodSaved; MaxTrials = MaxTrialsSaved; return 1; }
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"); }
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; }