Esempio n. 1
0
        /// <summary>
        /// Finds patterns of A on the left followed immediately by B on the right (with no other intermediate events), occurring within (strictly less than) a given time duration
        /// </summary>
        /// <typeparam name="TKey">Key type</typeparam>
        /// <typeparam name="TPayload">Payload type for left input</typeparam>
        /// <typeparam name="TPayload2">Payload type for right input</typeparam>
        /// <typeparam name="TResult">Result type</typeparam>
        /// <param name="stream">Left input stream</param>
        /// <param name="stream2">Right input stream</param>
        /// <param name="firstMatch">First element in pattern</param>
        /// <param name="secondMatch">Second element in pattern</param>
        /// <param name="resultSelector">Compose result tuple using matching input events</param>
        /// <param name="withinDuration">Pattern occurs within (strictly less than) given time duration</param>
        /// <returns>Pattern result stream</returns>
        public static IStreamable <TKey, TResult> FollowedByImmediate <TKey, TPayload, TPayload2, TResult>(
            this IStreamable <TKey, TPayload> stream,
            IStreamable <TKey, TPayload2> stream2,
            Expression <Func <TPayload, bool> > firstMatch,
            Expression <Func <TPayload2, bool> > secondMatch,
            Expression <Func <TPayload, TPayload2, TResult> > resultSelector,
            long withinDuration)
        {
            if (withinDuration >= 0)
            {
                // Set match duration
                if (withinDuration < 2)
                {
                    throw new Exception("Duration has to be at least 2 chronons");
                }
                if (withinDuration > StreamEvent.MaxSyncTime)
                {
                    throw new Exception("Duration is too large");
                }
                stream = stream.AlterEventDuration(withinDuration - 1);
            }

            // Clip the stream with itself, to make it a signal stream
            var clippedStream = stream.ClipEventDuration(stream2);

            // Shift the left side (first match) by one chronon, set right side (second match) to one chronon duration, join to find matches
            var result = clippedStream.Multicast(xs => xs.Where(firstMatch).ShiftEventLifetime(1).Join(stream2.Where(secondMatch).AlterEventDuration(1), resultSelector));

            return(result);
        }
Esempio n. 2
0
        /// <summary>
        /// Finds patterns of events that are repeated consecutively
        /// </summary>
        /// <typeparam name="TKey">Key type</typeparam>
        /// <typeparam name="TPayload">Payload type</typeparam>
        /// <typeparam name="TResult">Result type</typeparam>
        /// <param name="stream">Input stream</param>
        /// <param name="resultSelector">Compose result tuple using matching input events</param>
        /// <returns>Pattern result stream</returns>
        public static IStreamable <TKey, TResult> ConsecutivePairs <TKey, TPayload, TResult>(
            this IStreamable <TKey, TPayload> stream,
            Expression <Func <TPayload, TPayload, TResult> > resultSelector)
        {
            // Clip the stream with itself, to make it a signal stream
            var clippedStream = stream.AlterEventDuration(StreamEvent.InfinitySyncTime).Multicast(xs => xs.ClipEventDuration(xs));

            // Shift the left side (first match) by one chronon, set right side (second match) to one chronon duration, join to find pairs
            var result = clippedStream.Multicast(xs => xs.ShiftEventLifetime(1).Join(xs.AlterEventDuration(1), resultSelector));

            return(result);
        }
Esempio n. 3
0
 /// <summary>
 /// Index continuous intervals of the stream.
 /// </summary>
 /// <param name="source">Input stream</param>
 /// <param name="gap_tol">Gap tolerance</param>
 /// <returns>Events corresponding to continuous intervals</returns>
 public static IStreamable <TKey, Unit> Index <TKey, TPayload>(
     this IStreamable <TKey, TPayload> source,
     long gap_tol
     )
 {
     return(source
            .AlterEventDuration((s, e) => e - s + gap_tol)
            .Multicast(s => s.ClipEventDuration(s))
            .Select(e => Unit.Default)
            .Stitch()
            .AlterEventDuration((s, e) => e - s - gap_tol)
            );
 }
