Beispiel #1
0
    def test_decomposable_tridiagonal_shuffled(self):
        """
        This matrix decomposes into 2x2 blocks
        |x x      |
        |x x      |
        |  x x x  |
        |    x x  |
        |      x x|
        """
        N = 5
        row = []
        col = []
        data = []

        # Diagonal
        row.extend(range(N))
        col.extend(range(N))
        data.extend(1 for _ in range(N))

        # Below diagonal
        row.extend(range(1, N))
        col.extend(range(N - 1))
        data.extend(1 for _ in range(N - 1))

        # Above diagonal
        row.extend(i for i in range(N - 1) if not i % 2)
        col.extend(i + 1 for i in range(N - 1) if not i % 2)
        data.extend(1 for i in range(N - 1) if not i % 2)

        # Same results hold after applying a random permutation.
        row_perm = list(range(N))
        col_perm = list(range(N))
        random.shuffle(row_perm)
        random.shuffle(col_perm)

        row = [row_perm[i] for i in row]
        col = [col_perm[j] for j in col]

        matrix = sps.coo_matrix((data, (row, col)), shape=(N, N))

        row_block_map, col_block_map = block_triangularize(matrix)
        row_values = set(row_block_map.values())
        col_values = set(row_block_map.values())

        self.assertEqual(len(row_values), (N + 1) // 2)
        self.assertEqual(len(col_values), (N + 1) // 2)

        for i in range((N + 1) // 2):
            row_idx = row_perm[2 * i]
            col_idx = col_perm[2 * i]
            self.assertEqual(row_block_map[row_idx], i)
            self.assertEqual(col_block_map[col_idx], i)

            if 2 * i + 1 < N:
                row_idx = row_perm[2 * i + 1]
                col_idx = col_perm[2 * i + 1]
                self.assertEqual(row_block_map[row_idx], i)
                self.assertEqual(col_block_map[col_idx], i)
Beispiel #2
0
    def test_non_square_exception(self):
        N = 5
        row = list(range(N - 1))
        col = list(range(N - 1))
        data = [1 for _ in range(N - 1)]

        matrix = sps.coo_matrix((data, (row, col)), shape=(N, N - 1))

        with self.assertRaises(ValueError) as exc:
            row_block_map, col_block_map = block_triangularize(matrix)
        self.assertIn('non-square matrices', str(exc.exception))
Beispiel #3
0
    def test_low_rank_exception(self):
        N = 5
        row = list(range(N - 1))
        col = list(range(N - 1))
        data = [1 for _ in range(N - 1)]

        matrix = sps.coo_matrix((data, (row, col)), shape=(N, N))

        with self.assertRaises(ValueError) as exc:
            row_block_map, col_block_map = block_triangularize(matrix)
        self.assertIn('perfect matching', str(exc.exception))
Beispiel #4
0
    def test_decomposable_bordered(self):
        """
        This matrix decomposes
        |x        |
        |  x      |
        |    x   x|
        |      x x|
        |x x x x  |
        """
        N = 5
        half = N // 2
        row = []
        col = []
        data = []

        # Diagonal
        row.extend(range(N - 1))
        col.extend(range(N - 1))
        data.extend(1 for _ in range(N - 1))

        # Bottom row
        row.extend(N - 1 for _ in range(N - 1))
        col.extend(range(N - 1))
        data.extend(1 for _ in range(N - 1))

        # Right column
        row.extend(range(half, N - 1))
        col.extend(N - 1 for _ in range(half, N - 1))
        data.extend(1 for _ in range(half, N - 1))

        matrix = sps.coo_matrix((data, (row, col)), shape=(N, N))

        row_block_map, col_block_map = block_triangularize(matrix)
        row_values = set(row_block_map.values())
        col_values = set(row_block_map.values())

        self.assertEqual(len(row_values), half + 1)
        self.assertEqual(len(col_values), half + 1)

        first_half_set = set(range(half))
        for i in range(N):
            if i < half:
                # The first N//2 diagonal blocks are unordered
                self.assertIn(row_block_map[i], first_half_set)
                self.assertIn(col_block_map[i], first_half_set)
            else:
                self.assertEqual(row_block_map[i], half)
                self.assertEqual(col_block_map[i], half)
Beispiel #5
0
    def test_decomposable_tridiagonal(self):
        """
        This matrix decomposes into 2x2 blocks
        |x x      |
        |x x      |
        |  x x x  |
        |    x x  |
        |      x x|
        """
        N = 5
        row = []
        col = []
        data = []

        # Diagonal
        row.extend(range(N))
        col.extend(range(N))
        data.extend(1 for _ in range(N))

        # Below diagonal
        row.extend(range(1, N))
        col.extend(range(N - 1))
        data.extend(1 for _ in range(N - 1))

        # Above diagonal
        row.extend(i for i in range(N - 1) if not i % 2)
        col.extend(i + 1 for i in range(N - 1) if not i % 2)
        data.extend(1 for i in range(N - 1) if not i % 2)

        matrix = sps.coo_matrix((data, (row, col)), shape=(N, N))

        row_block_map, col_block_map = block_triangularize(matrix)
        row_values = set(row_block_map.values())
        col_values = set(row_block_map.values())

        self.assertEqual(len(row_values), (N + 1) // 2)
        self.assertEqual(len(col_values), (N + 1) // 2)

        for i in range((N + 1) // 2):
            self.assertEqual(row_block_map[2 * i], i)
            self.assertEqual(col_block_map[2 * i], i)

            if 2 * i + 1 < N:
                self.assertEqual(row_block_map[2 * i + 1], i)
                self.assertEqual(col_block_map[2 * i + 1], i)
Beispiel #6
0
    def test_triangularize(self):
        N = 5
        model = make_gas_expansion_model(N)

        # These are the variables and constraints of the square,
        # nonsingular subsystem
        variables = []
        variables.extend(model.P.values())
        variables.extend(model.T[i] for i in model.streams
                         if i != model.streams.first())
        variables.extend(model.rho[i] for i in model.streams
                         if i != model.streams.first())
        variables.extend(model.F[i] for i in model.streams
                         if i != model.streams.first())

        constraints = list(model.component_data_objects(pyo.Constraint))

        imat = get_structural_incidence_matrix(variables, constraints)
        con_idx_map = ComponentMap((c, i) for i, c in enumerate(constraints))
        var_idx_map = ComponentMap((v, i) for i, v in enumerate(variables))

        row_block_map, col_block_map = block_triangularize(imat)
        var_block_map = ComponentMap(
            (v, col_block_map[var_idx_map[v]]) for v in variables)
        con_block_map = ComponentMap(
            (c, row_block_map[con_idx_map[c]]) for c in constraints)

        var_values = set(var_block_map.values())
        con_values = set(con_block_map.values())
        self.assertEqual(len(var_values), N + 1)
        self.assertEqual(len(con_values), N + 1)

        self.assertEqual(var_block_map[model.P[0]], 0)

        for i in model.streams:
            if i != model.streams.first():
                self.assertEqual(var_block_map[model.rho[i]], i)
                self.assertEqual(var_block_map[model.T[i]], i)
                self.assertEqual(var_block_map[model.P[i]], i)
                self.assertEqual(var_block_map[model.F[i]], i)

                self.assertEqual(con_block_map[model.ideal_gas[i]], i)
                self.assertEqual(con_block_map[model.expansion[i]], i)
                self.assertEqual(con_block_map[model.mbal[i]], i)
                self.assertEqual(con_block_map[model.ebal[i]], i)
Beispiel #7
0
    def block_triangularize(self, variables=None, constraints=None):
        """
        Returns two ComponentMaps. A map from variables to their blocks
        in a block triangularization of the incidence matrix, and a
        map from constraints to their blocks in a block triangularization
        of the incidence matrix.
        """
        variables, constraints = self._validate_input(variables, constraints)
        matrix = self._extract_submatrix(variables, constraints)

        row_block_map, col_block_map = block_triangularize(matrix.tocoo())
        con_block_map = ComponentMap(
            (constraints[i], idx) for i, idx in row_block_map.items())
        var_block_map = ComponentMap(
            (variables[j], idx) for j, idx in col_block_map.items())
        # Switch the order of the maps here to match the method call.
        # Hopefully this does not get too confusing...
        return var_block_map, con_block_map
Beispiel #8
0
    def test_bordered(self):
        """
        This matrix is non-decomposable
        |x       x|
        |  x     x|
        |    x   x|
        |      x x|
        |x x x x  |
        """
        N = 5
        row = []
        col = []
        data = []
        # Diagonal
        row.extend(range(N - 1))
        col.extend(range(N - 1))
        data.extend(1 for _ in range(N - 1))

        # Bottom row
        row.extend(N - 1 for _ in range(N - 1))
        col.extend(range(N - 1))
        data.extend(1 for _ in range(N - 1))

        # Right column
        row.extend(range(N - 1))
        col.extend(N - 1 for _ in range(N - 1))
        data.extend(1 for _ in range(N - 1))

        matrix = sps.coo_matrix((data, (row, col)), shape=(N, N))

        row_block_map, col_block_map = block_triangularize(matrix)
        row_values = set(row_block_map.values())
        col_values = set(row_block_map.values())

        self.assertEqual(len(row_values), 1)
        self.assertEqual(len(col_values), 1)

        for i in range(N):
            self.assertEqual(row_block_map[i], 0)
            self.assertEqual(col_block_map[i], 0)
Beispiel #9
0
    def test_upper_tri(self):
        """
        This matrix has a unique maximal matching and SCC
        order, making it a good test for a "fully decomposable"
        matrix.
        |x x      |
        |  x x    |
        |    x x  |
        |      x x|
        |        x|
        """
        N = 5
        row = []
        col = []
        data = []
        # Diagonal
        row.extend(range(N))
        col.extend(range(N))
        data.extend(1 for _ in range(N))

        # Below diagonal
        row.extend(range(N - 1))
        col.extend(range(1, N))
        data.extend(1 for _ in range(N - 1))

        matrix = sps.coo_matrix((data, (row, col)), shape=(N, N))

        row_block_map, col_block_map = block_triangularize(matrix)
        row_values = set(row_block_map.values())
        col_values = set(row_block_map.values())

        self.assertEqual(len(row_values), N)
        self.assertEqual(len(col_values), N)

        for i in range(N):
            # The block_triangularize function permutes
            # to lower triangular form, so rows and
            # columns are transposed to assemble the blocks.
            self.assertEqual(row_block_map[i], N - 1 - i)
            self.assertEqual(col_block_map[i], N - 1 - i)
Beispiel #10
0
    def test_lower_tri(self):
        """
        This matrix has a unique maximal matching and SCC
        order, making it a good test for a "fully decomposable"
        matrix.
        |x        |
        |x x      |
        |  x x    |
        |    x x  |
        |      x x|
        """
        N = 5
        row = []
        col = []
        data = []
        # Diagonal
        row.extend(range(N))
        col.extend(range(N))
        data.extend(1 for _ in range(N))

        # Below diagonal
        row.extend(range(1, N))
        col.extend(range(N - 1))
        data.extend(1 for _ in range(N - 1))

        matrix = sps.coo_matrix((data, (row, col)), shape=(N, N))

        row_block_map, col_block_map = block_triangularize(matrix)
        row_values = set(row_block_map.values())
        col_values = set(row_block_map.values())

        self.assertEqual(len(row_values), N)
        self.assertEqual(len(col_values), N)

        for i in range(N):
            self.assertEqual(row_block_map[i], i)
            self.assertEqual(col_block_map[i], i)
Beispiel #11
0
    def test_identity(self):
        N = 5
        matrix = sps.identity(N).tocoo()
        row_block_map, col_block_map = block_triangularize(matrix)
        row_values = set(row_block_map.values())
        col_values = set(row_block_map.values())

        # For a (block) diagonal matrix, the order of diagonal
        # blocks is arbitary, so we can't perform any strong
        # checks here.
        #
        # Perfect matching is unique, but order of strongly
        # connected components is not.

        self.assertEqual(len(row_block_map), N)
        self.assertEqual(len(col_block_map), N)
        self.assertEqual(len(row_values), N)
        self.assertEqual(len(col_values), N)

        for i in range(N):
            self.assertIn(i, row_block_map)
            self.assertIn(i, col_block_map)
            self.assertIn(i, row_values)
            self.assertIn(i, col_values)