예제 #1
0
        private void buildEnvelopes()
        {
            _envelope.process(this.BaseValues, this.Length);

            // also create another arrays for keeping sorted envelope
            for (int i = 0; i < this.Length; i++)
            {
                int o = _sortingBuffer[i].Index;

                this.Ordered[i] = o;
                this.OrderedValues[i].set(this.BaseValues[o]);
                this.OrderedUpperEnvelope[i].set(_envelope.Upper[o]);
                this.OrderedLowerEnvelope[i].set(_envelope.Lower[o]);
            }
        }
        public DTWResult warp(Query query)
        {
            //prepare/reset knn search:
            jumpsize = query.Length;
            wk       = 0;
            _wk      = 0;
            lastloc  = 0;
            for (int tmpk = 0; tmpk < bestk; tmpk++)
            {
                _kvec[tmpk] = double.PositiveInfinity;
                _lvec[tmpk] = 0;
            }


            double bsf;   // best-so-far

            MDVector[] t; // data array

            MDVector[] tz, cb, cb1, cb2;

            MDVector d;
            int      i, j;
            int      dataIndex = 0;
            int      matchIndex = 0;
            int      kim = 0, keogh = 0, keogh2 = 0;


            double distance = 0;

            // prepare query object
            query.process();

            cb  = new MDVector[query.Length];
            cb1 = new MDVector[query.Length];
            cb2 = new MDVector[query.Length];

            t = new MDVector[query.Length * 2];
            for (i = 0; i < t.Length; i++)
            {
                t[i] = new MDVector(_dimensions);
            }

            tz = new MDVector[query.Length];
            for (i = 0; i < tz.Length; i++)
            {
                tz[i] = new MDVector(_dimensions);
            }

            // Initialize the cummulative lower bound
            for (i = 0; i < query.Length; i++)
            {
                cb[i] = new MDVector(_dimensions);
                cb[i].set(0);

                cb1[i] = new MDVector(_dimensions);
                cb1[i].set(0);

                cb2[i] = new MDVector(_dimensions);
                cb2[i].set(0);
            }

            // Initialize
            bsf = double.PositiveInfinity;
            i   = 0; /// current index of the data in current chunk of size EPOCH
            j   = 0; /// the starting index of the data in the circular array, t
            ex.set(0);
            ex2.set(0);

            bool done = false;
            int  it = 0, ep = 0, k = 0;
            int  I; /// the starting index of the data in current chunk of size EPOCH

            LemireEnvelope lemireEnvelope = new LemireEnvelope(EPOCH, query.WarpingWindow, _dimensions);

            DTWCalculator dtwCalculator = new DTWCalculator(query.Length, query.WarpingWindow, _dimensions);

            while (!done)
            {
                // Read first query.Length-1 points
                ep = 0;
                if (it == 0)
                {
                    for (k = 0; k < query.Length - 1; k++)
                    {
                        if (dataIndex < _data.Count)
                        {
                            buffer[k].set(_data[dataIndex++]);
                        }
                    }
                }
                else
                {
                    for (k = 0; k < query.Length - 1; k++)
                    {
                        buffer[k].set(buffer[EPOCH - query.Length + 1 + k]);
                    }
                }

                // Read buffer of size EPOCH or when all data has been read.
                ep = query.Length - 1;
                while (ep < EPOCH)
                {
                    if (dataIndex >= _data.Count)
                    {
                        break;
                    }
                    buffer[ep].set(_data[dataIndex++]);
                    ep++;
                }

                // Data are read in chunk of size EPOCH.
                // When there is nothing to read, the loop is end.
                if (ep <= query.Length - 1)
                {
                    done = true;
                }
                else
                {
                    lemireEnvelope.process(buffer, ep);

                    /// Do main task here..
                    ex.set(0);
                    ex2.set(0);
                    for (i = 0; i < ep; i++)
                    {
                        // A bunch of data has been read and pick one of them at a time to use
                        d = buffer[i];

                        // Calcualte sum and sum square
                        ex     = MDVector.add(ex, d, ex);
                        result = MDVector.multiply(d, d, result);
                        ex2    = MDVector.add(ex2, result, ex2);

                        // t is a circular array for keeping current data
                        t[i % query.Length].set(d);

                        // double the size for avoiding using modulo "%" operator
                        t[(i % query.Length) + query.Length].set(d);

                        // Start the task when there are more than query.Length-1 points in the current chunk
                        if (i >= query.Length - 1)
                        {
                            mean  = MDVector.divide(ex, query.Length, mean);
                            std   = MDVector.divide(ex2, query.Length, std);
                            mean2 = MDVector.multiply(mean, mean, mean2);
                            std   = MDVector.subtract(std, mean2, std);
                            std.sqrt();

                            // compute the start location of the data in the current circular array, t
                            j = (i + 1) % query.Length;
                            // the start location of the data in the current chunk
                            I = i - (query.Length - 1);

                            // Use a constant lower bound to prune the obvious subsequence
                            lb_kim = _kimLb.hierarchy(t, query.BaseValues, j, query.Length, mean, std, bsf);

                            if (lb_kim < bsf)
                            {
                                // Use a linear time lower bound to prune; z_normalization of t will be computed on the fly.
                                // uo, lo are envelop of the query.
                                lb_k = _keoghLb.cumulative(query.Ordered, t, query.OrderedUpperEnvelope, query.OrderedLowerEnvelope, cb1, j, query.Length, mean, std, bsf);

                                if (lb_k < bsf)
                                {
                                    // Take another linear time to compute z_normalization of t.
                                    // Note that for better optimization, this can merge to the previous function.
                                    for (k = 0; k < query.Length; k++)
                                    {
                                        tz[k] = Utilities.normalize(t[(k + j)], mean, std, tz[k]);
                                    }

                                    // Use another lb_keogh to prune
                                    // qo is the sorted query. tz is unsorted z_normalized data.
                                    // l_buff, u_buff are big envelop for all data in this chunk

                                    lb_k2 = _keoghLb.dataCumulative(query.Ordered, query.OrderedValues, cb2, lemireEnvelope.Lower, lemireEnvelope.Upper, I, query.Length, mean, std, bsf);

                                    if (lb_k2 < bsf)
                                    {
                                        // Choose better lower bound between lb_keogh and lb_keogh2 to be used in early abandoning DTW
                                        // Note that cb and cb2 will be cumulative summed here.
                                        if (lb_k > lb_k2)
                                        {
                                            cb[query.Length - 1].set(cb1[query.Length - 1]);
                                            for (k = query.Length - 2; k >= 0; k--)
                                            {
                                                cb[k] = MDVector.add(cb[k + 1], cb1[k], cb[k]);
                                            }
                                        }
                                        else
                                        {
                                            cb[query.Length - 1].set(cb2[query.Length - 1]);
                                            for (k = query.Length - 2; k >= 0; k--)
                                            {
                                                cb[k] = MDVector.add(cb[k + 1], cb2[k], cb[k]);
                                            }
                                        }

                                        // Compute DTW and early abandoning if possible
                                        distance = dtwCalculator.distance(tz, query.BaseValues, cb, bsf);

                                        if (distance < bsf)
                                        {
                                            // Update bsf
                                            // loc is the real starting location of the nearest neighbor in the file

                                            matchIndex = (it) * (EPOCH - query.Length + 1) + i - query.Length + 1;
                                            if (bestk == 1)
                                            {
                                                _kvec[0] = bsf;
                                                _lvec[0] = matchIndex;
                                                bsf      = distance;
                                            }
                                            else
                                            {
                                                bsf = ucr_set_knn(distance, matchIndex);
                                            }
                                        }
                                    }
                                    else
                                    {
                                        keogh2++;
                                    }
                                }
                                else
                                {
                                    keogh++;
                                }
                            }
                            else
                            {
                                kim++;
                            }

                            // Reduce absolute points from sum and sum square
                            ex     = MDVector.subtract(ex, t[j], ex);
                            result = MDVector.multiply(t[j], t[j], result);
                            ex2    = MDVector.subtract(ex2, result, ex2);
                        }
                    }

                    // If the size of last chunk is less than EPOCH, then no more data and terminate.
                    if (ep < EPOCH)
                    {
                        done = true;
                    }
                    else
                    {
                        it++;
                    }
                }
            }
            Array.Sort(_kvec, _lvec);
            return(new DTWResult()
            {
                Locations = _lvec, Distances = _kvec
            });
        }