@@ -1778,3 +1778,173 @@ def test_process_isconstant_1d_default():
17781778 T_subseq_isconstant_comp = core .process_isconstant (T , m , T_subseq_isconstant = None )
17791779
17801780 npt .assert_array_equal (T_subseq_isconstant_ref , T_subseq_isconstant_comp )
1781+
1782+
1783+ def test_update_incremental_PI_egressFalse ():
1784+ # This tests the function `core._update_incremental_PI`
1785+ # when `egress` is False, meaning new data point is being
1786+ # appended to the historical data.
1787+ T = np .random .rand (64 )
1788+ t = np .random .rand () # new datapoint
1789+ T_new = np .append (T , t )
1790+
1791+ m = 3
1792+ excl_zone = int (np .ceil (m / config .STUMPY_EXCL_ZONE_DENOM ))
1793+
1794+ for k in range (1 , 4 ):
1795+ # ref
1796+ mp_ref = naive .stump (T_new , m , row_wise = True , k = k )
1797+ P_ref = mp_ref [:, :k ].astype (np .float64 )
1798+ I_ref = mp_ref [:, k : 2 * k ].astype (np .int64 )
1799+
1800+ # comp
1801+ mp = naive .stump (T , m , row_wise = True , k = k )
1802+ P_comp = mp [:, :k ].astype (np .float64 )
1803+ I_comp = mp [:, k : 2 * k ].astype (np .int64 )
1804+
1805+ # Because of the new data point, the length of matrix profile
1806+ # and matrix profile indices should be increased by one.
1807+ P_comp = np .pad (
1808+ P_comp ,
1809+ [(0 , 1 ), (0 , 0 )],
1810+ mode = "constant" ,
1811+ constant_values = np .inf ,
1812+ )
1813+ I_comp = np .pad (
1814+ I_comp ,
1815+ [(0 , 1 ), (0 , 0 )],
1816+ mode = "constant" ,
1817+ constant_values = - 1 ,
1818+ )
1819+
1820+ D = core .mass (T_new [- m :], T_new )
1821+ core ._update_incremental_PI (D , P_comp , I_comp , excl_zone , n_appended = 0 )
1822+
1823+ # assertion
1824+ npt .assert_almost_equal (P_ref , P_comp )
1825+ npt .assert_almost_equal (I_ref , I_comp )
1826+
1827+
1828+ def test_update_incremental_PI_egressTrue ():
1829+ T = np .random .rand (64 )
1830+ t = np .random .rand () # new data point
1831+ m = 3
1832+ excl_zone = int (np .ceil (m / config .STUMPY_EXCL_ZONE_DENOM ))
1833+
1834+ for k in range (1 , 4 ):
1835+ # ref
1836+ # In egress=True mode, a new data point, t, is being appended
1837+ # to the historical data, T, while the oldest data point is
1838+ # being removed. Therefore, the first subsequence in T
1839+ # and the last subsequence does not get a chance to meet each
1840+ # other. Therefore, we need to exclude that distance.
1841+
1842+ T_with_t = np .append (T , t )
1843+ D = naive .distance_matrix (T_with_t , T_with_t , m )
1844+ D [- 1 , 0 ] = np .inf
1845+ D [0 , - 1 ] = np .inf
1846+
1847+ l = len (T_with_t ) - m + 1
1848+ P = np .empty ((l , k ), dtype = np .float64 )
1849+ I = np .empty ((l , k ), dtype = np .int64 )
1850+ for i in range (l ):
1851+ core .apply_exclusion_zone (D [i ], i , excl_zone , np .inf )
1852+ IDX = np .argsort (D [i ], kind = "mergesort" )[:k ]
1853+ I [i ] = IDX
1854+ P [i ] = D [i , IDX ]
1855+
1856+ P_ref = P [1 :].copy ()
1857+ I_ref = I [1 :].copy ()
1858+
1859+ # comp
1860+ mp = naive .stump (T , m , row_wise = True , k = k )
1861+ P_comp = mp [:, :k ].astype (np .float64 )
1862+ I_comp = mp [:, k : 2 * k ].astype (np .int64 )
1863+
1864+ P_comp [:- 1 ] = P_comp [1 :]
1865+ P_comp [- 1 ] = np .inf
1866+ I_comp [:- 1 ] = I_comp [1 :]
1867+ I_comp [- 1 ] = - 1
1868+
1869+ T_new = np .append (T [1 :], t )
1870+ D = core .mass (T_new [- m :], T_new )
1871+ core ._update_incremental_PI (D , P_comp , I_comp , excl_zone , n_appended = 1 )
1872+
1873+ # assertion
1874+ npt .assert_almost_equal (P_ref , P_comp )
1875+ npt .assert_almost_equal (I_ref , I_comp )
1876+
1877+
1878+ def test_update_incremental_PI_egressTrue_MemoryCheck ():
1879+ # This test function is to ensure that the function
1880+ # `core._update_incremental_PI` does not forget the
1881+ # nearest neighbors that were pointing to those old data
1882+ # points that are removed in the `egress=True` mode.
1883+ # This can be tested by inserting the same subsequence, s, in the beginning,
1884+ # middle, and end of the time series. This is to allow us to know which
1885+ # neighbor is the nearest neighbor to each of those three subsequences.
1886+
1887+ # In the `egress=True` mode, the first element of the time series is removed and
1888+ # a new data point is appended. However, the updated matrix profile index for the
1889+ # middle subsequence `s` should still refer to the first subsequence in
1890+ # the historical data.
1891+ seed = 0
1892+ np .random .seed (seed )
1893+
1894+ T = np .random .rand (64 )
1895+ m = 3
1896+ excl_zone = int (np .ceil (m / config .STUMPY_EXCL_ZONE_DENOM ))
1897+
1898+ s = np .random .rand (m )
1899+ T [:m ] = s
1900+ T [30 : 30 + m ] = s
1901+ T [- m :] = s
1902+
1903+ t = np .random .rand () # new data point
1904+ T_with_t = np .append (T , t )
1905+
1906+ # In egress=True mode, a new data point, t, is being appended
1907+ # to the historical data, T, while the oldest data point is
1908+ # being removed. Therefore, the first subsequence in T
1909+ # and the last subsequence does not get a chance to meet each
1910+ # other. Therefore, their pairwise distances should be excluded
1911+ # from the distance matrix.
1912+ D = naive .distance_matrix (T_with_t , T_with_t , m )
1913+ D [- 1 , 0 ] = np .inf
1914+ D [0 , - 1 ] = np .inf
1915+
1916+ l = len (T_with_t ) - m + 1
1917+ for i in range (l ):
1918+ core .apply_exclusion_zone (D [i ], i , excl_zone , np .inf )
1919+
1920+ T_new = np .append (T [1 :], t )
1921+ dist_profile = naive .distance_profile (T_new [- m :], T_new , m )
1922+ core .apply_exclusion_zone (dist_profile , len (dist_profile ) - 1 , excl_zone , np .inf )
1923+
1924+ for k in range (1 , 4 ):
1925+ # ref
1926+ P = np .empty ((l , k ), dtype = np .float64 )
1927+ I = np .empty ((l , k ), dtype = np .int64 )
1928+ for i in range (l ):
1929+ IDX = np .argsort (D [i ], kind = "mergesort" )[:k ]
1930+ I [i ] = IDX
1931+ P [i ] = D [i , IDX ]
1932+
1933+ P_ref = P [1 :].copy ()
1934+ I_ref = I [1 :].copy ()
1935+
1936+ # comp
1937+ mp = naive .stump (T , m , row_wise = True , k = k )
1938+ P_comp = mp [:, :k ].astype (np .float64 )
1939+ I_comp = mp [:, k : 2 * k ].astype (np .int64 )
1940+
1941+ P_comp [:- 1 ] = P_comp [1 :]
1942+ P_comp [- 1 ] = np .inf
1943+ I_comp [:- 1 ] = I_comp [1 :]
1944+ I_comp [- 1 ] = - 1
1945+ core ._update_incremental_PI (
1946+ dist_profile , P_comp , I_comp , excl_zone , n_appended = 1
1947+ )
1948+
1949+ npt .assert_almost_equal (P_ref , P_comp )
1950+ npt .assert_almost_equal (I_ref , I_comp )
0 commit comments