cp-library

This documentation is automatically generated by online-judge-tools/verification-helper

View the Project on GitHub kobejean/cp-library

:heavy_check_mark: test/unittests/ds/view/csr_cls_test.py

Depends on

Code

# verification-helper: PROBLEM https://judge.yosupo.jp/problem/aplusb

import pytest
import random

class TestCSR:
    def test_initialization(self):
        """Test basic initialization of CSR"""
        A = [1, 2, 3, 4, 5, 6]
        O = [0, 2, 4, 6]  # 3 rows: [1,2], [3,4], [5,6]
        csr = CSR(A, O)
        
        assert csr.A is A
        assert csr.O is O
        assert len(csr) == 3

    def test_len(self):
        """Test __len__ method"""
        A = [1, 2, 3, 4, 5]
        O = [0, 2, 3, 5]  # 3 rows: [1,2], [3], [4,5]
        csr = CSR(A, O)
        
        assert len(csr) == 3
        
        # Empty CSR
        empty_csr = CSR([], [0])
        assert len(empty_csr) == 0

    def test_getitem(self):
        """Test __getitem__ method (returns temporary view)"""
        A = [10, 20, 30, 40, 50, 60]
        O = [0, 2, 4, 6]  # 3 rows: [10,20], [30,40], [50,60]
        csr = CSR(A, O)
        
        # Test temporary access - each call returns the same view object but points to different rows
        # Test row 0
        row = csr[0]
        assert len(row) == 2
        assert row[0] == 10
        assert row[1] == 20
        
        # Test row 1 - same view object, different range
        row = csr[1]
        assert len(row) == 2
        assert row[0] == 30
        assert row[1] == 40
        
        # Test row 2 - same view object, different range
        row = csr[2]
        assert len(row) == 2
        assert row[0] == 50
        assert row[1] == 60

    def test_call(self):
        """Test __call__ method (direct element access)"""
        A = [10, 20, 30, 40, 50, 60]
        O = [0, 2, 4, 6]  # 3 rows: [10,20], [30,40], [50,60]
        csr = CSR(A, O)
        
        # Direct access to elements
        assert csr(0, 0) == 10
        assert csr(0, 1) == 20
        assert csr(1, 0) == 30
        assert csr(1, 1) == 40
        assert csr(2, 0) == 50
        assert csr(2, 1) == 60

    def test_set(self):
        """Test set method"""
        A = [10, 20, 30, 40, 50, 60]
        O = [0, 2, 4, 6]  # 3 rows: [10,20], [30,40], [50,60]
        csr = CSR(A, O)
        
        # Modify elements
        csr.set(0, 0, 15)
        csr.set(1, 1, 45)
        csr.set(2, 0, 55)
        
        assert A == [15, 20, 30, 45, 55, 60]
        assert csr(0, 0) == 15
        assert csr(1, 1) == 45
        assert csr(2, 0) == 55

    def test_getitem_method(self):
        """Test __getitem__ method (creates new view)"""
        A = [1, 2, 3, 4, 5, 6, 7, 8]
        O = [0, 3, 5, 8]  # 3 rows: [1,2,3], [4,5], [6,7,8]
        csr = CSR(A, O)
        
        # Create views for each row
        view0 = csr[0]
        view1 = csr[1]
        view2 = csr[2]
        
        assert len(view0) == 3
        assert view0[0] == 1
        assert view0[2] == 3
        
        assert len(view1) == 2
        assert view1[0] == 4
        assert view1[1] == 5
        
        assert len(view2) == 3
        assert view2[0] == 6
        assert view2[2] == 8

    def test_bucketize(self):
        """Test bucketize class method"""
        # Create buckets: bucket 0 gets [1,3], bucket 1 gets [2], bucket 2 gets [4,5]
        N = 3
        K = [0, 1, 0, 2, 2]  # Keys indicating which bucket each value goes to
        V = [1, 2, 3, 4, 5]  # Values to be bucketed
        
        csr = CSR.bucketize(N, K, V)
        
        assert len(csr) == 3
        
        # Check bucket 0: should contain [3, 1] (reverse order due to algorithm)
        row0 = csr[0]
        assert len(row0) == 2
        assert set([row0[0], row0[1]]) == {1, 3}
        
        # Check bucket 1: should contain [2]
        row1 = csr[1]
        assert len(row1) == 1
        assert row1[0] == 2
        
        # Check bucket 2: should contain [5, 4] (reverse order)
        row2 = csr[2]
        assert len(row2) == 2
        assert set([row2[0], row2[1]]) == {4, 5}

    def test_empty_rows(self):
        """Test CSR with empty rows"""
        A = [1, 2, 3, 4]
        O = [0, 2, 2, 4]  # 3 rows: [1,2], [], [3,4]
        csr = CSR(A, O)
        
        assert len(csr) == 3
        
        # Row 0: [1,2]
        row0 = csr[0]
        assert len(row0) == 2
        assert row0[0] == 1
        assert row0[1] == 2
        
        # Row 1: empty
        row1 = csr[1]
        assert len(row1) == 0
        
        # Row 2: [3,4]
        row2 = csr[2]
        assert len(row2) == 2
        assert row2[0] == 3
        assert row2[1] == 4

    def test_single_element_rows(self):
        """Test CSR with single element rows"""
        A = [10, 20, 30]
        O = [0, 1, 2, 3]  # 3 rows: [10], [20], [30]
        csr = CSR(A, O)
        
        assert len(csr) == 3
        
        for i in range(3):
            row = csr[i]
            assert len(row) == 1
            assert row[0] == (i + 1) * 10
            assert csr(i, 0) == (i + 1) * 10

    def test_view_modifications(self):
        """Test that view modifications affect the underlying data"""
        A = [1, 2, 3, 4, 5, 6]
        O = [0, 2, 4, 6]  # 3 rows: [1,2], [3,4], [5,6]
        csr = CSR(A, O)
        
        # Get a view and modify it
        row1 = csr[1]
        row1[0] = 30
        row1[1] = 40
        
        # Check that underlying data changed
        assert A == [1, 2, 30, 40, 5, 6]
        assert csr(1, 0) == 30
        assert csr(1, 1) == 40

    def test_view_operations(self):
        """Test various view operations"""
        A = [5, 3, 1, 4, 2, 6]
        O = [0, 3, 6]  # 2 rows: [5,3,1], [4,2,6]
        csr = CSR(A, O)
        
        # Get views and operate on them
        row0 = csr[0]
        row0.sort()
        assert A[:3] == [1, 3, 5]
        
        row1 = csr[1]
        row1.reverse()
        assert A[3:] == [6, 2, 4]

    def test_view_creation_behavior(self):
        """Test that __getitem__ creates new view objects each time"""
        A = [1, 2, 3, 4, 5, 6]
        O = [0, 2, 4, 6]  # 3 rows: [1,2], [3,4], [5,6]
        csr = CSR(A, O)
        
        # __getitem__ creates new view objects each time
        view1 = csr[0]  # New view of row 0
        view2 = csr[0]  # Another new view of row 0
        
        # Should be different objects but point to the same data
        assert view1 is not view2  # Different objects
        
        # But should have the same data
        assert len(view1) == len(view2) == 2
        assert view1[0] == view2[0] == 1  # Row 0 data
        assert view1[1] == view2[1] == 2  # Row 0 data
        
        # Views of different rows should also be independent
        row0_view = csr[0]
        row1_view = csr[1] 
        
        assert row0_view is not row1_view  # Different objects
        assert len(row0_view) == 2
        assert row0_view[0] == 1  # Row 0 data
        assert len(row1_view) == 2  
        assert row1_view[0] == 3  # Row 1 data

    def test_large_csr(self):
        """Test CSR with larger data"""
        # Create 100 rows with 10 elements each
        A = list(range(1000))
        O = [i * 10 for i in range(101)]  # 100 rows
        csr = CSR(A, O)
        
        assert len(csr) == 100
        
        # Test random access
        assert csr(50, 5) == 505
        assert csr(99, 9) == 999
        
        # Test view length
        for i in range(100):
            assert len(csr[i]) == 10

    def test_bucketize_edge_cases(self):
        """Test bucketize with edge cases"""
        # All elements go to the same bucket
        N = 3
        K = [1, 1, 1, 1]
        V = [10, 20, 30, 40]
        
        csr = CSR.bucketize(N, K, V)
        assert len(csr) == 3
        
        # Bucket 0 should be empty
        assert len(csr[0]) == 0
        
        # Bucket 1 should have all elements
        assert len(csr[1]) == 4
        
        # Bucket 2 should be empty
        assert len(csr[2]) == 0

    def test_bucketize_empty(self):
        """Test bucketize with empty input"""
        N = 3
        K = []
        V = []
        
        csr = CSR.bucketize(N, K, V)
        assert len(csr) == 3
        
        # All buckets should be empty
        for i in range(3):
            assert len(csr[i]) == 0

    def test_different_data_types(self):
        """Test CSR with different data types"""
        # String data
        A = ['a', 'b', 'c', 'd', 'e', 'f']
        O = [0, 2, 4, 6]
        csr = CSR(A, O)
        
        assert csr(0, 0) == 'a'
        assert csr(1, 1) == 'd'
        assert csr(2, 0) == 'e'
        
        # Float data
        A_float = [1.1, 2.2, 3.3, 4.4]
        O_float = [0, 2, 4]
        csr_float = CSR(A_float, O_float)
        
        assert csr_float(0, 0) == 1.1
        assert csr_float(1, 1) == 4.4

    def test_bounds_checking(self):
        """Test that appropriate errors are raised for out-of-bounds access"""
        A = [1, 2, 3, 4]
        O = [0, 2, 4]  # 2 rows: [1,2], [3,4]
        csr = CSR(A, O)
        
        # These should work
        assert csr(0, 1) == 2
        assert csr(1, 0) == 3
        
        # Out of bounds row access should raise IndexError when accessing the view
        # Note: CSR doesn't validate bounds itself, the view does
        row = csr[0]
        with pytest.raises(IndexError):
            row[2]  # Row 0 only has 2 elements (indices 0, 1)

    def test_random_operations(self):
        """Test random operations for robustness"""
        random.seed(42)  # For reproducibility
        
        # Create random CSR structure
        num_rows = 50
        total_elements = 500
        A = [random.randint(1, 1000) for _ in range(total_elements)]
        
        # Generate random row sizes
        O = [0]
        remaining = total_elements
        for i in range(num_rows - 1):
            if remaining > 0:
                row_size = random.randint(0, min(20, remaining))
                O.append(O[-1] + row_size)
                remaining -= row_size
            else:
                O.append(O[-1])
        O.append(total_elements)
        
        csr = CSR(A, O)
        assert len(csr) == num_rows
        
        # Perform random operations
        for _ in range(100):
            row_idx = random.randint(0, num_rows - 1)
            row = csr[row_idx]
            
            if len(row) > 0:
                col_idx = random.randint(0, len(row) - 1)
                # Read operation
                val1 = csr(row_idx, col_idx)
                val2 = row[col_idx]
                assert val1 == val2
                
                # Write operation
                new_val = random.randint(2000, 3000)
                csr.set(row_idx, col_idx, new_val)
                assert csr(row_idx, col_idx) == new_val
                assert row[col_idx] == new_val

    def test_view_isolation(self):
        """Test that different views don't interfere with each other"""
        A = [1, 2, 3, 4, 5, 6, 7, 8]
        O = [0, 3, 5, 8]  # 3 rows: [1,2,3], [4,5], [6,7,8]
        csr = CSR(A, O)
        
        # Get multiple views
        view0 = csr[0]
        view1 = csr[1]
        view2 = csr[2]
        
        # Modify through different views
        view0[0] = 10
        view1[1] = 50
        view2[2] = 80
        
        # Check that modifications are isolated and correct
        assert A == [10, 2, 3, 4, 50, 6, 7, 80]
        assert view0[0] == 10
        assert view1[1] == 50
        assert view2[2] == 80
        
        # Other elements should be unchanged
        assert view0[1] == 2
        assert view1[0] == 4
        assert view2[0] == 6

