コード例 #1
0
        public void GraphDSLs_Partial_must_be_able_to_build_and_reuse_simple_partial_graphs()
        {
            var doubler = GraphDsl.Create(b =>
            {
                var broadcast = b.Add(new Broadcast <int>(2));
                var zip       = b.Add(ZipWith.Apply((int i, int i1) => i + i1));

                b.From(broadcast.Out(0)).To(zip.In0);
                b.From(broadcast.Out(1)).To(zip.In1);

                return(new FlowShape <int, int>(broadcast.In, zip.Out));
            });

            var task =
                RunnableGraph.FromGraph(GraphDsl.Create(doubler, doubler, Sink.First <IEnumerable <int> >(), Tuple.Create,
                                                        (b, d1, d2, sink) =>
            {
                var source =
                    Source.From(Enumerable.Range(1, 3))
                    .MapMaterializedValue <Tuple <NotUsed, NotUsed, Task <IEnumerable <int> > > >(_ => null);

                b.From(source).To(d1.Inlet);
                b.From(d1.Outlet).To(d2.Inlet);
                b.From(d2.Outlet).Via(Flow.Create <int>().Grouped(100)).To(sink.Inlet);

                return(ClosedShape.Instance);
            })).Run(Materializer).Item3;

            task.Wait(TimeSpan.FromSeconds(3)).Should().BeTrue();
            task.Result.ShouldAllBeEquivalentTo(new[] { 4, 8, 12 });
        }
