@@ -9,3 +9,128 @@ fn floyd_works() {
99fn brent_works ( ) {
1010 assert_eq ! ( brent( -10 , |x| ( x + 5 ) % 6 + 3 ) , ( 3 , 6 , 2 ) ) ;
1111}
12+
13+ #[ test]
14+ fn floyd_partial_works ( ) {
15+ let ( lam, elem, mu_tilde) = floyd_partial ( -10 , |x| ( x + 5 ) % 6 + 3 ) ;
16+ // Check that we get the correct cycle length
17+ assert_eq ! ( lam, 3 ) ;
18+ // Check that elem is in the cycle (cycle is 6, 8, 4)
19+ assert ! ( [ 4 , 6 , 8 ] . contains( & elem) ) ;
20+ // Check that mu_tilde is an upper bound: mu <= mu_tilde < mu + lam
21+ // We know mu = 2 from the full algorithm
22+ assert ! ( 2 <= mu_tilde) ;
23+ assert ! ( mu_tilde < 2 + 3 ) ;
24+ }
25+
26+ #[ test]
27+ fn brent_partial_works ( ) {
28+ let ( lam, elem, mu_tilde) = brent_partial ( -10 , |x| ( x + 5 ) % 6 + 3 ) ;
29+ // Check that we get the correct cycle length
30+ assert_eq ! ( lam, 3 ) ;
31+ // Check that elem is in the cycle (cycle is 6, 8, 4)
32+ assert ! ( [ 4 , 6 , 8 ] . contains( & elem) ) ;
33+ // Check that mu_tilde is an upper bound: mu <= mu_tilde
34+ // We know mu = 2 from the full algorithm
35+ assert ! ( 2 <= mu_tilde) ;
36+ }
37+
38+ #[ test]
39+ fn partial_functions_match_full_functions ( ) {
40+ // Test that partial functions return the same lambda as full functions
41+ let f = |x| ( x + 5 ) % 6 + 3 ;
42+
43+ let ( lam_floyd, elem_floyd, mu_floyd) = floyd ( -10 , f) ;
44+ let ( lam_floyd_partial, elem_floyd_partial, mu_tilde_floyd) = floyd_partial ( -10 , f) ;
45+
46+ let ( lam_brent, elem_brent, mu_brent) = brent ( -10 , f) ;
47+ let ( lam_brent_partial, elem_brent_partial, mu_tilde_brent) = brent_partial ( -10 , f) ;
48+
49+ // Lambda should be the same
50+ assert_eq ! ( lam_floyd, lam_floyd_partial) ;
51+ assert_eq ! ( lam_brent, lam_brent_partial) ;
52+ assert_eq ! ( lam_floyd, lam_brent) ;
53+
54+ // Elements should be in the cycle
55+ assert ! ( [ 4 , 6 , 8 ] . contains( & elem_floyd) ) ;
56+ assert ! ( [ 4 , 6 , 8 ] . contains( & elem_floyd_partial) ) ;
57+ assert ! ( [ 4 , 6 , 8 ] . contains( & elem_brent) ) ;
58+ assert ! ( [ 4 , 6 , 8 ] . contains( & elem_brent_partial) ) ;
59+
60+ // Mu values from full algorithms should be the same
61+ assert_eq ! ( mu_floyd, mu_brent) ;
62+
63+ // Mu_tilde should be valid upper bounds
64+ assert ! ( mu_floyd <= mu_tilde_floyd) ;
65+ assert ! ( mu_tilde_floyd < mu_floyd + lam_floyd) ;
66+ assert ! ( mu_brent <= mu_tilde_brent) ;
67+ }
68+
69+ #[ test]
70+ fn test_longer_cycle ( ) {
71+ // Test with a longer cycle: sequence from 0 to 99, then cycles
72+ let f = |x : i32 | ( x + 1 ) % 100 ;
73+
74+ let ( lam_floyd, elem_floyd, mu_floyd) = floyd ( 0 , f) ;
75+ let ( lam_floyd_partial, elem_floyd_partial, mu_tilde_floyd) = floyd_partial ( 0 , f) ;
76+
77+ let ( lam_brent, elem_brent, mu_brent) = brent ( 0 , f) ;
78+ let ( lam_brent_partial, elem_brent_partial, mu_tilde_brent) = brent_partial ( 0 , f) ;
79+
80+ // Cycle length should be 100 (0, 1, 2, ..., 99, 0, ...)
81+ assert_eq ! ( lam_floyd, 100 ) ;
82+ assert_eq ! ( lam_floyd_partial, 100 ) ;
83+ assert_eq ! ( lam_brent, 100 ) ;
84+ assert_eq ! ( lam_brent_partial, 100 ) ;
85+
86+ // Mu should be 0 (cycle starts immediately)
87+ assert_eq ! ( mu_floyd, 0 ) ;
88+ assert_eq ! ( mu_brent, 0 ) ;
89+
90+ // Elements should be in the cycle
91+ assert ! ( ( 0 ..100 ) . contains( & elem_floyd) ) ;
92+ assert ! ( ( 0 ..100 ) . contains( & elem_floyd_partial) ) ;
93+ assert ! ( ( 0 ..100 ) . contains( & elem_brent) ) ;
94+ assert ! ( ( 0 ..100 ) . contains( & elem_brent_partial) ) ;
95+
96+ // Mu_tilde should be valid upper bounds
97+ assert ! ( mu_floyd <= mu_tilde_floyd) ;
98+ assert ! ( mu_tilde_floyd < mu_floyd + lam_floyd) ;
99+ assert ! ( mu_brent <= mu_tilde_brent) ;
100+ }
101+
102+ #[ test]
103+ fn test_short_cycle_large_mu ( ) {
104+ // Sequence starting from -100, adds 1 each step,
105+ // but when value reaches 10, it resets to 0
106+ // This creates: -100, -99, ..., -1, 0, 1, ..., 9, 10, 0, 1, ..., 9, 10, 0, ...
107+ // mu = 100 (steps to reach 0, which is the start of the cycle), lambda = 11 (0 to 10 inclusive)
108+ let f = |x : i32 | if x == 10 { 0 } else { x + 1 } ;
109+
110+ let ( lam_floyd, elem_floyd, mu_floyd) = floyd ( -100 , f) ;
111+ let ( lam_floyd_partial, elem_floyd_partial, mu_tilde_floyd) = floyd_partial ( -100 , f) ;
112+
113+ let ( lam_brent, elem_brent, mu_brent) = brent ( -100 , f) ;
114+ let ( lam_brent_partial, elem_brent_partial, mu_tilde_brent) = brent_partial ( -100 , f) ;
115+
116+ // Cycle length should be 11 (0, 1, 2, ..., 9, 10, 0, ...)
117+ assert_eq ! ( lam_floyd, 11 ) ;
118+ assert_eq ! ( lam_floyd_partial, 11 ) ;
119+ assert_eq ! ( lam_brent, 11 ) ;
120+ assert_eq ! ( lam_brent_partial, 11 ) ;
121+
122+ // Mu should be 100 (it takes 100 steps to get from -100 to 0, then cycles)
123+ assert_eq ! ( mu_floyd, 100 ) ;
124+ assert_eq ! ( mu_brent, 100 ) ;
125+
126+ // Elements should be in the cycle (0 to 10)
127+ assert ! ( ( 0 ..=10 ) . contains( & elem_floyd) ) ;
128+ assert ! ( ( 0 ..=10 ) . contains( & elem_floyd_partial) ) ;
129+ assert ! ( ( 0 ..=10 ) . contains( & elem_brent) ) ;
130+ assert ! ( ( 0 ..=10 ) . contains( & elem_brent_partial) ) ;
131+
132+ // Mu_tilde should be valid upper bounds
133+ assert ! ( mu_floyd <= mu_tilde_floyd) ;
134+ assert ! ( mu_tilde_floyd < mu_floyd + lam_floyd) ;
135+ assert ! ( mu_brent <= mu_tilde_brent) ;
136+ }
0 commit comments