public SequenceData Operate(IList <ProcParam <SequenceProcEnv> > args, SequenceProcEnv env)
        {
            var operand  = args[0] as SequenceMultiSelectParameter;
            var sep      = args[1] as StringParameter;
            var useEmpty = args[2] as BooleanParameter;
            List <SequenceData> sequences = new List <SequenceData>();

            sequences.Add(env.SelectedSequence);
            sequences.AddRange(operand.Value);
            ICSLabelSequence ret = new ICSLabelSequence();
            var timeList         = TimeSeriesValuesCalculation.MergeTimeList(sequences.Select(p => p.Values)).ToList();

            if (timeList.Count != 0)
            {
                var lastTime = timeList.Last();
                foreach (var time in timeList)
                {
                    if (time < lastTime)
                    {
                        StringBuilder tmp   = new StringBuilder();
                        bool          empty = true;
                        foreach (var sequence in sequences)
                        {
                            var label = sequence.GetLabelAt(time);
                            if (label != "" || useEmpty.Value)
                            {
                                if (!empty)
                                {
                                    tmp.Append(sep.Value);
                                }
                                tmp.Append(label);
                                empty = false;
                            }
                        }
                        ret.SetLabel(time, lastTime, tmp.ToString());
                    }
                }
            }
            return(SequenceData.FromLabelSequence(ret, PathEx.GiveName("Product", sequences.Select(p => p.Title))));
        }
        public static ICSLabelSequence ToLabelByCondition(IList <SequenceData> sequences, Func <decimal?[], int> cond)
        {
            var timeList  = TimeSeriesValuesCalculation.MergeTimeList(sequences.Select(p => p.Values)).ToList();
            var ret       = new ICSLabelSequence();
            int prevKey   = 0;
            int prevIndex = -1;

            for (int key = 1; key < timeList.Count - 1; key++)
            {
                var values = sequences.Select(s => s.Values[timeList[key]][s.Borders.TargetColumnIndex]).ToArray();
                int index  = cond(values);
                if (prevIndex != index)
                {
                    if (prevIndex >= 0 && prevIndex < sequences.Count)
                    {
                        ret.SetLabel(timeList[prevKey], timeList[key], sequences[prevIndex].Title);
                    }
                    else
                    {
                        ret.SetLabel(timeList[prevKey], timeList[key], "");
                    }
                    prevKey   = key;
                    prevIndex = index;
                }
            }
            if (timeList.Count >= 1)
            {
                if (prevIndex >= 0 && prevIndex < sequences.Count)
                {
                    ret.SetLabel(timeList[prevKey], timeList[timeList.Count - 1], sequences[prevIndex].Title);
                }
                else
                {
                    ret.SetLabel(timeList[prevKey], timeList[timeList.Count - 1], "");
                }
            }
            return(ret);
        }
        public SequenceData Operate(IList <ProcParam <SequenceProcEnv> > args, SequenceProcEnv env)
        {
            var mode = args[0] as SingleSelectParameter;
            var threshold = args[1] as NumberParameter;
            var correct = args[2] as SequenceSingleSelectParameter;
            var correctSequence = correct.Value;
            ICSLabelSequence ret = new ICSLabelSequence();
            decimal          correctCount = 0, obtainCount = 0, matchCount = 0;

            switch (mode.Value)
            {
            case 0:
                var common = TimeSeriesValuesCalculation.MergeTimeList(new[] { env.SelectedSequence.Values, correctSequence.Values }).ToList();
                for (int i = 0; i < common.Count - 1; i++)
                {
                    string o = env.SelectedSequence.GetLabelAt(common[i]);
                    string c = correctSequence.GetLabelAt(common[i]);
                    if (o == "" && c == "")
                    {
                        continue;
                    }
                    decimal interval = common[i + 1] - common[i];
                    if (o != "")
                    {
                        obtainCount += interval;
                    }
                    if (c != "")
                    {
                        correctCount += interval;
                    }
                    if (o == c)
                    {
                        matchCount += interval;
                    }
                    ret.SetLabel(common[i], common[i + 1], o == c ? "Match" : o == "" ? "False Negative" : c == "" ? "False Positive" : "Mismatch");
                }
                break;

            case 1:
            case 2:
                SequenceData main, sub;
                if (mode.Value == 1)
                {
                    main = correctSequence;
                    sub  = env.SelectedSequence;
                }
                else
                {
                    main = env.SelectedSequence;
                    sub  = correctSequence;
                }
                var subLabel = sub.GetLabelSequence();
                foreach (var label in main.GetLabelSequence().EnumerateLabels())
                {
                    decimal denom = label.Duration;
                    if (label.LabelText != "")
                    {
                        var     clip  = subLabel.ClipLabelsBetween(label.BeginTime, label.EndTime, ICSLabelSequence.ClipLabelsMode.CutBorder);
                        decimal numer = clip.Where(l => l.LabelText == label.LabelText).Select(l => l.Duration).Sum();
                        if (numer >= denom * threshold.Value)
                        {
                            matchCount++;
                            ret.SetLabel(label.ChangeText("Match"));
                        }
                        else
                        {
                            ret.SetLabel(label.ChangeText(mode.Value == 1 ? "False Negative" : "False Positive"));
                        }
                        obtainCount++;
                        correctCount++;
                    }
                    else
                    {
                        var clip      = subLabel.ClipLabelsBetween(label.BeginTime, label.EndTime, ICSLabelSequence.ClipLabelsMode.CutBorder);
                        var missClip  = clip.Where(l => l.LabelText != "").ToList();
                        var missCount = missClip.Count;
                        if (mode.Value == 1)
                        {
                            obtainCount += missCount;
                        }
                        else
                        {
                            correctCount += missCount;
                        }
                        foreach (var m in missClip)
                        {
                            ret.SetLabel(m.ChangeText(mode.Value == 1 ? "False Positive" : "False Negative"));
                        }
                    }
                }
                break;
            }
            return(SequenceData.FromLabelSequence(ret, PathEx.GiveName("PrecisionRecall", env.SelectedSequence.Title, correctSequence.Title)));
        }