Пример #1
0
 /// <summary>
 /// Returns whether spot can be removed from break
 /// </summary>
 /// <param name="spot"></param>
 /// <returns></returns>
 private bool CanMoveSpotFromBreak(Spot spot)
 {
     // Unbooked spots can always be moved
     // Booked spots can only be moved if preemptable
     return(BreakUtilities.IsBreakRefNotSetOrUnused(_spotInfos[spot.Uid].ExternalBreakRefAtRunStart) ||
            (!BreakUtilities.IsBreakRefNotSetOrUnused(_spotInfos[spot.Uid].ExternalBreakRefAtRunStart) && spot.Preemptable));
 }
        private static void ValidateMultipartSpots(
            IReadOnlyList <SmoothBreak> progSmoothBreaks,
            SpotPositionRules breakPositionRules,
            SpotPositionRules requestedPositionInBreakRules,
            bool canSplitMultipartSpotsOverBreaks,
            CanAddSpotService canAddSpotService,
            SmoothFailureMessagesForSpotsCollection result,
            IReadOnlyCollection <Spot> spotsAlreadyInTheBreak,
            IReadOnlyList <Spot> multipartSpots)
        {
            if (multipartSpots.Count == 0)
            {
                return;
            }

            foreach (var spot in multipartSpots)
            {
                bool canAddSpotAtBreakPosition = canAddSpotService
                                                 .CanAddSpotWithBreakRequestForMultipartSpotWithDefaultPosition(
                    spot.BreakRequest,
                    progSmoothBreaks,
                    breakPositionRules);

                if (!canAddSpotAtBreakPosition)
                {
                    result.Add(spot.Uid, SmoothFailureMessages.T1_BreakPosition);
                }

                // Determine if we can add at requested position in break
                // TODO: Check that multipart Spots are all linked
                if (!canAddSpotService.CanAddMultipartSpotAtRequestedPosition(
                        spot.MultipartSpot,
                        spot.MultipartSpotPosition,
                        requestedPositionInBreakRules))
                {
                    result.Add(spot.Uid, SmoothFailureMessages.T1_RequestedPositionInBreak);
                }
            }

            // For the multipart spot type then check if this is the break
            // that it must be added to
            if (canSplitMultipartSpotsOverBreaks)
            {
                return;
            }

            // Multipart spots can't be split over breaks, ensure that
            // break will contain all linked multipart spots
            if (multipartSpots[0].MultipartSpot == MultipartSpotTypes.TopTail &&
                multipartSpots.Count < 2)
            {
                // We're not placing both spots, ensure that this break
                // has linked spot. Get all linked spots that have been
                // placed in this break.
                var linkedSpotsPlacedInBreak = BreakUtilities.GetLinkedMultipartSpots(
                    multipartSpots[0],
                    spotsAlreadyInTheBreak,
                    includeInputSpotInOutput: false
                    );

                if (linkedSpotsPlacedInBreak.Count == 0)
                {
                    // Break doesn't contain linked spots, can't add to
                    // this break
                    foreach (var spot in multipartSpots)
                    {
                        result.Add(
                            spot.Uid,
                            SmoothFailureMessages.T1_CantAddTopAndTailToSameBreak);
                    }
                }
            }
        }
