@@ -261,19 +261,30 @@ def test_polar_express_16steps_almost_orthogonal(self, size):
261261 out = muon_utils .newton_schulz (x , steps = 16 , coefficient_type = "polar_express" )
262262 assert_close_to_orthogonal (out , diag_atol = 1e-5 , off_diag_atol = 1e-5 )
263263
264- @parameterized .parameters (
265- (511 , 513 ),
266- (511 , 257 ),
267- (257 , 513 ),
264+ @parameterized .product (
265+ shape = [(511 , 513 ), (511 , 257 ), (257 , 513 ), (2 , 31 , 17 )],
266+ steps = [0 , 1 , 7 , 8 , 9 , 10 , 16 ],
268267 )
269- def test_polar_express_9steps_close_to_reference (self , dim1 , dim2 ):
270- x = torch .randn (dim1 , dim2 , device = self .device , dtype = torch .float32 )
271- out_pe9 = muon_utils .newton_schulz (x , steps = 9 , coefficient_type = "polar_express" )
268+ def test_polar_express_close_to_reference (self , shape , steps ):
269+ x = torch .randn (* shape , device = self .device , dtype = torch .float32 )
270+ out_pe = muon_utils .newton_schulz (x , steps = steps , coefficient_type = "polar_express" )
272271
273- coeff = deepcopy (muon_utils ._COEFFICIENT_SETS ["polar_express" ])
274- coeff .append (coeff [- 1 ])
272+ coeff = list (
273+ muon_utils .get_coefficient_iterator (
274+ steps , muon_utils ._COEFFICIENT_SETS ["polar_express" ], mode = "repeat_penultimate"
275+ )
276+ )
275277 out_ref = newton_schulz_ref (x , coefficient_sets = coeff )
276- torch .testing .assert_close (out_pe9 , out_ref , atol = 2e-6 , rtol = 1e-7 )
278+ torch .testing .assert_close (out_pe , out_ref , atol = 2e-6 , rtol = 1e-7 )
279+
280+ def test_polar_express_guarded_coefficient_matches_rounded_safety_factor (self ):
281+ coeff = muon_utils ._COEFFICIENT_SETS ["polar_express" ]
282+ a , b , c = coeff [- 1 ]
283+ expected = torch .tensor (
284+ (round (a / 1.01 , 4 ), round (b / 1.01 ** 3 , 4 ), round (c / 1.01 ** 5 , 4 )), dtype = torch .float32
285+ )
286+ actual = torch .tensor (coeff [- 2 ], dtype = torch .float32 )
287+ torch .testing .assert_close (actual , expected , atol = 0 , rtol = 0 )
277288
278289 @parameterized .parameters (
279290 (511 , 513 ),
@@ -428,6 +439,23 @@ def test_get_coefficient_iterator_empty_raises_value_error(self) -> None:
428439 with self .assertRaisesRegex (ValueError , "must be non-empty" ):
429440 list (muon_utils .get_coefficient_iterator (5 , []))
430441
442+ @parameterized .named_parameters (
443+ ("zero_steps" , 0 , []),
444+ ("truncated_prefix" , 1 , [0 ]),
445+ ("no_repetition" , 2 , [0 , 2 ]),
446+ ("full_schedule" , 3 , [0 , 1 , 2 ]),
447+ ("one_extra_step" , 4 , [0 , 1 , 1 , 2 ]),
448+ ("several_extra_steps" , 7 , [0 , 1 , 1 , 1 , 1 , 1 , 2 ]),
449+ )
450+ def test_get_coefficient_iterator_repeat_penultimate (self , steps , expected_indices ):
451+ coeff = [(1.0 , 2.0 , 3.0 ), (4.0 , 5.0 , 6.0 ), (7.0 , 8.0 , 9.0 )]
452+ actual = list (muon_utils .get_coefficient_iterator (steps , coeff , mode = "repeat_penultimate" ))
453+ self .assertEqual (actual , [coeff [index ] for index in expected_indices ])
454+
455+ def test_get_coefficient_iterator_repeat_penultimate_requires_two_coefficients (self ):
456+ with self .assertRaisesRegex (ValueError , "requires at least two" ):
457+ muon_utils .get_coefficient_iterator (5 , [(1.0 , 2.0 , 3.0 )], mode = "repeat_penultimate" )
458+
431459 def test_get_coefficient_iterator_invalid_mode_raises_value_error (self ) -> None :
432460 """Test that get_coefficient_iterator raises ValueError for invalid mode."""
433461 with self .assertRaisesRegex (ValueError , "Invalid mode.*invalid" ):
0 commit comments