from cp_library.ds.view.csr_cls import CSR

if __name__ == '__main__':
    from cp_library.test.unittest_helper import run_verification_helper_unittest
    run_verification_helper_unittest()
# verification-helper: PROBLEM https://judge.yosupo.jp/problem/aplusb

import pytest
import random

class TestCSR:
    def test_initialization(self):
        """Test basic initialization of CSR"""
        A = [1, 2, 3, 4, 5, 6]
        O = [0, 2, 4, 6]  # 3 rows: [1,2], [3,4], [5,6]
        csr = CSR(A, O)
        
        assert csr.A is A
        assert csr.O is O
        assert len(csr) == 3

    def test_len(self):
        """Test __len__ method"""
        A = [1, 2, 3, 4, 5]
        O = [0, 2, 3, 5]  # 3 rows: [1,2], [3], [4,5]
        csr = CSR(A, O)
        
        assert len(csr) == 3
        
        # Empty CSR
        empty_csr = CSR([], [0])
        assert len(empty_csr) == 0

    def test_getitem(self):
        """Test __getitem__ method (returns temporary view)"""
        A = [10, 20, 30, 40, 50, 60]
        O = [0, 2, 4, 6]  # 3 rows: [10,20], [30,40], [50,60]
        csr = CSR(A, O)
        
        # Test temporary access - each call returns the same view object but points to different rows
        # Test row 0
        row = csr[0]
        assert len(row) == 2
        assert row[0] == 10
        assert row[1] == 20
        
        # Test row 1 - same view object, different range
        row = csr[1]
        assert len(row) == 2
        assert row[0] == 30
        assert row[1] == 40
        
        # Test row 2 - same view object, different range
        row = csr[2]
        assert len(row) == 2
        assert row[0] == 50
        assert row[1] == 60

    def test_call(self):
        """Test __call__ method (direct element access)"""
        A = [10, 20, 30, 40, 50, 60]
        O = [0, 2, 4, 6]  # 3 rows: [10,20], [30,40], [50,60]
        csr = CSR(A, O)
        
        # Direct access to elements
        assert csr(0, 0) == 10
        assert csr(0, 1) == 20
        assert csr(1, 0) == 30
        assert csr(1, 1) == 40
        assert csr(2, 0) == 50
        assert csr(2, 1) == 60

    def test_set(self):
        """Test set method"""
        A = [10, 20, 30, 40, 50, 60]
        O = [0, 2, 4, 6]  # 3 rows: [10,20], [30,40], [50,60]
        csr = CSR(A, O)
        
        # Modify elements
        csr.set(0, 0, 15)
        csr.set(1, 1, 45)
        csr.set(2, 0, 55)
        
        assert A == [15, 20, 30, 45, 55, 60]
        assert csr(0, 0) == 15
        assert csr(1, 1) == 45
        assert csr(2, 0) == 55

    def test_getitem_method(self):
        """Test __getitem__ method (creates new view)"""
        A = [1, 2, 3, 4, 5, 6, 7, 8]
        O = [0, 3, 5, 8]  # 3 rows: [1,2,3], [4,5], [6,7,8]
        csr = CSR(A, O)
        
        # Create views for each row
        view0 = csr[0]
        view1 = csr[1]
        view2 = csr[2]
        
        assert len(view0) == 3
        assert view0[0] == 1
        assert view0[2] == 3
        
        assert len(view1) == 2
        assert view1[0] == 4
        assert view1[1] == 5
        
        assert len(view2) == 3
        assert view2[0] == 6
        assert view2[2] == 8

    def test_bucketize(self):
        """Test bucketize class method"""
        # Create buckets: bucket 0 gets [1,3], bucket 1 gets [2], bucket 2 gets [4,5]
        N = 3
        K = [0, 1, 0, 2, 2]  # Keys indicating which bucket each value goes to
        V = [1, 2, 3, 4, 5]  # Values to be bucketed
        
        csr = CSR.bucketize(N, K, V)
        
        assert len(csr) == 3
        
        # Check bucket 0: should contain [3, 1] (reverse order due to algorithm)
        row0 = csr[0]
        assert len(row0) == 2
        assert set([row0[0], row0[1]]) == {1, 3}
        
        # Check bucket 1: should contain [2]
        row1 = csr[1]
        assert len(row1) == 1
        assert row1[0] == 2
        
        # Check bucket 2: should contain [5, 4] (reverse order)
        row2 = csr[2]
        assert len(row2) == 2
        assert set([row2[0], row2[1]]) == {4, 5}

    def test_empty_rows(self):
        """Test CSR with empty rows"""
        A = [1, 2, 3, 4]
        O = [0, 2, 2, 4]  # 3 rows: [1,2], [], [3,4]
        csr = CSR(A, O)
        
        assert len(csr) == 3
        
        # Row 0: [1,2]
        row0 = csr[0]
        assert len(row0) == 2
        assert row0[0] == 1
        assert row0[1] == 2
        
        # Row 1: empty
        row1 = csr[1]
        assert len(row1) == 0
        
        # Row 2: [3,4]
        row2 = csr[2]
        assert len(row2) == 2
        assert row2[0] == 3
        assert row2[1] == 4

    def test_single_element_rows(self):
        """Test CSR with single element rows"""
        A = [10, 20, 30]
        O = [0, 1, 2, 3]  # 3 rows: [10], [20], [30]
        csr = CSR(A, O)
        
        assert len(csr) == 3
        
        for i in range(3):
            row = csr[i]
            assert len(row) == 1
            assert row[0] == (i + 1) * 10
            assert csr(i, 0) == (i + 1) * 10

    def test_view_modifications(self):
        """Test that view modifications affect the underlying data"""
        A = [1, 2, 3, 4, 5, 6]
        O = [0, 2, 4, 6]  # 3 rows: [1,2], [3,4], [5,6]
        csr = CSR(A, O)
        
        # Get a view and modify it
        row1 = csr[1]
        row1[0] = 30
        row1[1] = 40
        
        # Check that underlying data changed
        assert A == [1, 2, 30, 40, 5, 6]
        assert csr(1, 0) == 30
        assert csr(1, 1) == 40

    def test_view_operations(self):
        """Test various view operations"""
        A = [5, 3, 1, 4, 2, 6]
        O = [0, 3, 6]  # 2 rows: [5,3,1], [4,2,6]
        csr = CSR(A, O)
        
        # Get views and operate on them
        row0 = csr[0]
        row0.sort()
        assert A[:3] == [1, 3, 5]
        
        row1 = csr[1]
        row1.reverse()
        assert A[3:] == [6, 2, 4]

    def test_view_creation_behavior(self):
        """Test that __getitem__ creates new view objects each time"""
        A = [1, 2, 3, 4, 5, 6]
        O = [0, 2, 4, 6]  # 3 rows: [1,2], [3,4], [5,6]
        csr = CSR(A, O)
        
        # __getitem__ creates new view objects each time
        view1 = csr[0]  # New view of row 0
        view2 = csr[0]  # Another new view of row 0
        
        # Should be different objects but point to the same data
        assert view1 is not view2  # Different objects
        
        # But should have the same data
        assert len(view1) == len(view2) == 2
        assert view1[0] == view2[0] == 1  # Row 0 data
        assert view1[1] == view2[1] == 2  # Row 0 data
        
        # Views of different rows should also be independent
        row0_view = csr[0]
        row1_view = csr[1] 
        
        assert row0_view is not row1_view  # Different objects
        assert len(row0_view) == 2
        assert row0_view[0] == 1  # Row 0 data
        assert len(row1_view) == 2  
        assert row1_view[0] == 3  # Row 1 data

    def test_large_csr(self):
        """Test CSR with larger data"""
        # Create 100 rows with 10 elements each
        A = list(range(1000))
        O = [i * 10 for i in range(101)]  # 100 rows
        csr = CSR(A, O)
        
        assert len(csr) == 100
        
        # Test random access
        assert csr(50, 5) == 505
        assert csr(99, 9) == 999
        
        # Test view length
        for i in range(100):
            assert len(csr[i]) == 10

    def test_bucketize_edge_cases(self):
        """Test bucketize with edge cases"""
        # All elements go to the same bucket
        N = 3
        K = [1, 1, 1, 1]
        V = [10, 20, 30, 40]
        
        csr = CSR.bucketize(N, K, V)
        assert len(csr) == 3
        
        # Bucket 0 should be empty
        assert len(csr[0]) == 0
        
        # Bucket 1 should have all elements
        assert len(csr[1]) == 4
        
        # Bucket 2 should be empty
        assert len(csr[2]) == 0

    def test_bucketize_empty(self):
        """Test bucketize with empty input"""
        N = 3
        K = []
        V = []
        
        csr = CSR.bucketize(N, K, V)
        assert len(csr) == 3
        
        # All buckets should be empty
        for i in range(3):
            assert len(csr[i]) == 0

    def test_different_data_types(self):
        """Test CSR with different data types"""
        # String data
        A = ['a', 'b', 'c', 'd', 'e', 'f']
        O = [0, 2, 4, 6]
        csr = CSR(A, O)
        
        assert csr(0, 0) == 'a'
        assert csr(1, 1) == 'd'
        assert csr(2, 0) == 'e'
        
        # Float data
        A_float = [1.1, 2.2, 3.3, 4.4]
        O_float = [0, 2, 4]
        csr_float = CSR(A_float, O_float)
        
        assert csr_float(0, 0) == 1.1
        assert csr_float(1, 1) == 4.4

    def test_bounds_checking(self):
        """Test that appropriate errors are raised for out-of-bounds access"""
        A = [1, 2, 3, 4]
        O = [0, 2, 4]  # 2 rows: [1,2], [3,4]
        csr = CSR(A, O)
        
        # These should work
        assert csr(0, 1) == 2
        assert csr(1, 0) == 3
        
        # Out of bounds row access should raise IndexError when accessing the view
        # Note: CSR doesn't validate bounds itself, the view does
        row = csr[0]
        with pytest.raises(IndexError):
            row[2]  # Row 0 only has 2 elements (indices 0, 1)

    def test_random_operations(self):
        """Test random operations for robustness"""
        random.seed(42)  # For reproducibility
        
        # Create random CSR structure
        num_rows = 50
        total_elements = 500
        A = [random.randint(1, 1000) for _ in range(total_elements)]
        
        # Generate random row sizes
        O = [0]
        remaining = total_elements
        for i in range(num_rows - 1):
            if remaining > 0:
                row_size = random.randint(0, min(20, remaining))
                O.append(O[-1] + row_size)
                remaining -= row_size
            else:
                O.append(O[-1])
        O.append(total_elements)
        
        csr = CSR(A, O)
        assert len(csr) == num_rows
        
        # Perform random operations
        for _ in range(100):
            row_idx = random.randint(0, num_rows - 1)
            row = csr[row_idx]
            
            if len(row) > 0:
                col_idx = random.randint(0, len(row) - 1)
                # Read operation
                val1 = csr(row_idx, col_idx)
                val2 = row[col_idx]
                assert val1 == val2
                
                # Write operation
                new_val = random.randint(2000, 3000)
                csr.set(row_idx, col_idx, new_val)
                assert csr(row_idx, col_idx) == new_val
                assert row[col_idx] == new_val

    def test_view_isolation(self):
        """Test that different views don't interfere with each other"""
        A = [1, 2, 3, 4, 5, 6, 7, 8]
        O = [0, 3, 5, 8]  # 3 rows: [1,2,3], [4,5], [6,7,8]
        csr = CSR(A, O)
        
        # Get multiple views
        view0 = csr[0]
        view1 = csr[1]
        view2 = csr[2]
        
        # Modify through different views
        view0[0] = 10
        view1[1] = 50
        view2[2] = 80
        
        # Check that modifications are isolated and correct
        assert A == [10, 2, 3, 4, 50, 6, 7, 80]
        assert view0[0] == 10
        assert view1[1] == 50
        assert view2[2] == 80
        
        # Other elements should be unchanged
        assert view0[1] == 2
        assert view1[0] == 4
        assert view2[0] == 6