Esempio n. 4
0
 /// <summary>
 /// Performs the 'Chop' operator to chop (partition) gap intervals across beat boundaries with gap tolerance.
 /// </summary>
 /// <param name="source">Input stream</param>
 /// <param name="offset">Stream offset</param>
 /// <param name="period">Beat period to chop</param>
 /// <param name="gap_tol">Gap tolerance</param>
 /// <returns>Signal stream after gaps chopped</returns>
 public static IStreamable <TKey, TPayload> Chop <TKey, TPayload>(
     this IStreamable <TKey, TPayload> source,
     long offset,
     long period,
     long gap_tol)
 {
     gap_tol = Math.Max(period, gap_tol);
     return(source
            .AlterEventDuration((s, e) => e - s + gap_tol)
            .Multicast(t => t.ClipEventDuration(t))
            .AlterEventDuration((s, e) => (e - s > gap_tol) ? period : e - s)
            .Chop(offset, period)
            );
 }
Esempio n. 5
0
        private static void JoinPointsTest(bool fixedInterval = false)
        {
            var left  = new Subject <StreamEvent <string> >();
            var right = new Subject <StreamEvent <string> >();


            var qc = new QueryContainer();
            IStreamable <Empty, string> leftInput  = qc.RegisterInput(left);
            IStreamable <Empty, string> rightInput = qc.RegisterInput(right);

            if (fixedInterval)
            {
                leftInput  = leftInput.AlterEventDuration(1);
                rightInput = rightInput.AlterEventDuration(1);
            }

            var query = leftInput.Join(
                rightInput,
                l => (l != null ? l[0].ToString() : null),
                r => (r != null ? r[0].ToString() : null),
                (l, r) => $"{l},{r}");

            var output = new List <StreamEvent <string> >();

            qc.RegisterOutput(query).ForEachAsync(o => output.Add(o));
            var process = qc.Restore();

            // Should match and egress immediately
            left.OnNext(StreamEvent.CreatePoint(100, "A1"));
            right.OnNext(StreamEvent.CreatePoint(100, "A2"));
            process.Flush();

            var expected = new StreamEvent <string>[]
            {
                StreamEvent.CreatePoint(100, "A1,A2"),
            };

            Assert.IsTrue(expected.SequenceEqual(output));
            output.Clear();

            left.OnCompleted();
            right.OnCompleted();
        }
Esempio n. 6
0
        /// <summary>
        /// ConsecutivePairs with gap_tolerance
        /// </summary>
        /// <typeparam name="TKey">Key type</typeparam>
        /// <typeparam name="TPayload">Payload type</typeparam>
        /// <typeparam name="TResult">Result type</typeparam>
        /// <param name="stream">Input stream</param>
        /// <param name="resultSelector">Compose result tuple using matching input events</param>
        /// <param name="gap_tol">Gap tolerance</param>
        /// <param name="period">Period of input stream (default: 1)</param>
        /// <returns>Pattern result stream</returns>
        public static IStreamable <TKey, TResult> ConsecutivePairs <TKey, TPayload, TResult>(
            this IStreamable <TKey, TPayload> stream,
            Expression <Func <TPayload, TPayload, TResult> > resultSelector,
            long gap_tol,
            long period = 1)
        {
            var clippedStream = stream
                                .AlterEventDuration((s, e) => e - s + gap_tol)
                                .Multicast(xs => xs.ClipEventDuration(xs))
                                .AlterEventDuration((s, e) => (e - s > gap_tol) ? period : e - s)
            ;

            var result = clippedStream
                         .Multicast(xs => xs
                                    .ShiftEventLifetime(1)
                                    .Join(xs.AlterEventDuration(1), resultSelector));

            return(result);
        }