PageRenderTime 32ms CodeModel.GetById 18ms RepoModel.GetById 0ms app.codeStats 0ms

/Microsoft/Product Team Samples V2.1/UdsoPatternDetector/UdsoAugmentedFiniteAutomaton/AfaOperator.cs

#
C# | 244 lines | 130 code | 26 blank | 88 comment | 20 complexity | 3e62151787bb608a0ead984ff6a58336 MD5 | raw file
Possible License(s): Apache-2.0
  1. // *********************************************************
  2. //
  3. // Copyright (c) Microsoft. All rights reserved.
  4. // This code is licensed under the Apache 2.0 License.
  5. // THIS CODE IS PROVIDED *AS IS* WITHOUT WARRANTY OR
  6. // CONDITIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED,
  7. // INCLUDING, WITHOUT LIMITATION, ANY IMPLIED WARRANTIES
  8. // OR CONDITIONS OF TITLE, FITNESS FOR A PARTICULAR
  9. // PURPOSE, MERCHANTABILITY, OR NON-INFRINGEMENT.
  10. //
  11. // *********************************************************
  12. namespace StreamInsight.Samples.UserExtensions.Afa
  13. {
  14. using System;
  15. using System.Collections.Generic;
  16. using System.Runtime.Serialization;
  17. using Microsoft.ComplexEventProcessing;
  18. using Microsoft.ComplexEventProcessing.Extensibility;
  19. /// <summary>
  20. /// The UDSO that performs pattern detection over a stream, given an AFA.
  21. /// </summary>
  22. /// <typeparam name="TInput">The event type.</typeparam>
  23. /// <typeparam name="TRegister">The register type.</typeparam>
  24. /// <typeparam name="TFactory">The type that produces an AFA descriptor for pattern detection.</typeparam>
  25. [DataContract]
  26. public sealed class AfaOperator<TInput, TRegister, TFactory> : CepPointStreamOperator<TInput, TRegister>
  27. where TFactory : IAfaDescriptorFactory<TInput, TRegister>, new()
  28. {
  29. /// <summary>
  30. /// The maximum duration of a pattern.
  31. /// </summary>
  32. [DataMember(Name = "PatternMaxDuration")]
  33. private readonly TimeSpan _patternMaxDuration;
  34. /// <summary>
  35. /// Descriptor for the AFA to be detected.
  36. /// </summary>
  37. private AfaDescriptor<TInput, TRegister> _descriptor;
  38. /// <summary>
  39. /// The current event start time.
  40. /// </summary>
  41. [DataMember(Name = "StartTime")]
  42. private DateTimeOffset? _startTime;
  43. /// <summary>
  44. /// The current set of (partial) pattern matches.
  45. /// </summary>
  46. [DataMember(Name = "CurrentRuns")]
  47. private LinkedList<Run> _currentRuns;
  48. /// <summary>
  49. /// The previous set of (partial) pattern matches.
  50. /// </summary>
  51. [DataMember(Name = "PreviousRuns")]
  52. private LinkedList<Run> _previousRuns;
  53. /// <summary>
  54. /// Initializes a new instance of AfaOperator.
  55. /// </summary>
  56. /// <param name="patternMaxDuration">The maximum duration of a pattern.</param>
  57. public AfaOperator(TimeSpan patternMaxDuration)
  58. {
  59. this._patternMaxDuration = patternMaxDuration;
  60. _descriptor = new TFactory().CreateDescriptor();
  61. }
  62. /// <summary>
  63. /// What to do on deserialization.
  64. /// </summary>
  65. /// <param name="context">The context.</param>
  66. [OnDeserialized]
  67. public void OnDeserialized(StreamingContext context)
  68. {
  69. _descriptor = new TFactory().CreateDescriptor();
  70. }
  71. /// <summary>
  72. /// Is the UDSO internal state empty?
  73. /// </summary>
  74. public override bool IsEmpty
  75. {
  76. get { return _currentRuns == null && _previousRuns == null; }
  77. }
  78. /// <summary>
  79. /// Processes an incoming event.
  80. /// </summary>
  81. /// <param name="inputEvent">The incoming event.</param>
  82. /// <returns>The IEnumerable of registers corresponding to detected patterns.</returns>
  83. public override IEnumerable<TRegister> ProcessEvent(PointEvent<TInput> inputEvent)
  84. {
  85. // Process only the appropriate events
  86. if (!_descriptor.CtiVisibility && inputEvent.EventKind == EventKind.Cti)
  87. {
  88. yield break;
  89. }
  90. // Check if time has advanced; if yes, update _previousRuns and reset _currentRuns
  91. if (_startTime.HasValue && _startTime.Value < inputEvent.StartTime)
  92. {
  93. _previousRuns = _currentRuns;
  94. _currentRuns = null;
  95. }
  96. _startTime = inputEvent.StartTime;
  97. bool runsEnded = true;
  98. // Process this event: create new runs from existing runs associated with the previous timestamp
  99. if (_previousRuns != null)
  100. {
  101. foreach (Run oldRun in _previousRuns)
  102. {
  103. IEnumerable<Run> newRuns = ApplyTransition(inputEvent.StartTime, inputEvent, oldRun);
  104. foreach (var newRun in newRuns)
  105. {
  106. if (_currentRuns == null)
  107. _currentRuns = new LinkedList<Run>();
  108. _currentRuns.AddLast(newRun);
  109. // If we have reached a final state, include the register value in result.
  110. if (_descriptor.IsFinalState(newRun.State))
  111. {
  112. yield return newRun.Register;
  113. }
  114. else
  115. {
  116. runsEnded = false;
  117. }
  118. }
  119. }
  120. }
  121. if (_descriptor.AllowOverlappingInstances || runsEnded)
  122. {
  123. // Create new runs starting from this event
  124. Run run = new Run(_descriptor.StartState, _descriptor.DefaultRegister, inputEvent.StartTime);
  125. IEnumerable<Run> newRuns = ApplyTransition(inputEvent.StartTime, inputEvent, run);
  126. foreach (var newRun in newRuns)
  127. {
  128. if (_currentRuns == null)
  129. _currentRuns = new LinkedList<Run>();
  130. _currentRuns.AddLast(newRun);
  131. // If we have reached a final state, include the register value in result.
  132. if (_descriptor.IsFinalState(newRun.State))
  133. yield return newRun.Register;
  134. }
  135. }
  136. }
  137. /// <summary>
  138. /// Applies a transition on an incoming event.
  139. /// </summary>
  140. /// <param name="startTime">The event start time.</param>
  141. /// <param name="inputEvent">The input event.</param>
  142. /// <param name="previousRun">The previous partial match.</param>
  143. /// <returns>The set of new (partial) matches after applying the transition.</returns>
  144. private IEnumerable<Run> ApplyTransition(DateTimeOffset startTime, PointEvent<TInput> inputEvent, Run previousRun)
  145. {
  146. if (previousRun.PatternStartTime.Add(_patternMaxDuration) <= startTime)
  147. {
  148. yield break;
  149. }
  150. int fromState = previousRun.State;
  151. List<int> toStates = _descriptor.GetToStates(fromState);
  152. foreach (int toState in toStates)
  153. {
  154. TRegister targetRegister;
  155. if (_descriptor.TryApplyTransition(inputEvent, fromState, toState, previousRun.Register, out targetRegister))
  156. {
  157. Run newRun = new Run(toState, targetRegister, previousRun.PatternStartTime);
  158. yield return newRun;
  159. }
  160. }
  161. }
  162. /// <summary>
  163. /// Data structure defining a (possibly partial) pattern match.
  164. /// </summary>
  165. [DataContract]
  166. private struct Run
  167. {
  168. /// <summary>
  169. /// The current register value.
  170. /// </summary>
  171. [DataMember]
  172. private readonly TRegister _register;
  173. /// <summary>
  174. /// The current state.
  175. /// </summary>
  176. [DataMember]
  177. private readonly int _state;
  178. /// <summary>
  179. /// The start time of the pattern.
  180. /// </summary>
  181. [DataMember]
  182. private readonly DateTimeOffset _patternStartTime;
  183. /// <summary>
  184. /// Initializes a new partial pattern match.
  185. /// </summary>
  186. /// <param name="state"></param>
  187. /// <param name="register"></param>
  188. /// <param name="patternStartTime"></param>
  189. internal Run(int state, TRegister register, DateTimeOffset patternStartTime)
  190. {
  191. this._register = register;
  192. this._state = state;
  193. this._patternStartTime = patternStartTime;
  194. }
  195. /// <summary>
  196. /// Gets the current register value.
  197. /// </summary>
  198. public TRegister Register
  199. {
  200. get { return _register; }
  201. }
  202. /// <summary>
  203. /// Gets the current state.
  204. /// </summary>
  205. public int State
  206. {
  207. get { return _state; }
  208. }
  209. /// <summary>
  210. /// Gets the pattern start time.
  211. /// </summary>
  212. public DateTimeOffset PatternStartTime
  213. {
  214. get { return _patternStartTime; }
  215. }
  216. }
  217. }
  218. }