'''
╺━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━╸
             https://kobejean.github.io/cp-library               
'''
from typing import Generic
from typing import TypeVar
_S = TypeVar('S')
_T = TypeVar('T')
_U = TypeVar('U')




import sys

def list_find(lst: list, value, start = 0, stop = sys.maxsize):
    try:
        return lst.index(value, start, stop)
    except:
        return -1

class view(Generic[_T]):
    __slots__ = 'A', 'l', 'r'
    def __init__(V, A: list[_T], l: int, r: int): V.A, V.l, V.r = A, l, r
    def __len__(V): return V.r - V.l
    def __getitem__(V, i: int): 
        if 0 <= i < V.r - V.l: return V.A[V.l+i]
        else: raise IndexError
    def __setitem__(V, i: int, v: _T): V.A[V.l+i] = v
    def __contains__(V, v: _T): return list_find(V.A, v, V.l, V.r) != -1
    def set_range(V, l: int, r: int): V.l, V.r = l, r
    def index(V, v: _T): return V.A.index(v, V.l, V.r) - V.l
    def reverse(V):
        l, r = V.l, V.r-1
        while l < r: V.A[l], V.A[r] = V.A[r], V.A[l]; l += 1; r -= 1
    def sort(V, /, *args, **kwargs):
        A = V.A[V.l:V.r]; A.sort(*args, **kwargs)
        for i,a in enumerate(A,V.l): V.A[i] = a
    def pop(V): V.r -= 1; return V.A[V.r]
    def append(V, v: _T): V.A[V.r] = v; V.r += 1
    def popleft(V): V.l += 1; return V.A[V.l-1]
    def appendleft(V, v: _T): V.l -= 1; V.A[V.l] = v; 
    def validate(V): return 0 <= V.l <= V.r <= len(V.A)

