private static void ResolveConflictOnMachine(
            OnlineConflict conflict,
            ref LinkedListNode <IOnlineChainNode> nodeOnCurrentMachine,
            ref LinkedListNode <IOnlineChainNode> nodeOnAnotherMachine,
            bool isFirstDetail,
            OnlineChain chainOnCurrentMachine,
            OnlineChain chainOnAnotherMachine,
            double timeFromMachinesStart,
            OnlineExecutionContext context)
        {
            if (!(chainOnAnotherMachine.First(i =>
                                              i.Type == OnlineChainType.Conflict &&
                                              (i as OnlineConflict).Details.Keys.SequenceEqual(conflict.Details.Keys)) is OnlineConflict
                  conflictOnAnotherMachine))
            {
                throw new InvalidOperationException("Not found conflict on another machine");
            }

            var conflictNodeOnAnotherMachine = chainOnAnotherMachine.Find(conflictOnAnotherMachine);
            var nodeOnCurrentMachineToRemove = nodeOnCurrentMachine;

            if (!isFirstDetail)
            {
                var sumOfPOnCurrent = chainOnCurrentMachine
                                      .TakeWhile(i => !Equals(i, nodeOnCurrentMachineToRemove.Value))
                                      .Sum(i => i.Type switch
                {
                    OnlineChainType.Detail when i is Detail detail => detail.Time.P,
                    OnlineChainType.Downtime when i is Downtime downtime => downtime.Time,
                    _ => throw new InvalidOperationException()
                });
        private static void ProcessDetailOnMachine(
            OnlineChain chain,
            ref LinkedListNode <IOnlineChainNode> node,
            Func <Detail, double> downtimeCalculationFunc,
            ISet <int> processedDetailNumbersOnAnotherMachine,
            ref double time,
            bool isFirstDetail,
            OnlineExecutionContext context,
            ConflictResolverDelegate conflictResolver)
        {
            var currentDetail = node.Value;

            if (currentDetail.Type == OnlineChainType.Conflict)
            {
                var conflict = currentDetail as OnlineConflict;

                var start = Stopwatch.GetTimestamp();
                conflictResolver(conflict, ref node, context, isFirstDetail);
                var stop = Stopwatch.GetTimestamp();

                context.ExecutionTime = context.ExecutionTime.Add(
                    TimeSpan.FromMilliseconds((stop - start) / (double)Stopwatch.Frequency * 1000));


                if (node.Value.Type != OnlineChainType.Detail)
                {
                    throw new InvalidOperationException("Conflict resolver didn't change current node");
                }

                currentDetail = node.Value;
            }

            if (!(currentDetail is Detail detail))
            {
                throw new InvalidCastException(
                          $"Try cast {currentDetail.GetType().FullName} to {typeof(Detail).FullName}");
            }

            if (processedDetailNumbersOnAnotherMachine.Contains(detail.Number))
            {
                time += detail.Time.P;
            }
            else
            {
                var downTime = downtimeCalculationFunc(detail);

                if (Math.Abs(downTime) < 0.000000000000001)
                {
                    node = node.Previous;
                    return;
                }

                node = chain.AddBefore(node, new Downtime(downTime));

                time += downTime;
            }
        }
        public void Execute_ShouldBeFinishedWithoutAnyExceptions(string path,
                                                                 OnlineChain onlineChainOnFirst, OnlineChain onlineChainOnSecond, HashSet <int> processedOnFirst,
                                                                 HashSet <int> processedOnSecond)
        {
            // Arrange
            _outputHelper.WriteLine($"Running test with data from '{path}'");

            // Act
            var context = _onlineExecutor.Execute(onlineChainOnFirst, onlineChainOnSecond, processedOnFirst,
                                                  processedOnSecond);

            // Assert
            context.Should().NotBeNull();
        }
Exemple #4
0
        private static OnlineChain GetOnlineChainOnSecondMachine(ExperimentInfo experimentInfo)
        {
            var onlineChain = new OnlineChain();

            foreach (var chainNode in experimentInfo.J21Chain)
            {
                var element = chainNode.Type switch
                {
                    ChainType.Detail when chainNode is LaboriousDetail detail => (IOnlineChainNode)detail.OnSecond,
                    ChainType.Conflict when chainNode is Conflict conflict => new OnlineConflict(
                        conflict.Details.Values.Select(d =>
                                                       new KeyValuePair <int, Detail>(d.OnSecond.Number, d.OnSecond))),
                    _ => throw new InvalidOperationException()
                };

                onlineChain.AddLast(element);
            }

            foreach (var j2 in experimentInfo.J2)
            {
                onlineChain.AddLast(j2);
            }

            foreach (var chainNode in experimentInfo.J12Chain)
            {
                var element = chainNode.Type switch
                {
                    ChainType.Detail when chainNode is LaboriousDetail detail => (IOnlineChainNode)detail.OnSecond,
                    ChainType.Conflict when chainNode is Conflict conflict => new OnlineConflict(
                        conflict.Details.Values.Select(d =>
                                                       new KeyValuePair <int, Detail>(d.OnSecond.Number, d.OnSecond))),
                    _ => throw new InvalidOperationException()
                };

                onlineChain.AddLast(element);
            }

            return(onlineChain);
        }
        public OnlineExecutionContext Execute(OnlineChain onlineChainOnFirst, OnlineChain onlineChainOnSecond,
                                              HashSet <int> processedDetailsOnFirst, HashSet <int> processedDetailsOnSecond)
        {
            var context = new OnlineExecutionContext();

            IOnlineChainNode currentDetailOnFirst  = null;
            IOnlineChainNode currentDetailOnSecond = null;

            var timeFromMachinesStart = 0.0;
            var time1 = 0.0;
            var time2 = 0.0;

            var isFirstDetail = true;

            var nodeOnFirstMachine  = onlineChainOnFirst.First;
            var nodeOnSecondMachine = onlineChainOnSecond.First;

            var hasDetailOnFirst  = nodeOnFirstMachine != null;
            var hasDetailOnSecond = nodeOnSecondMachine != null;

            // details are on two machines
            while (hasDetailOnFirst && hasDetailOnSecond ||
                   time1 > time2 && hasDetailOnSecond ||
                   time2 > time1 && hasDetailOnFirst)
            {
                // time1 equal to time2
                if (Math.Abs(time1 - time2) < 0.001)
                {
                    if (hasDetailOnFirst)
                    {
                        ProcessDetailOnMachine(
                            ref currentDetailOnFirst,
                            processedDetailsOnFirst,
                            processedDetailsOnSecond,
                            ref nodeOnFirstMachine,
                            ref nodeOnSecondMachine,
                            timeFromMachinesStart,
                            onlineChainOnFirst,
                            onlineChainOnSecond,
                            ref time1,
                            out hasDetailOnFirst,
                            isFirstDetail,
                            context);
                    }


                    //if (nodeOnSecondMachine?.List == null)
                    //{
                    //    if (isFirstDetail)
                    //        nodeOnSecondMachine = experimentInfo.OnlineChainOnSecondMachine.First;
                    //}

                    if (hasDetailOnSecond)
                    {
                        ProcessDetailOnMachine(
                            ref currentDetailOnSecond,
                            processedDetailsOnSecond,
                            processedDetailsOnFirst,
                            ref nodeOnSecondMachine,
                            ref nodeOnFirstMachine,
                            timeFromMachinesStart,
                            onlineChainOnSecond,
                            onlineChainOnFirst,
                            ref time2,
                            out hasDetailOnSecond,
                            isFirstDetail,
                            context);
                    }
                }
                else if (time1 < time2)
                {
                    ProcessDetailOnMachine(
                        ref currentDetailOnFirst,
                        processedDetailsOnFirst,
                        processedDetailsOnSecond,
                        ref nodeOnFirstMachine,
                        ref nodeOnSecondMachine,
                        timeFromMachinesStart,
                        onlineChainOnFirst,
                        onlineChainOnSecond,
                        ref time1,
                        out hasDetailOnFirst,
                        isFirstDetail,
                        context);
                }
                else
                {
                    ProcessDetailOnMachine(
                        ref currentDetailOnSecond,
                        processedDetailsOnSecond,
                        processedDetailsOnFirst,
                        ref nodeOnSecondMachine,
                        ref nodeOnFirstMachine,
                        timeFromMachinesStart,
                        onlineChainOnSecond,
                        onlineChainOnFirst,
                        ref time2,
                        out hasDetailOnSecond,
                        isFirstDetail,
                        context);
                }

                timeFromMachinesStart = Math.Min(time1, time2);

                isFirstDetail = false;
            }

            // details only on first machines
            if (hasDetailOnFirst)
            {
                for (var node = nodeOnFirstMachine; node != null; node = node.Next)
                {
                    if (node.Value is Detail detail)
                    {
                        time1 += detail.Time.P;
                    }
                    else
                    {
                        throw new InvalidOperationException(
                                  "There can be no conflicts and downtimes when one of machine finished work");
                    }
                }
            }
            else
            {
                // details only on second machine
                for (var node = nodeOnSecondMachine; node != null; node = node.Next)
                {
                    if (node.Value is Detail detail)
                    {
                        time2 += detail.Time.P;
                    }
                    else
                    {
                        throw new InvalidOperationException(
                                  "There can be no conflicts and downtimes when one of machine finished work");
                    }
                }
            }

            timeFromMachinesStart = Math.Max(time1, time2);

            context.TimeFromMachinesStart = timeFromMachinesStart;
            context.Time1 = time1;
            context.Time2 = time2;

            return(context);
        }