import unittest from tinygrad import Tensor, Device, dtypes, GlobalCounters from test.helpers import assert_kernel_count class TestSetitemInto(unittest.TestCase): def test_setitem_into_unrealized(self): GlobalCounters.reset() t = Tensor.arange(4, dtype=dtypes.int32).reshape(2, 2) assert_kernel_count(0) t[1] = 5 assert_kernel_count(0) t.realize() assert_kernel_count(0) self.assertEqual(GlobalCounters.global_mem, 0) self.assertListEqual(t.tolist(), [[0, 1], [5, 5]]) def test_setitem_into_unrealized_sliced_compute(self): # base computation contains SHRINK from prior slicing (like QR decomposition pattern) GlobalCounters.reset() a = Tensor.arange(8, dtype=dtypes.int32).reshape(2, 4) w = a[0] + a[1] # unrealized ADD with SHRINK in graph: [4, 6, 8, 10] assert_kernel_count(0) w[1] = 99 assert_kernel_count(0) w.realize() assert_kernel_count(0) self.assertEqual(GlobalCounters.global_mem, 0) self.assertListEqual(w.tolist(), [4, 99, 8, 10]) def test_setitem_into_empty(self): GlobalCounters.reset() t = Tensor.empty(4, dtype=dtypes.int32) t[1] = 5 assert_kernel_count(0) t.realize() assert_kernel_count(1) self.assertEqual(GlobalCounters.global_mem, 4) t[1].realize() t.realize() assert_kernel_count(1) self.assertEqual(t[1].item(), 5) def test_setitem_into_empty_alu(self): GlobalCounters.reset() t = Tensor.empty(4, dtype=dtypes.int32) + 1 assert_kernel_count(0) t[1] = 5 assert_kernel_count(0) t.realize() assert_kernel_count(1) self.assertLessEqual(GlobalCounters.global_mem, 32) t[1].realize() t.realize() assert_kernel_count(1) self.assertEqual(t[1].item(), 5) def test_setitem_into_tensor(self): t = Tensor([1, 2, 3, 4], dtype=dtypes.int32).realize() GlobalCounters.reset() t[1] = 5 assert_kernel_count(0) t[1].realize() assert_kernel_count(1) self.assertEqual(GlobalCounters.global_mem, 4) t.realize() assert_kernel_count(1) self.assertListEqual(t.tolist(), [1, 5, 3, 4]) def test_setitem_into_tensor_alu(self): t = Tensor([1, 2, 3, 4], dtype=dtypes.int32).realize() + 1 GlobalCounters.reset() t[1] = 5 assert_kernel_count(0) t[1].realize() assert_kernel_count(1) self.assertLessEqual(GlobalCounters.global_mem, 32) t[1].realize() t.realize() assert_kernel_count(1) self.assertListEqual(t.tolist(), [2, 5, 4, 5]) def test_setitem_into_const(self): GlobalCounters.reset() t = Tensor.ones(4, dtype=dtypes.int32, buffer=False) t[1] = 5 assert_kernel_count(0) t.realize() assert_kernel_count(0) self.assertEqual(GlobalCounters.global_mem, 0) self.assertListEqual(t.tolist(), [1, 5, 1, 1]) def test_setitem_into_const_alu(self): GlobalCounters.reset() t = Tensor.ones(4, dtype=dtypes.int32, buffer=False) + 1 t[1] = 5 assert_kernel_count(0) t.realize() assert_kernel_count(0) self.assertEqual(GlobalCounters.global_mem, 0) self.assertListEqual(t.tolist(), [2, 5, 2, 2]) def test_setitem_into_arange(self): # NOTE: arange has no real buffer, but assigning to it is fine GlobalCounters.reset() other = Tensor.arange(4, dtype=dtypes.int32) t = Tensor.arange(4, dtype=dtypes.int32) self.assertIs(other.uop, t.uop) t[1] = 5 assert_kernel_count(0) t.realize() assert_kernel_count(0) self.assertListEqual(t.tolist(), [0, 5, 2, 3]) @unittest.skipUnless(Device.DEFAULT != "CPU", "source must be on another device") def test_setitem_slice_assign_from_other_device(self): # Copy and assign; CL and WEBGPU also need a kernel to materialize the source slice (no buffer views). a = Tensor.ones(20, device="CPU") b = Tensor.arange(20).float().clone() Tensor.realize(a, b) GlobalCounters.reset() a[10:12].assign(b[13:15].to(a.device)).realize() assert_kernel_count(3 if Device.DEFAULT in {"CL", "WEBGPU"} else 2) self.assertListEqual(a.tolist(), [1.0]*10 + [13.0, 14.0] + [1.0]*8) if __name__ == '__main__': unittest.main()