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;
}
Esempio n. 3
0
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;
}