Пример #3
0
        /// <summary>
        /// Returns best break to add spot(s) to.
        /// </summary>
        public BestBreakResult GetBestBreak(
            SmoothPass smoothPass,
            SmoothPassDefaultIteration smoothPassIteration,
            IReadOnlyCollection <BestBreakFactorGroup> bestBreakFactorGroups,
            IReadOnlyCollection <SmoothBreak> validSmoothBreaks,
            IReadOnlyCollection <Spot> spotsToPlace,
            IReadOnlyDictionary <Guid, SpotInfo> spotInfos,
            IReadOnlyDictionary <string, Clash> clashesByExternalRef,
            IReadOnlyDictionary <string, Product> productsByExternalRef,
            IReadOnlyCollection <SmoothBreak> progSmoothBreaks,
            out BestBreakFactorGroup usedBestBreakFactorGroup)
        {
            var bestBreakResult = new BestBreakResult();

            usedBestBreakFactorGroup = null;

            string breakDetailsListString = BreakUtilities.GetListOfBreakExternalReferences(
                "; ",
                validSmoothBreaks.Select(sb => sb.TheBreak).ToList());

            // Get spot details list as string
            string spotDetailsListString = SpotUtilities.GetSpotDetailsListString(spotsToPlace);

            // Check each group in priority order
            foreach (var bestBreakFactorGroup in bestBreakFactorGroups.OrderBy(g => g.Sequence))
            {
                _smoothDiagnostics.LogBestBreakFactorMessage(
                    smoothPass,
                    smoothPassIteration,
                    bestBreakFactorGroup,
                    null,
                    spotsToPlace,
                    null,
                    $"Checking best break factor group (Breaks={breakDetailsListString}; Spots={spotDetailsListString})"
                    );

                // Set all breaks to check
                var smoothBreaksRemaining = new List <SmoothBreak>();
                smoothBreaksRemaining.AddRange(validSmoothBreaks);

                // Generate unique random score for each break so that we can
                // pick a random break if necessary.
                IReadOnlyCollection <double> randomScoreByBreak = GetRandomScoreByBreak(
                    progSmoothBreaks,
                    uniqueScore: true);

                // Calculate scores for each break, determine best score
                var     scoreByBreak   = new Dictionary <SmoothBreak, decimal>();
                decimal bestBreakScore = -1;

                foreach (var smoothBreak in smoothBreaksRemaining)
                {
                    var(breakScore, scoreDebug) = _bestBreakFactorForGroupService
                                                  .GetBestBreakFactorScoreForGroup(
                        smoothBreak,
                        spotsToPlace,
                        spotInfos,
                        clashesByExternalRef,
                        productsByExternalRef,
                        progSmoothBreaks,
                        randomScoreByBreak,
                        bestBreakFactorGroup,
                        _smoothResources
                        );

                    LogBestBreakFactorScore(
                        smoothPass,
                        smoothPassIteration,
                        smoothBreak,
                        spotsToPlace,
                        breakScore,
                        bestBreakFactorGroup,
                        "Main",
                        scoreDebug
                        );

                    scoreByBreak.Add(smoothBreak, breakScore);

                    if (breakScore > bestBreakScore || bestBreakScore == -1)
                    {
                        bestBreakScore = breakScore;
                    }
                }

                if (bestBreakScore > 0)   // At least one break has a non-zero score
                {
                    // Remove all breaks with score less than the best score
                    var smoothBreaksToRemove = new List <SmoothBreak>();
                    foreach (var smoothBreak in smoothBreaksRemaining)
                    {
                        if (scoreByBreak[smoothBreak] < bestBreakScore)
                        {
                            smoothBreaksToRemove.Add(smoothBreak);
                        }
                    }

                    while (smoothBreaksToRemove.Count > 0)
                    {
                        _ = smoothBreaksRemaining.Remove(smoothBreaksToRemove[0]);
                        smoothBreaksToRemove.RemoveAt(0);
                    }

                    // Single break with best score, return it
                    if (smoothBreaksRemaining.Count == 1)
                    {
                        _smoothDiagnostics.LogBestBreakFactorMessage(
                            smoothPass,
                            smoothPassIteration,
                            bestBreakFactorGroup,
                            smoothBreaksRemaining[0].TheBreak,
                            spotsToPlace,
                            bestBreakScore,
                            $"Using single break which has best score (Spots={spotDetailsListString})"
                            );

                        usedBestBreakFactorGroup    = bestBreakFactorGroup;
                        bestBreakResult.Score       = bestBreakScore;
                        bestBreakResult.SmoothBreak = smoothBreaksRemaining[0];

                        return(bestBreakResult);
                    }

                    // Multiple breaks with best score, determine what we do
                    if (smoothBreaksRemaining.Count > 1)
                    {
                        switch (bestBreakFactorGroup.SameBreakGroupScoreAction)
                        {
                        // Check next group, our default and so no action
                        // required here
                        case SameBreakGroupScoreActions.CheckNextGroup:
                            _smoothDiagnostics.LogBestBreakFactorMessage(
                                smoothPass,
                                smoothPassIteration,
                                bestBreakFactorGroup,
                                null,
                                spotsToPlace,
                                null,
                                "CheckNextGroup: Need to check next group"
                                );
                            break;

                        // Check single factor to identify single break
                        case SameBreakGroupScoreActions.UseSingleBreakFactorIfBestScoreIsNonZero:
                            // Calculate score for each remaining break
                            _smoothDiagnostics.LogBestBreakFactorMessage(
                                smoothPass,
                                smoothPassIteration,
                                bestBreakFactorGroup,
                                null,
                                spotsToPlace,
                                null,
                                $"UseSingleBreakFactorIfBestScoreIsNonZero: Finding break for single break factor score for group (BreaksRemaining={smoothBreaksRemaining.Count.ToString()})"
                                );

                            var     scoreByBreak2   = new Dictionary <SmoothBreak, decimal>();
                            decimal bestBreakScore2 = -1;

                            foreach (var smoothBreak in smoothBreaksRemaining)
                            {
                                decimal breakScore2 = _bestBreakFactorService
                                                      .GetBestBreakFactorScoreForFactor(
                                    smoothBreak,
                                    spotsToPlace,
                                    spotInfos,
                                    clashesByExternalRef,
                                    productsByExternalRef,
                                    progSmoothBreaks,
                                    randomScoreByBreak,
                                    bestBreakFactorGroup.SameBreakGroupScoreFactor,
                                    _smoothResources
                                    );

                                var scoreDebug = $"UseSingleBreakFactorIfBestScoreIsNonZero: {bestBreakFactorGroup.SameBreakGroupScoreFactor.Factor.ToString()}={breakScore2.ToString("0.000000000000000000000000000000")}";

                                LogBestBreakFactorScore(
                                    smoothPass,
                                    smoothPassIteration,
                                    smoothBreak,
                                    spotsToPlace,
                                    breakScore2,
                                    bestBreakFactorGroup,
                                    "",
                                    scoreDebug
                                    );

                                scoreByBreak2.Add(smoothBreak, breakScore2);
                                if (breakScore2 > bestBreakScore2 || bestBreakScore2 == -1)
                                {
                                    bestBreakScore2 = breakScore2;
                                }
                            }

                            // Remove all but the break with the best score
                            var smoothBreaksToRemove2 = new List <SmoothBreak>();
                            foreach (var smoothBreak in smoothBreaksRemaining)
                            {
                                if (scoreByBreak2[smoothBreak] < bestBreakScore2)
                                {
                                    smoothBreaksToRemove2.Add(smoothBreak);
                                }
                            }

                            while (smoothBreaksToRemove2.Count > 0)
                            {
                                _ = smoothBreaksRemaining.Remove(smoothBreaksToRemove2[0]);
                                smoothBreaksToRemove2.RemoveAt(0);
                            }

                            // Return first break Sanity check, if no break
                            // then check next group
                            if (smoothBreaksRemaining.Count > 0)
                            {
                                _smoothDiagnostics.LogBestBreakFactorMessage(
                                    smoothPass,
                                    smoothPassIteration,
                                    bestBreakFactorGroup,
                                    smoothBreaksRemaining[0].TheBreak,
                                    spotsToPlace,
                                    null,
                                    string.Format("UseSingleBreakFactorIfBestScoreIsNonZero: Found break for single break factor score for group (Spots={0}; BreaksRemaining={1})", spotDetailsListString, smoothBreaksRemaining.Count)
                                    );

                                usedBestBreakFactorGroup    = bestBreakFactorGroup;
                                bestBreakResult.Score       = bestBreakScore2;
                                bestBreakResult.SmoothBreak = smoothBreaksRemaining[0];
                                return(bestBreakResult);
                            }
                            else
                            {
                                _smoothDiagnostics.LogBestBreakFactorMessage(
                                    smoothPass,
                                    smoothPassIteration,
                                    bestBreakFactorGroup,
                                    null,
                                    spotsToPlace,
                                    null,
                                    string.Format("UseSingleBreakFactorIfBestScoreIsNonZero: WARNING: Not found break for single break factor score for group (Spots={0}; BreaksRemaining={1})", spotDetailsListString, smoothBreaksRemaining.Count)
                                    );
                            }

                            break;
                        }
                    }
                }
                else    // No break has a non-zero score, check next group
                {
                    _smoothDiagnostics.LogBestBreakFactorMessage(
                        smoothPass,
                        smoothPassIteration,
                        bestBreakFactorGroup,
                        null,
                        spotsToPlace,
                        null,
                        "No breaks with highest score, checking next group"
                        );
                }
            }

            _smoothDiagnostics.LogBestBreakFactorMessage(
                smoothPass,
                smoothPassIteration,
                null,
                null,
                spotsToPlace,
                null,
                "No best break for spots"
                );

            // All groups checked, no best break, shouldn't really happen,
            // possibly bad configuration
            return(bestBreakResult);
        }