class CSR(Generic[_T]):
    __slots__ = 'A', 'O'
    def __init__(csr, A: list[_T], O: list[int]): csr.A, csr.O = A, O
    def __len__(csr): return len(csr.O)-1
    def __getitem__(csr, i: int): return view(csr.A, csr.O[i], csr.O[i+1])
    def __call__(csr, i: int, j: int): return csr.A[csr.O[i]+j]
    def set(csr, i: int, j: int, v: _T): csr.A[csr.O[i]+j] = v
    @classmethod
    def bucketize(cls, N: int, K: list[int], V: list[_T]):
        A: list[_T] = [0]*len(K); O = [0]*(N+1)
        for k in K: O[k] += 1
        for i in range(N): O[i+1] += O[i]
        for e in range(len(K)): k = K[~e]; O[k] -= 1; A[O[k]] = V[~e]
        return cls(A, O)

if __name__ == '__main__':
    """
    Helper for making unittest files compatible with verification-helper.
    
    This module provides a helper function to run a dummy Library Checker test
    so that unittest files can be verified by oj-verify.
    """
    
    def run_verification_helper_unittest():
        """
        Run a dummy Library Checker test for verification-helper compatibility.
        
        This function should be called in the __main__ block of unittest files
        that need to be compatible with verification-helper.
        
        The function:
        1. Reads A and B from input
        2. Writes A+B to output  
        3. If the result is the expected value (1198300249), runs pytest
        4. Exits with the pytest result code
        """
        
        
        from typing import Type, Union, overload
        
        import typing
        from collections import deque
        from numbers import Number
        from types import GenericAlias 
        from typing import Callable, Collection, Iterator, Union
        
        import os
        from io import BytesIO, IOBase
        
        
        class FastIO(IOBase):
            BUFSIZE = 8192
            newlines = 0
        
            def __init__(self, file):
                self._fd = file.fileno()
                self.buffer = BytesIO()
                self.writable = "x" in file.mode or "r" not in file.mode
                self.write = self.buffer.write if self.writable else None
        
            def read(self):
                BUFSIZE = self.BUFSIZE
                while True:
                    b = os.read(self._fd, max(os.fstat(self._fd).st_size, BUFSIZE))
                    if not b: break
                    ptr = self.buffer.tell()
                    self.buffer.seek(0, 2), self.buffer.write(b), self.buffer.seek(ptr)
                self.newlines = 0
                return self.buffer.read()
        
            def readline(self):
                BUFSIZE = self.BUFSIZE
                while self.newlines == 0:
                    b = os.read(self._fd, max(os.fstat(self._fd).st_size, BUFSIZE))
                    self.newlines = b.count(b"\n") + (not b)
                    ptr = self.buffer.tell()
                    self.buffer.seek(0, 2), self.buffer.write(b), self.buffer.seek(ptr)
                self.newlines -= 1
                return self.buffer.readline()
        
            def flush(self):
                if self.writable:
                    os.write(self._fd, self.buffer.getvalue())
                    self.buffer.truncate(0), self.buffer.seek(0)
        
        
        class IOWrapper(IOBase):
            stdin: 'IOWrapper' = None
            stdout: 'IOWrapper' = None
            
            def __init__(self, file):
                self.buffer = FastIO(file)
                self.flush = self.buffer.flush
                self.writable = self.buffer.writable
        
            def write(self, s):
                return self.buffer.write(s.encode("ascii"))
            
            def read(self):
                return self.buffer.read().decode("ascii")
            
            def readline(self):
                return self.buffer.readline().decode("ascii")
        try:
            sys.stdin = IOWrapper.stdin = IOWrapper(sys.stdin)
            sys.stdout = IOWrapper.stdout = IOWrapper(sys.stdout)
        except:
            pass
        
        class TokenStream(Iterator):
            stream = IOWrapper.stdin
        
            def __init__(self):
                self.queue = deque()
        
            def __next__(self):
                if not self.queue: self.queue.extend(self._line())
                return self.queue.popleft()
            
            def wait(self):
                if not self.queue: self.queue.extend(self._line())
                while self.queue: yield
         
            def _line(self):
                return TokenStream.stream.readline().split()
        
            def line(self):
                if self.queue:
                    A = list(self.queue)
                    self.queue.clear()
                    return A
                return self._line()
        TokenStream.default = TokenStream()
        
        class CharStream(TokenStream):
            def _line(self):
                return TokenStream.stream.readline().rstrip()
        CharStream.default = CharStream()
        
        ParseFn = Callable[[TokenStream],_T]
        class Parser:
            def __init__(self, spec: Union[type[_T],_T]):
                self.parse = Parser.compile(spec)
        
            def __call__(self, ts: TokenStream) -> _T:
                return self.parse(ts)
            
            @staticmethod
            def compile_type(cls: type[_T], args = ()) -> _T:
                if issubclass(cls, Parsable):
                    return cls.compile(*args)
                elif issubclass(cls, (Number, str)):
                    def parse(ts: TokenStream): return cls(next(ts))              
                    return parse
                elif issubclass(cls, tuple):
                    return Parser.compile_tuple(cls, args)
                elif issubclass(cls, Collection):
                    return Parser.compile_collection(cls, args)
                elif callable(cls):
                    def parse(ts: TokenStream):
                        return cls(next(ts))              
                    return parse
                else:
                    raise NotImplementedError()
            
            @staticmethod
            def compile(spec: Union[type[_T],_T]=int) -> ParseFn[_T]:
                if isinstance(spec, (type, GenericAlias)):
                    cls = typing.get_origin(spec) or spec
                    args = typing.get_args(spec) or tuple()
                    return Parser.compile_type(cls, args)
                elif isinstance(offset := spec, Number): 
                    cls = type(spec)  
                    def parse(ts: TokenStream): return cls(next(ts)) + offset
                    return parse
                elif isinstance(args := spec, tuple):      
                    return Parser.compile_tuple(type(spec), args)
                elif isinstance(args := spec, Collection):
                    return Parser.compile_collection(type(spec), args)
                elif isinstance(fn := spec, Callable): 
                    def parse(ts: TokenStream): return fn(next(ts))
                    return parse
                else:
                    raise NotImplementedError()
        
            @staticmethod
            def compile_line(cls: _T, spec=int) -> ParseFn[_T]:
                if spec is int:
                    fn = Parser.compile(spec)
                    def parse(ts: TokenStream): return cls([int(token) for token in ts.line()])
                    return parse
                else:
                    fn = Parser.compile(spec)
                    def parse(ts: TokenStream): return cls([fn(ts) for _ in ts.wait()])
                    return parse
        
            @staticmethod
            def compile_repeat(cls: _T, spec, N) -> ParseFn[_T]:
                fn = Parser.compile(spec)
                def parse(ts: TokenStream): return cls([fn(ts) for _ in range(N)])
                return parse
        
            @staticmethod
            def compile_children(cls: _T, specs) -> ParseFn[_T]:
                fns = tuple((Parser.compile(spec) for spec in specs))
                def parse(ts: TokenStream): return cls([fn(ts) for fn in fns])  
                return parse
                    
            @staticmethod
            def compile_tuple(cls: type[_T], specs) -> ParseFn[_T]:
                if isinstance(specs, (tuple,list)) and len(specs) == 2 and specs[1] is ...:
                    return Parser.compile_line(cls, specs[0])
                else:
                    return Parser.compile_children(cls, specs)
        
            @staticmethod
            def compile_collection(cls, specs):
                if not specs or len(specs) == 1 or isinstance(specs, set):
                    return Parser.compile_line(cls, *specs)
                elif (isinstance(specs, (tuple,list)) and len(specs) == 2 and isinstance(specs[1], int)):
                    return Parser.compile_repeat(cls, specs[0], specs[1])
                else:
                    raise NotImplementedError()
        
        class Parsable:
            @classmethod
            def compile(cls):
                def parser(ts: TokenStream): return cls(next(ts))
                return parser
            
            @classmethod
            def __class_getitem__(cls, item):
                return GenericAlias(cls, item)
        
        @overload
        def read() -> list[int]: ...
        @overload
        def read(spec: Type[_T], char=False) -> _T: ...
        @overload
        def read(spec: _U, char=False) -> _U: ...
        @overload
        def read(*specs: Type[_T], char=False) -> tuple[_T, ...]: ...
        @overload
        def read(*specs: _U, char=False) -> tuple[_U, ...]: ...
        def read(*specs: Union[Type[_T],_U], char=False):
            if not char and not specs: return [int(s) for s in TokenStream.default.line()]
            parser: _T = Parser.compile(specs[0] if len(specs) == 1 else specs)
            return parser(CharStream.default if char else TokenStream.default)
        
        
        import os
        from io import BytesIO, IOBase
        
        
        class FastIO(IOBase):
            BUFSIZE = 8192
            newlines = 0
        
            def __init__(self, file):
                self._fd = file.fileno()
                self.buffer = BytesIO()
                self.writable = "x" in file.mode or "r" not in file.mode
                self.write = self.buffer.write if self.writable else None
        
            def read(self):
                BUFSIZE = self.BUFSIZE
                while True:
                    b = os.read(self._fd, max(os.fstat(self._fd).st_size, BUFSIZE))
                    if not b: break
                    ptr = self.buffer.tell()
                    self.buffer.seek(0, 2), self.buffer.write(b), self.buffer.seek(ptr)
                self.newlines = 0
                return self.buffer.read()
        
            def readline(self):
                BUFSIZE = self.BUFSIZE
                while self.newlines == 0:
                    b = os.read(self._fd, max(os.fstat(self._fd).st_size, BUFSIZE))
                    self.newlines = b.count(b"\n") + (not b)
                    ptr = self.buffer.tell()
                    self.buffer.seek(0, 2), self.buffer.write(b), self.buffer.seek(ptr)
                self.newlines -= 1
                return self.buffer.readline()
        
            def flush(self):
                if self.writable:
                    os.write(self._fd, self.buffer.getvalue())
                    self.buffer.truncate(0), self.buffer.seek(0)
        
        
        class IOWrapper(IOBase):
            stdin: 'IOWrapper' = None
            stdout: 'IOWrapper' = None
            
            def __init__(self, file):
                self.buffer = FastIO(file)
                self.flush = self.buffer.flush
                self.writable = self.buffer.writable
        
            def write(self, s):
                return self.buffer.write(s.encode("ascii"))
            
            def read(self):
                return self.buffer.read().decode("ascii")
            
            def readline(self):
                return self.buffer.readline().decode("ascii")
        try:
            sys.stdin = IOWrapper.stdin = IOWrapper(sys.stdin)
            sys.stdout = IOWrapper.stdout = IOWrapper(sys.stdout)
        except:
            pass
        
        def write(*args, **kwargs):
            '''Prints the values to a stream, or to stdout_fast by default.'''
            sep, file = kwargs.pop("sep", " "), kwargs.pop("file", IOWrapper.stdout)
            at_start = True
            for x in args:
                if not at_start:
                    file.write(sep)
                file.write(str(x))
                at_start = False
            file.write(kwargs.pop("end", "\n"))
            if kwargs.pop("flush", False):
                file.flush()
        
        A, B = read()
        write(C := A + B)
        if C != 1198300249: 
            sys.exit(0)
        
        import io
        from contextlib import redirect_stdout, redirect_stderr
    
        # Capture all output during test execution
        output = io.StringIO()
        with redirect_stdout(output), redirect_stderr(output):
            # Get the calling module's file path
            frame = sys._getframe(1)
            test_file = frame.f_globals.get('__file__')
            if test_file is None:
                test_file = sys.argv[0]
            result = pytest.main([test_file])
        
        if result != 0: 
            print(output.getvalue())
        sys.exit(result)
    run_verification_helper_unittest()
Back to top page