コード例 #2
0
        public void GraphDSLs_Partial_must_be_able_to_build_and_reuse_simple_partial_graphs()
        {
            var doubler = GraphDsl.Create(b =>
            {
                var broadcast = b.Add(new Broadcast <int>(2));
                var zip       = b.Add(ZipWith.Apply((int i, int i1) => i + i1));

                b.From(broadcast.Out(0)).To(zip.In0);
                b.From(broadcast.Out(1)).To(zip.In1);

                return(new FlowShape <int, int>(broadcast.In, zip.Out));
            });

            var task =
                RunnableGraph.FromGraph(GraphDsl.Create(doubler, doubler, Sink.First <IEnumerable <int> >(), ValueTuple.Create,
                                                        (b, d1, d2, sink) =>
            {
                var source =
                    Source.From(Enumerable.Range(1, 3))
                    .MapMaterializedValue(_ => default((NotUsed, NotUsed, Task <IEnumerable <int> >)));

                b.From(source).To(d1.Inlet);
                b.From(d1.Outlet).To(d2.Inlet);
                b.From(d2.Outlet).Via(Flow.Create <int>().Grouped(100)).To(sink.Inlet);

                return(ClosedShape.Instance);
            })).Run(Materializer).Item3;
コード例 #3
0
ファイル: GraphTests.cs プロジェクト: matej-hron/POC
        public void PartialGraph()
        {
            var pickMaxOfThree = GraphDsl.Create(b =>
            {
                var zip1 = b.Add(ZipWith.Apply <int, int, int>(Math.Max));
                var zip2 = b.Add(ZipWith.Apply <int, int, int>(Math.Max));
                b.From(zip1.Out).To(zip2.In0);

                return(new UniformFanInShape <int, int>(zip2.Out, zip1.In0, zip1.In1, zip2.In1));
            });

            var resultSink = Sink.First <int>();

            var g = RunnableGraph.FromGraph(GraphDsl.Create(resultSink, (b, sink) =>
            {
                var pm3 = b.Add(pickMaxOfThree);
                var s1  = Source.Single(1).MapMaterializedValue <Task <int> >(_ => null);
                var s2  = Source.Single(2).MapMaterializedValue <Task <int> >(_ => null);
                var s3  = Source.Single(3).MapMaterializedValue <Task <int> >(_ => null);

                b.From(s1).To(pm3.In(0));
                b.From(s2).To(pm3.In(1));
                b.From(s3).To(pm3.In(2));

                b.From(pm3.Out).To(sink);

                return(ClosedShape.Instance);
            }));

            var max = WithMaterializer(g.Run);

            Assert.That(max.Result, Is.EqualTo(3));
        }
コード例 #4
0
        public void GraphDSLs_Partial_must_be_able_to_build_and_reuse_complex_materializing_partial_graphs()
        {
            var summer = Sink.Aggregate <int, int>(0, (i, i1) => i + i1);

            var doubler = GraphDsl.Create(summer, summer, Tuple.Create, (b, s1, s2) =>
            {
                var broadcast  = b.Add(new Broadcast <int>(3));
                var broadcast2 = b.Add(new Broadcast <int>(2));
                var zip        = b.Add(ZipWith.Apply((int i, int i1) => i + i1));

                b.From(broadcast.Out(0)).To(zip.In0);
                b.From(broadcast.Out(1)).To(zip.In1);
                b.From(broadcast.Out(2)).To(s1.Inlet);

                b.From(zip.Out).To(broadcast2.In);
                b.From(broadcast2.Out(0)).To(s2.Inlet);

                return(new FlowShape <int, int>(broadcast.In, broadcast2.Out(1)));
            });

            var t =
                RunnableGraph.FromGraph(GraphDsl.Create(doubler, doubler, Sink.First <IEnumerable <int> >(), Tuple.Create,
                                                        (b, d1, d2, sink) =>
            {
                var source =
                    Source.From(Enumerable.Range(1, 3))
                    .MapMaterializedValue <Tuple <Tuple <Task <int>, Task <int> >, Tuple <Task <int>, Task <int> >, Task <IEnumerable <int> > > >(_ => null);

                b.From(source).To(d1.Inlet);
                b.From(d1.Outlet).To(d2.Inlet);
                b.From(d2.Outlet).Via(Flow.Create <int>().Grouped(100)).To(sink.Inlet);

                return(ClosedShape.Instance);
            })).Run(Materializer);

            var task = Task.WhenAll(t.Item1.Item1, t.Item1.Item2, t.Item2.Item1, t.Item2.Item2);

            task.Wait(TimeSpan.FromSeconds(3)).Should().BeTrue();
            task.Result.ShouldAllBeEquivalentTo(new[] { 6, 12, 12, 24 });
            t.Item3.Wait(TimeSpan.FromSeconds(3)).Should().BeTrue();
            t.Item3.Result.ShouldAllBeEquivalentTo(new [] { 4, 8, 12 });
        }
コード例 #5
0
        public void ZipWith_must_work_with_up_to_9_inputs()
        {
            // the jvm version uses 19 inputs but we have only 9

            this.AssertAllStagesStopped(() =>
            {
                var probe = this.CreateManualSubscriberProbe <string>();

                RunnableGraph.FromGraph(GraphDsl.Create(b =>
                {
                    Func <int, string, int, string, int, string, int, string, int, string> sum9 =
                        (i1, s1, i2, s2, i3, s3, i4, s4, i5) => i1 + s1 + i2 + s2 + i3 + s3 + i4 + s4 + i5;

                    // odd input ports will be Int, even input ports will be String
                    var zipWith = b.Add(ZipWith.Apply(sum9));

                    b.From(Source.Single(1)).To(zipWith.In0);
                    b.From(Source.Single("2")).To(zipWith.In1);
                    b.From(Source.Single(3)).To(zipWith.In2);
                    b.From(Source.Single("4")).To(zipWith.In3);
                    b.From(Source.Single(5)).To(zipWith.In4);
                    b.From(Source.Single("6")).To(zipWith.In5);
                    b.From(Source.Single(7)).To(zipWith.In6);
                    b.From(Source.Single("8")).To(zipWith.In7);
                    b.From(Source.Single(9)).To(zipWith.In8);
                    b.From(zipWith.Out).To(Sink.FromSubscriber(probe));

                    return(ClosedShape.Instance);
                })).Run(Materializer);

                var subscription = probe.ExpectSubscription();

                subscription.Request(1);
                probe.ExpectNext(Enumerable.Range(1, 9).Aggregate("", (s, i) => s + i));
                probe.ExpectComplete();
            }, Materializer);
        }
コード例 #6
0
        private static RunnableGraph <ISourceQueueWithComplete <ChannelData <float> > > CreateGraph(IActorRef target, List <ChannelAdjusterConfig> configs, ChannelData <float> sample)
        {
            /*
             *  Digital Merger is only necessary when there are additional digitals created and the same goes for the
             *  Broadcast following the Analog Splitter. A broadcast is only required when the analog channel is produces
             *  the additional digitals. Otherwise the analog is pushed straight to the merger
             +---------------+--------------+-----------------------------------------------------------------------+
             |               |              |                     SyncData                           |              |
             |               |              +-------------+----------------+-------------------------+              |
             |  QueueSource  | Channel Data |             |    FilterFlow           |                | Channel Data |
             |               |    Splitter  |    Analog   |  ================       |     Analog     |              |
             |               |              |   Splitter  |  Broadcast => Filter    |     Merger     |              |
             |               |              |             |         ----------------+----------------+              |
             |               |              |             |         \=> -FullScale  |                |              |
             |               |              |             |         \=> +FullScale  |    Digital     |              |
             |               |              |             |         \=> FlatLining  |     Merger     |              |
             |               |              +-------------+-------------------------+                |              |
             |               |              |    Digitals                           |                |              |
             +---------------+--------------+-----------------------------------------------------------------------+
             */

            var indices = GetIndices(sample, configs);
            var number  = indices.Count();

            var temporalOffsets = configs.Select(x => - x.TemporalOffset).Append(0);

            var temp        = temporalOffsets.Select(x => x - temporalOffsets.Min()).ToList();
            var skipIndices = temp.Take(temp.Count - 1).ToList();
            var zerothIndex = temp.Last();



            var bufferSize      = temp.Max() + 1;
            var skipFlowsNeeded = skipIndices.Any(x => x != 0);

            var graph = GraphDsl.Create(Source.Queue <ChannelData <float> >(10000, OverflowStrategy.Backpressure), (builder, source) =>
            {
                //Split channel data into sync data, analogs and digitals
                var channelDataSplitter = new UnzipWith <
                    ChannelData <float>,
                    ISyncData,
                    IReadOnlyList <DataChannel <float> >,
                    IReadOnlyList <DataChannel <bool> >
                    >(cd => Tuple.Create(cd as ISyncData, cd.Analogs, cd.Digitals));
                var channelDataSplitterShape = builder.Add(channelDataSplitter);

                //Split, filter and reorder the analog channels into the required data channels
                var analogSplitter = new UnzipEnumerable <
                    IReadOnlyList <DataChannel <float> >,
                    DataChannel <float>
                    >(list => indices.Select(i => list[i]).ToImmutableList(), number
                      );
                var analogSplitterShape = builder.Add(analogSplitter);

                //Re-combine the filtered analog channels
                var analogMerger      = new ZipN <DataChannel <float> >(number);
                var analogMergerShape = builder.Add(analogMerger);

                //Digital additional flows
                var additionalDigitalFlows = new List <FlowShape <DataChannel <float>, DataChannel <bool> > >();

                //Create the appropriate analog filtering flows.
                for (int i = 0; i < configs.Count(); i++)
                {
                    var skipValue = skipIndices[i];
                    //Create new flows for the analogs
                    switch (configs[i].Option)
                    {
                    // 1a) Each cfg generates one analog flow...
                    case FilterOption.PassThrough:
                        if (skipFlowsNeeded)
                        {
                            builder.From(analogSplitterShape.Out(i))
                            .Via(
                                builder.Add(
                                    Flow.Create <DataChannel <float> >()
                                    .Buffer(bufferSize, OverflowStrategy.Backpressure)
                                    .Skip(skipValue)
                                    .Log("AnalogLog")
                                    )
                                )
                            .To(analogMergerShape.In(i));
                        }
                        else
                        {
                            // Pass through channels can be connected straight from the splitter to the merger.
                            builder.From(analogSplitterShape.Out(i)).To(analogMergerShape.In(i));
                        }
                        break;

                    case FilterOption.Filter:
                        // Filtered channels create a single flow and connected from the splitter to the merger.
                        var scale  = configs[i].Scale;
                        var offset = configs[i].Offset;

                        var filterFlow = skipFlowsNeeded ?
                                         Flow.Create <DataChannel <float> >()
                                         .Buffer(bufferSize, OverflowStrategy.Backpressure)
                                         .Skip(skipValue)
                                         .Select(x => new DataChannel <float>(x.Name, x.Value * scale + offset, x.Units))
                                                    :
                                         Flow.Create <DataChannel <float> >()
                                         .Select(x => new DataChannel <float>(x.Name, x.Value * scale + offset, x.Units));

                        builder.From(analogSplitterShape.Out(i)).Via(builder.Add(filterFlow)).To(analogMergerShape.In(i));
                        break;

                    // 1b) OR One analog flow and 3 additional digital flows.
                    case FilterOption.CreateDigitals:
                        // Filtered channels that create digitals creates a broadcaster for the analog channel first...
                        var analogBroadcaster = new Broadcast <DataChannel <float> >(4);

                        // ...then three flows for the digitals
                        var d1Flow = builder.Add(Flow.Create <DataChannel <float> >().Select(x => new DataChannel <bool>($"{x.Name}_+FullScale", false)));
                        var d2Flow = builder.Add(Flow.Create <DataChannel <float> >().Select(x => new DataChannel <bool>($"{x.Name}_-FullScale", false)));
                        var d3Flow = builder.Add(Flow.Create <DataChannel <float> >().Select(x => new DataChannel <bool>($"{x.Name}_Flatlining", false)));

                        // ...add the digital flow shapes to be connected later
                        additionalDigitalFlows.Add(d1Flow);
                        additionalDigitalFlows.Add(d2Flow);
                        additionalDigitalFlows.Add(d3Flow);

                        // ...create the broadcaster shape
                        var analogBroadcasterShape = builder.Add(analogBroadcaster);

                        // ...create the filter flow and connect the broadcaster to the merger via the filter
                        var scaler    = configs[i].Scale;
                        var offsetter = configs[i].Offset;
                        var filter    = skipFlowsNeeded ?
                                        Flow.Create <DataChannel <float> >()
                                        .Buffer(bufferSize, OverflowStrategy.Backpressure)
                                        .Skip(skipValue)
                                        .Select(x => new DataChannel <float>(x.Name, x.Value * scaler + offsetter, x.Units))
                                                :
                                        Flow.Create <DataChannel <float> >()
                                        .Select(x => new DataChannel <float>(x.Name, x.Value * scaler + offsetter, x.Units));


                        // ...link the analog splitter output to the broadcaster
                        builder.From(analogSplitterShape.Out(i))
                        .Via(filter)
                        .To(analogBroadcasterShape);

                        builder.From(analogBroadcasterShape.Out(0)).To(analogMergerShape.In(i));
                        // ...link the broadcaster channels to the additional digital flows
                        builder.From(analogBroadcasterShape.Out(1)).Via(d1Flow);
                        builder.From(analogBroadcasterShape.Out(2)).Via(d2Flow);
                        builder.From(analogBroadcasterShape.Out(3)).Via(d3Flow);
                        break;

                    case FilterOption.NotSet:
                        throw new ArgumentException("Filter Option Not Set is not allowed.");
                    }
                }

                //Merge everything back together
                var channelDataMerger = ZipWith.Apply <
                    ISyncData,
                    IImmutableList <DataChannel <float> >,
                    IReadOnlyList <DataChannel <bool> >,
                    ChannelData <float>
                    >(
                    (sync, analogs, digitals) => new ChannelData <float>
                    (
                        analogs,
                        digitals,
                        sync.TimeStamp,
                        sync.TachometerCount,
                        sync.MasterSyncIncrement,
                        sync.MasterSyncState,
                        sync.SampleIndex
                    )
                    );
                var channelDataMergerShape = builder.Add(channelDataMerger);

                //Sink
                var sink      = Sink.ActorRef <ChannelData <float> >(target, false);
                var sinkShape = builder.Add(sink);

                //_________Link stages_________

                //=====Source=====
                //Source to the channel data splitter
                if (skipFlowsNeeded)
                {
                    builder.From(source)
                    .Via(builder.Add(Flow.Create <ChannelData <float> >().Buffer(bufferSize, OverflowStrategy.Backpressure)))
                    .To(channelDataSplitterShape.In);

                    //=====Splitter=====
                    //Splitter sync data to merger.
                    builder.From(channelDataSplitterShape.Out0)
                    .Via(builder.Add(Flow.Create <ISyncData>().Buffer(bufferSize, OverflowStrategy.Backpressure).Skip(zerothIndex)))
                    .To(channelDataMergerShape.In0);

                    //Splitter analogs to analog splitter.
                    builder.From(channelDataSplitterShape.Out1)
                    .Via(builder.Add(Flow.Create <IReadOnlyList <DataChannel <float> > >().Buffer(bufferSize, OverflowStrategy.Backpressure)))
                    .To(analogSplitterShape.In);

                    //=====AdditionalDigitalFlows=====
                    if (additionalDigitalFlows.Count > 0)
                    {
                        // Additonal Digital Merger
                        var additionalDigitalMerger      = new ZipWithN <DataChannel <bool>, IImmutableList <DataChannel <bool> > >(channel => channel, additionalDigitalFlows.Count);
                        var additionalDigitalMergerShape = builder.Add(additionalDigitalMerger);

                        //Combine the input digitals with the generated additional digitals
                        var digitalMerger      = ZipWith.Apply <List <DataChannel <bool> >, ImmutableList <DataChannel <bool> >, IReadOnlyList <DataChannel <bool> > >((channel1, channel2) => channel1.Concat(channel2).ToList());
                        var digitalMergerShape = builder.Add(digitalMerger);

                        //Splitter digitals to digital merger.
                        builder.From(channelDataSplitterShape.Out2)
                        .Via(builder.Add(Flow.Create <IReadOnlyList <DataChannel <bool> > >().Buffer(bufferSize, OverflowStrategy.Backpressure)))
                        .To(digitalMergerShape.In0);

                        // Merge all additional flows together.
                        for (int i = 0; i < additionalDigitalFlows.Count; i++)
                        {
                            builder.From(additionalDigitalFlows[i]).To(additionalDigitalMergerShape.In(i));
                        }
                        //Additional digitals to digital merger
                        builder.From(additionalDigitalMergerShape.Out).To(digitalMergerShape.In1);

                        //=====DigitalMerger=====
                        //Digital merger to channel data merger
                        builder.From(digitalMergerShape.Out).To(channelDataMergerShape.In2);
                    }
                    else
                    {
                        // Splitter digitals to final merger.
                        builder.From(channelDataSplitterShape.Out2)
                        .Via(builder.Add(Flow.Create <IReadOnlyList <DataChannel <bool> > >().Buffer(bufferSize, OverflowStrategy.Backpressure)))
                        .To(channelDataMergerShape.In2);
                    }

                    // Analog merger to final merger.
                    builder.From(analogMergerShape.Out).To(channelDataMergerShape.In1);


                    //=====Merger=====
                    //Channel Data Merger to sink
                    builder.From(channelDataMergerShape.Out).To(sinkShape);
                }
                else
                {
                    builder.From(source).To(channelDataSplitterShape.In);

                    //=====Splitter=====
                    //Splitter sync data to merger.
                    builder.From(channelDataSplitterShape.Out0).To(channelDataMergerShape.In0);
                    //Splitter analogs to analog splitter.
                    builder.From(channelDataSplitterShape.Out1).To(analogSplitterShape.In);

                    //=====AdditionalDigitalFlows=====
                    if (additionalDigitalFlows.Count > 0)
                    {
                        // Additonal Digital Merger
                        var additionalDigitalMerger      = new ZipWithN <DataChannel <bool>, IImmutableList <DataChannel <bool> > >(channel => channel, additionalDigitalFlows.Count);
                        var additionalDigitalMergerShape = builder.Add(additionalDigitalMerger);

                        //Combine the input digitals with the generated additional digitals
                        var digitalMerger      = ZipWith.Apply <List <DataChannel <bool> >, ImmutableList <DataChannel <bool> >, IReadOnlyList <DataChannel <bool> > >((channel1, channel2) => channel1.Concat(channel2).ToList());
                        var digitalMergerShape = builder.Add(digitalMerger);

                        //Splitter digitals to digital merger.
                        builder.From(channelDataSplitterShape.Out2).To(digitalMergerShape.In0);

                        // Merge all additional flows together.
                        for (int i = 0; i < additionalDigitalFlows.Count; i++)
                        {
                            builder.From(additionalDigitalFlows[i]).To(additionalDigitalMergerShape.In(i));
                        }
                        //Additional digitals to digital merger
                        builder.From(additionalDigitalMergerShape.Out).To(digitalMergerShape.In1);

                        //=====DigitalMerger=====
                        //Digital merger to channel data merger
                        builder.From(digitalMergerShape.Out).To(channelDataMergerShape.In2);
                    }
                    else
                    {
                        // Splitter digitals to final merger.
                        builder.From(channelDataSplitterShape.Out2).To(channelDataMergerShape.In2);
                    }

                    // Analog merger to final merger.
                    builder.From(analogMergerShape.Out).To(channelDataMergerShape.In1);


                    //=====Merger=====
                    //Channel Data Merger to sink
                    builder.From(channelDataMergerShape.Out).To(sinkShape);
                }

                return(ClosedShape.Instance);
            });

            return(RunnableGraph.FromGraph(graph));
        }