コード例 #1
0
ファイル: block.py プロジェクト: renemilk/pyMor
    def __init__(self, blocks):
        blocks = np.array(blocks)
        assert isinstance(blocks, np.ndarray) and blocks.ndim == 2
        self._blocks = blocks
        assert all(isinstance(op, OperatorInterface) or op is None for op in self._operators())

        # check if every row/column contains at least one operator
        assert all(any(blocks[i, j] is not None for j in range(blocks.shape[1]))
                   for i in range(blocks.shape[0]))
        assert all(any(blocks[i, j] is not None for i in range(blocks.shape[0]))
                   for j in range(blocks.shape[1]))

        # find source/range types for every column/row
        source_types = [None for j in range(blocks.shape[1])]
        range_types = [None for i in range(blocks.shape[0])]
        for (i, j), op in np.ndenumerate(blocks):
            if op is not None:
                assert source_types[j] is None or op.source == source_types[j]
                source_types[j] = op.source
                assert range_types[i] is None or op.range == range_types[i]
                range_types[i] = op.range

        # turn Nones to ZeroOperators
        for (i, j) in np.ndindex(blocks.shape):
            if blocks[i, j] is None:
                self._blocks[i, j] = ZeroOperator(range_types[i], source_types[j])

        self.source = BlockVectorSpace(source_types)
        self.range = BlockVectorSpace(range_types)
        self.num_source_blocks = len(source_types)
        self.num_range_blocks = len(range_types)
        self.linear = all(op.linear for op in self._operators())
        self.build_parameter_type(*self._operators())
コード例 #2
0
 def __init__(self, subdomain, solution_space, grid, block_space):
     self.subdomain, self.grid, self.block_space = subdomain, grid, block_space
     self.neighborhood = grid.neighborhood_of(subdomain)
     self.source = solution_space.subspaces[subdomain]
     self.range = BlockVectorSpace(
         [solution_space.subspaces[ii] for ii in self.neighborhood],
         'OI_{}'.format(subdomain))
コード例 #3
0
class OswaldInterpolationErrorOperator(OperatorBase):

    linear = True

    def __init__(self, subdomain, solution_space, grid, block_space):
        self.subdomain, self.grid, self.block_space = subdomain, grid, block_space
        self.neighborhood = grid.neighborhood_of(subdomain)
        self.source = solution_space.subspaces[subdomain]
        self.range = BlockVectorSpace(
            [solution_space.subspaces[ii] for ii in self.neighborhood],
            'OI_{}'.format(subdomain))

    def apply(self, U, mu=None):
        assert U in self.source
        results = self.range.empty(reserve=len(U))
        for u_i in range(len(U)):
            result = self.range.zeros()
            result._blocks[self.neighborhood.index(self.subdomain)].axpy(
                1, U[u_i])

            for i_ii, ii in enumerate(self.neighborhood):
                ii_neighborhood = self.grid.neighborhood_of(ii)
                ii_neighborhood_space = self.block_space.restricted_to_neighborhood(
                    ii_neighborhood)

                subdomain_uh_with_neighborhood_support = make_discrete_function(
                    ii_neighborhood_space,
                    ii_neighborhood_space.project_onto_neighborhood([
                        U._list[u_i].impl if nn == self.subdomain else Vector(
                            self.block_space.local_space(nn).size(), 0.)
                        for nn in ii_neighborhood
                    ], ii_neighborhood))

                interpolated_u_vector = ii_neighborhood_space.project_onto_neighborhood(
                    [
                        Vector(self.block_space.local_space(nn).size(), 0.)
                        for nn in ii_neighborhood
                    ], ii_neighborhood)
                interpolated_u = make_discrete_function(
                    ii_neighborhood_space, interpolated_u_vector)

                apply_oswald_interpolation_operator(
                    self.grid, ii,
                    make_subdomain_boundary_info(
                        self.grid,
                        {'type': 'xt.grid.boundaryinfo.alldirichlet'}),
                    subdomain_uh_with_neighborhood_support, interpolated_u)

                local_sizes = np.array([
                    ii_neighborhood_space.local_space(nn).size()
                    for nn in ii_neighborhood
                ])
                offsets = np.hstack(([0], np.cumsum(local_sizes)))
                ind = ii_neighborhood.index(ii)
                result._blocks[i_ii]._list[0].data[:] -= \
                    np.frombuffer(interpolated_u_vector)[offsets[ind]:offsets[ind+1]]
            results.append(result)

        return results
コード例 #4
0
class FluxReconstructionOperator(OperatorBase):

    linear = True

    def __init__(self, subdomain, solution_space, grid, block_space,
                 global_rt_space, subdomain_rt_spaces, lambda_xi, kappa):
        self.grid = grid
        self.block_space = block_space
        self.global_rt_space = global_rt_space
        self.subdomain_rt_spaces = subdomain_rt_spaces
        self.subdomain = subdomain
        self.neighborhood = grid.neighborhood_of(subdomain)
        self.lambda_xi = lambda_xi
        self.kappa = kappa

        self.source = solution_space.subspaces[subdomain]
        vector_type = solution_space.subspaces[0].vector_type
        self.range = BlockVectorSpace([
            DuneXTVectorSpace(vector_type, subdomain_rt_spaces[ii].size(),
                              'LOCALRT_' + str(ii))
            for ii in self.grid.neighborhood_of(subdomain)
        ], 'RT_{}'.format(subdomain))

    def apply(self, U, mu=None):
        assert U in self.source
        result = self.range.empty(reserve=len(U))
        local_subdomains, num_local_subdomains, num_global_subdomains = _get_subdomains(
            self.grid)
        for u_i in range(len(U)):
            subdomain_uhs_with_global_support = \
                make_discrete_function(
                    self.block_space,
                    self.block_space.project_onto_neighborhood(
                        [U._list[u_i].impl if nn == self.subdomain else
                         Vector(self.block_space.local_space(nn).size(), 0.)
                         for nn in range(num_global_subdomains)],
                        [nn for nn in range(num_global_subdomains)]
                    )
                )

            reconstructed_uh_kk_with_global_support = make_discrete_function(
                self.global_rt_space)
            apply_diffusive_flux_reconstruction_in_neighborhood(
                self.grid, self.subdomain, self.lambda_xi, self.kappa,
                subdomain_uhs_with_global_support,
                reconstructed_uh_kk_with_global_support)

            blocks = [
                s.make_array([
                    self.subdomain_rt_spaces[ii].restrict(
                        reconstructed_uh_kk_with_global_support.vector_copy())
                ])  # NOQA
                for s, ii in zip(self.range.subspaces,
                                 self.grid.neighborhood_of(self.subdomain))
            ]
            result.append(self.range.make_array(blocks))

        return result
コード例 #5
0
ファイル: operators.py プロジェクト: tobiasleibner/pymor
def test_block_identity_lincomb():
    space = NumpyVectorSpace(10)
    space2 = BlockVectorSpace([space, space])
    identity = BlockDiagonalOperator([IdentityOperator(space), IdentityOperator(space)])
    identity2 = IdentityOperator(space2)
    ones = space.ones()
    ones2 = space2.make_array([ones, ones])
    idid = identity + identity2
    assert almost_equal(ones2 * 2, idid.apply(ones2))
    assert almost_equal(ones2 * 2, idid.apply_adjoint(ones2))
    assert almost_equal(ones2 * 0.5, idid.apply_inverse(ones2))
    assert almost_equal(ones2 * 0.5, idid.apply_inverse_adjoint(ones2))
コード例 #6
0
ファイル: block.py プロジェクト: danglive/pymor
    def __init__(self, blocks):
        blocks = np.array(blocks)
        assert 1 <= blocks.ndim <= 2
        if self.blocked_source and self.blocked_range:
            assert blocks.ndim == 2
        elif self.blocked_source:
            if blocks.ndim == 1:
                blocks.shape = (1, len(blocks))
        else:
            if blocks.ndim == 1:
                blocks.shape = (len(blocks), 1)
        self.blocks = blocks
        assert all(
            isinstance(op, OperatorInterface) or op is None
            for op in self._operators())

        # check if every row/column contains at least one operator
        assert all(
            any(blocks[i, j] is not None for j in range(blocks.shape[1]))
            for i in range(blocks.shape[0]))
        assert all(
            any(blocks[i, j] is not None for i in range(blocks.shape[0]))
            for j in range(blocks.shape[1]))

        # find source/range spaces for every column/row
        source_spaces = [None for j in range(blocks.shape[1])]
        range_spaces = [None for i in range(blocks.shape[0])]
        for (i, j), op in np.ndenumerate(blocks):
            if op is not None:
                assert source_spaces[j] is None or op.source == source_spaces[j]
                source_spaces[j] = op.source
                assert range_spaces[i] is None or op.range == range_spaces[i]
                range_spaces[i] = op.range

        # turn Nones to ZeroOperators
        for (i, j) in np.ndindex(blocks.shape):
            if blocks[i, j] is None:
                self.blocks[i, j] = ZeroOperator(range_spaces[i],
                                                 source_spaces[j])

        self.source = BlockVectorSpace(
            source_spaces) if self.blocked_source else source_spaces[0]
        self.range = BlockVectorSpace(
            range_spaces) if self.blocked_range else range_spaces[0]
        self.num_source_blocks = len(source_spaces)
        self.num_range_blocks = len(range_spaces)
        self.linear = all(op.linear for op in self._operators())
        self.build_parameter_type(*self._operators())
コード例 #7
0
def test_blockspace():
    from pymor.vectorarrays.block import BlockVectorSpace, BlockVectorArray
    from pymor.core.pickle import dump, load

    b = BlockVectorSpace([])
    with tempfile.TemporaryFile('wb') as dp_file:
        dump(b, file=dp_file)
コード例 #8
0
    def __init__(self, subdomain, solution_space, grid, block_space,
                 global_rt_space, subdomain_rt_spaces, lambda_xi, kappa):
        self.grid = grid
        self.block_space = block_space
        self.global_rt_space = global_rt_space
        self.subdomain_rt_spaces = subdomain_rt_spaces
        self.subdomain = subdomain
        self.neighborhood = grid.neighborhood_of(subdomain)
        self.lambda_xi = lambda_xi
        self.kappa = kappa

        self.source = solution_space.subspaces[subdomain]
        vector_type = solution_space.subspaces[0].vector_type
        self.range = BlockVectorSpace([
            DuneXTVectorSpace(vector_type, subdomain_rt_spaces[ii].size(),
                              'LOCALRT_' + str(ii))
            for ii in self.grid.neighborhood_of(subdomain)
        ], 'RT_{}'.format(subdomain))
 def __init__(self, *args, **kwargs):
     super().__init__(*args, **kwargs)
     self.range = BlockVectorSpace([self.global_space.subspaces[ii] for ii in self.grid.neighborhood_of(self.jj)],
                                   'OI_{}'.format(self.jj))
     self.source = BlockVectorSpace([self.global_space.subspaces[ii] for ii in self.grid.neighborhood_of(self.kk)],
                                    'OI_{}'.format(self.kk))
     if self.subdomain not in self._matrices:
         matrix = make_local_elliptic_matrix_operator(self.grid, self.subdomain,
                                                      self.block_space.local_space(self.subdomain),
                                                      self.lambda_bar, self.kappa)
         matrix.assemble()
         matrix = matrix.matrix()
         self._matrices[self.subdomain] = DuneXTMatrixOperator(matrix,
                                                               range_id='domain_{}'.format(self.subdomain),
                                                               source_id='domain_{}'.format(self.subdomain))
     self.matrix = self._matrices[self.subdomain]
     self.range_index = self.grid.neighborhood_of(self.jj).index(self.subdomain)
     self.source_index = self.grid.neighborhood_of(self.kk).index(self.subdomain)
コード例 #10
0
ファイル: block.py プロジェクト: tobiasleibner/pymor
    def __init__(self, blocks, source_id='STATE', range_id='STATE'):
        blocks = np.array(blocks)
        assert 1 <= blocks.ndim <= 2
        if self.blocked_source and self.blocked_range:
            assert blocks.ndim == 2
        elif self.blocked_source:
            if blocks.ndim == 1:
                blocks.shape = (1, len(blocks))
        else:
            if blocks.ndim == 1:
                blocks.shape = (len(blocks), 1)
        self._blocks = blocks
        assert all(isinstance(op, OperatorInterface) or op is None for op in self._operators())

        # check if every row/column contains at least one operator
        assert all(any(blocks[i, j] is not None for j in range(blocks.shape[1]))
                   for i in range(blocks.shape[0]))
        assert all(any(blocks[i, j] is not None for i in range(blocks.shape[0]))
                   for j in range(blocks.shape[1]))

        # find source/range spaces for every column/row
        source_spaces = [None for j in range(blocks.shape[1])]
        range_spaces = [None for i in range(blocks.shape[0])]
        for (i, j), op in np.ndenumerate(blocks):
            if op is not None:
                assert source_spaces[j] is None or op.source == source_spaces[j]
                source_spaces[j] = op.source
                assert range_spaces[i] is None or op.range == range_spaces[i]
                range_spaces[i] = op.range

        # turn Nones to ZeroOperators
        for (i, j) in np.ndindex(blocks.shape):
            if blocks[i, j] is None:
                self._blocks[i, j] = ZeroOperator(range_spaces[i], source_spaces[j])

        self.source = BlockVectorSpace(source_spaces, id_=source_id) if self.blocked_source else source_spaces[0]
        self.range = BlockVectorSpace(range_spaces, id_=range_id) if self.blocked_range else range_spaces[0]
        self.num_source_blocks = len(source_spaces)
        self.num_range_blocks = len(range_spaces)
        self.linear = all(op.linear for op in self._operators())
        self.build_parameter_type(*self._operators())
class OswaldInterpolationErrorOperator(EstimatorOperatorBase):

    def __init__(self, *args, **kwargs):
        super().__init__(*args, **kwargs)
        assert self.subdomain == self.kk == self.jj
        self.range = BlockVectorSpace([self.global_space.subspaces[ii] for ii in self.neighborhood],
                                      'OI_{}'.format(self.subdomain))

    def _apply(self, U, mu=None):
        from dune.gdt import apply_oswald_interpolation_operator

        assert len(U) == 1
        assert U in self.source

        result = self.range.zeros()
        result._blocks[self.neighborhood.index(self.subdomain)].axpy(1, U)

        for i_ii, ii in enumerate(self.neighborhood):
            ii_neighborhood = self.grid.neighborhood_of(ii)
            ii_neighborhood_space = self.block_space.restricted_to_neighborhood(ii_neighborhood)

            subdomain_uh_with_neighborhood_support = make_discrete_function(
                ii_neighborhood_space,
                ii_neighborhood_space.project_onto_neighborhood(
                    [U._list[0].impl if nn == self.subdomain else Vector(self.block_space.local_space(nn).size(), 0.)
                     for nn in ii_neighborhood],
                    ii_neighborhood
                )
            )

            interpolated_u_vector = ii_neighborhood_space.project_onto_neighborhood(
                [Vector(self.block_space.local_space(nn).size(), 0.) for nn in ii_neighborhood], ii_neighborhood)
            interpolated_u = make_discrete_function(ii_neighborhood_space, interpolated_u_vector)

            apply_oswald_interpolation_operator(
                self.grid, ii,
                make_subdomain_boundary_info(self.grid, {'type': 'xt.grid.boundaryinfo.alldirichlet'}),
                subdomain_uh_with_neighborhood_support,
                interpolated_u
            )

            local_sizes = np.array([ii_neighborhood_space.local_space(nn).size() for nn in ii_neighborhood])
            offsets = np.hstack(([0], np.cumsum(local_sizes)))
            ind = ii_neighborhood.index(ii)
            result._blocks[i_ii]._list[0].data[:] -= np.frombuffer(interpolated_u_vector)[offsets[ind]:offsets[ind+1]]

        return result
コード例 #12
0
ファイル: block.py プロジェクト: prklVIP/pymor
def test_blk_diag_apply_inverse_adjoint():
    np.random.seed(0)

    A = np.random.randn(2, 2)
    B = np.random.randn(3, 3)
    C = spla.block_diag(A, B)
    Aop = NumpyMatrixOperator(A)
    Bop = NumpyMatrixOperator(B)
    Cop = BlockDiagonalOperator((Aop, Bop))

    v1 = np.random.randn(2)
    v2 = np.random.randn(3)
    v = np.hstack((v1, v2))
    v1va = NumpyVectorSpace.from_numpy(v1)
    v2va = NumpyVectorSpace.from_numpy(v2)
    vva = BlockVectorSpace.make_array((v1va, v2va))

    wva = Cop.apply_inverse_adjoint(vva)
    w = np.hstack((wva.block(0).to_numpy(), wva.block(1).to_numpy()))
    assert np.allclose(spla.solve(C.T, v), w)
コード例 #13
0
def test_blk_diag_apply_inverse():
    np.random.seed(0)

    A = np.random.randn(2, 2)
    B = np.random.randn(3, 3)
    C = spla.block_diag(A, B)
    Aop = NumpyMatrixOperator(A)
    Bop = NumpyMatrixOperator(B)
    Cop = BlockDiagonalOperator((Aop, Bop))

    v1 = np.random.randn(2)
    v2 = np.random.randn(3)
    v = np.hstack((v1, v2))
    v1va = NumpyVectorSpace.from_data(v1)
    v2va = NumpyVectorSpace.from_data(v2)
    vva = BlockVectorSpace.make_array((v1va, v2va))

    wva = Cop.apply_inverse(vva)
    w = np.hstack((wva.block(0).data, wva.block(1).data))
    assert np.allclose(spla.solve(C, v), w)
コード例 #14
0
ファイル: block.py プロジェクト: prklVIP/pymor
def test_apply_adjoint():
    np.random.seed(0)

    A11 = np.random.randn(2, 3)
    A12 = np.random.randn(2, 4)
    A21 = np.zeros((5, 3))
    A22 = np.random.randn(5, 4)
    A = np.vstack((np.hstack((A11, A12)), np.hstack((A21, A22))))
    A11op = NumpyMatrixOperator(A11)
    A12op = NumpyMatrixOperator(A12)
    A22op = NumpyMatrixOperator(A22)
    Aop = BlockOperator(np.array([[A11op, A12op], [None, A22op]]))

    v1 = np.random.randn(2)
    v2 = np.random.randn(5)
    v = np.hstack((v1, v2))
    v1va = NumpyVectorSpace.from_numpy(v1)
    v2va = NumpyVectorSpace.from_numpy(v2)
    vva = BlockVectorSpace.make_array((v1va, v2va))

    wva = Aop.apply_adjoint(vva)
    w = np.hstack((wva.block(0).to_numpy(), wva.block(1).to_numpy()))
    assert np.allclose(A.T.dot(v), w)
コード例 #15
0
def _block_vector_spaces(draw, np_data_list, compatible, count, dims):
    ret = []
    rr = draw(hyst.randoms())

    def _block_dims(d):
        bd = []
        while d > 1:
            block_size = rr.randint(1, d)
            bd.append(block_size)
            d -= block_size
        if d > 0:
            bd.append(d)
        return bd

    for c, (d, ar) in enumerate(zip(dims, np_data_list)):
        # only redraw after initial for (potentially) incompatible arrays
        if c == 0 or (not compatible and c > 0):
            block_dims = _block_dims(d)
        constituent_spaces = [NumpyVectorSpace(dim) for dim in block_dims]
        # TODO this needs to be relaxed again
        assume(len(constituent_spaces))
        ret.append((BlockVectorSpace(constituent_spaces), ar))
    return ret
コード例 #16
0
def test_apply_transpose():
    np.random.seed(0)

    A11 = np.random.randn(2, 3)
    A12 = np.random.randn(2, 4)
    A21 = np.zeros((5, 3))
    A22 = np.random.randn(5, 4)
    A = np.vstack((np.hstack((A11, A12)),
                   np.hstack((A21, A22))))
    A11op = NumpyMatrixOperator(A11)
    A12op = NumpyMatrixOperator(A12)
    A22op = NumpyMatrixOperator(A22)
    Aop = BlockOperator(np.array([[A11op, A12op], [None, A22op]]))

    v1 = np.random.randn(2)
    v2 = np.random.randn(5)
    v = np.hstack((v1, v2))
    v1va = NumpyVectorSpace.from_data(v1)
    v2va = NumpyVectorSpace.from_data(v2)
    vva = BlockVectorSpace.make_array((v1va, v2va))

    wva = Aop.apply_transpose(vva)
    w = np.hstack((wva.block(0).data, wva.block(1).data))
    assert np.allclose(A.T.dot(v), w)
コード例 #17
0
ファイル: block.py プロジェクト: pymor/pymor
class BlockOperatorBase(OperatorBase):

    def _operators(self):
        """Iterator over operators."""
        for (i, j) in np.ndindex(self._blocks.shape):
            yield self._blocks[i, j]

    def __init__(self, blocks):
        blocks = np.array(blocks)
        assert 1 <= blocks.ndim <= 2
        if self.blocked_source and self.blocked_range:
            assert blocks.ndim == 2
        elif self.blocked_source:
            if blocks.ndim == 1:
                blocks.shape = (1, len(blocks))
        else:
            if blocks.ndim == 1:
                blocks.shape = (len(blocks), 1)
        self._blocks = blocks
        assert all(isinstance(op, OperatorInterface) or op is None for op in self._operators())

        # check if every row/column contains at least one operator
        assert all(any(blocks[i, j] is not None for j in range(blocks.shape[1]))
                   for i in range(blocks.shape[0]))
        assert all(any(blocks[i, j] is not None for i in range(blocks.shape[0]))
                   for j in range(blocks.shape[1]))

        # find source/range spaces for every column/row
        source_spaces = [None for j in range(blocks.shape[1])]
        range_spaces = [None for i in range(blocks.shape[0])]
        for (i, j), op in np.ndenumerate(blocks):
            if op is not None:
                assert source_spaces[j] is None or op.source == source_spaces[j]
                source_spaces[j] = op.source
                assert range_spaces[i] is None or op.range == range_spaces[i]
                range_spaces[i] = op.range

        # turn Nones to ZeroOperators
        for (i, j) in np.ndindex(blocks.shape):
            if blocks[i, j] is None:
                self._blocks[i, j] = ZeroOperator(range_spaces[i], source_spaces[j])

        self.source = BlockVectorSpace(source_spaces) if self.blocked_source else source_spaces[0]
        self.range = BlockVectorSpace(range_spaces) if self.blocked_range else range_spaces[0]
        self.num_source_blocks = len(source_spaces)
        self.num_range_blocks = len(range_spaces)
        self.linear = all(op.linear for op in self._operators())
        self.build_parameter_type(*self._operators())

    @property
    def H(self):
        return self.adjoint_type(np.vectorize(lambda op: op.H if op else None)(self._blocks.T))

    def apply(self, U, mu=None):
        assert U in self.source

        V_blocks = [None for i in range(self.num_range_blocks)]
        for (i, j), op in np.ndenumerate(self._blocks):
            Vi = op.apply(U.block(j) if self.blocked_source else U, mu=mu)
            if V_blocks[i] is None:
                V_blocks[i] = Vi
            else:
                V_blocks[i] += Vi

        return self.range.make_array(V_blocks) if self.blocked_range else V_blocks[0]

    def apply_adjoint(self, V, mu=None):
        assert V in self.range

        U_blocks = [None for j in range(self.num_source_blocks)]
        for (i, j), op in np.ndenumerate(self._blocks):
            Uj = op.apply_adjoint(V.block(i) if self.blocked_range else V, mu=mu)
            if U_blocks[j] is None:
                U_blocks[j] = Uj
            else:
                U_blocks[j] += Uj

        return self.source.make_array(U_blocks) if self.blocked_source else U_blocks[0]

    def assemble(self, mu=None):
        blocks = np.empty(self._blocks.shape, dtype=object)
        for (i, j) in np.ndindex(self._blocks.shape):
            blocks[i, j] = self._blocks[i, j].assemble(mu)
        if np.all(blocks == self._blocks):
            return self
        else:
            return self.__class__(blocks)

    def as_range_array(self, mu=None):

        def process_row(row, space):
            R = space.empty()
            for op in row:
                if op is not None:
                    R.append(op.as_range_array(mu))
            return R

        subspaces = self.range.subspaces if self.blocked_range else [self.range]
        blocks = [process_row(row, space) for row, space in zip(self._blocks, subspaces)]
        return self.range.make_array(blocks) if self.blocked_range else blocks[0]

    def as_source_array(self, mu=None):

        def process_col(col, space):
            R = space.empty()
            for op in col:
                if op is not None:
                    R.append(op.as_source_array(mu))
            return R

        subspaces = self.source.subspaces if self.blocked_source else [self.source]
        blocks = [process_col(col, space) for col, space in zip(self._blocks.T, subspaces)]
        return self.source.make_array(blocks) if self.blocked_source else blocks[0]
コード例 #18
0
def block_vector_array_factory(length, dims, seed):
    return BlockVectorSpace(
        [NumpyVectorSpace(dim) for dim in dims]).from_numpy(
            numpy_vector_array_factory(length, sum(dims), seed).to_numpy())
コード例 #19
0
class BlockOperator(OperatorBase):
    """A matrix of arbitrary |Operators|.

    This operator can be :meth:`applied <pymor.operators.interfaces.OperatorInterface.apply>`
    to a compatible :class:`BlockVectorArrays <pymor.vectorarrays.block.BlockVectorArray>`.

    Parameters
    ----------
    blocks
        Two-dimensional array-like where each entry is an |Operator| or `None`.
    """
    def _operators(self):
        """Iterator over operators."""
        for (i, j) in np.ndindex(self._blocks.shape):
            yield self._blocks[i, j]

    def __init__(self, blocks):
        blocks = np.array(blocks)
        assert isinstance(blocks, np.ndarray) and blocks.ndim == 2
        self._blocks = blocks
        assert all(
            isinstance(op, OperatorInterface) or op is None
            for op in self._operators())

        # check if every row/column contains at least one operator
        assert all(
            any(blocks[i, j] is not None for j in range(blocks.shape[1]))
            for i in range(blocks.shape[0]))
        assert all(
            any(blocks[i, j] is not None for i in range(blocks.shape[0]))
            for j in range(blocks.shape[1]))

        # find source/range types for every column/row
        source_types = [None for j in range(blocks.shape[1])]
        range_types = [None for i in range(blocks.shape[0])]
        for (i, j), op in np.ndenumerate(blocks):
            if op is not None:
                assert source_types[j] is None or op.source == source_types[j]
                source_types[j] = op.source
                assert range_types[i] is None or op.range == range_types[i]
                range_types[i] = op.range

        # turn Nones to ZeroOperators
        for (i, j) in np.ndindex(blocks.shape):
            if blocks[i, j] is None:
                self._blocks[i, j] = ZeroOperator(source_types[j],
                                                  range_types[i])

        self.source = BlockVectorSpace(source_types)
        self.range = BlockVectorSpace(range_types)
        self.num_source_blocks = len(source_types)
        self.num_range_blocks = len(range_types)
        self.linear = all(op.linear for op in self._operators())
        self.build_parameter_type(*self._operators())

    @property
    def T(self):
        return type(self)(np.vectorize(lambda op: op.T if op else None)(
            self._blocks.T))

    @classmethod
    def hstack(cls, operators):
        """Horizontal stacking of |Operators|.

        Parameters
        ----------
        operators
            An iterable where each item is an |Operator| or `None`.
        """
        blocks = np.array([[op for op in operators]])
        return cls(blocks)

    @classmethod
    def vstack(cls, operators):
        """Vertical stacking of |Operators|.

        Parameters
        ----------
        operators
            An iterable where each item is an |Operator| or `None`.
        """
        blocks = np.array([[op] for op in operators])
        return cls(blocks)

    def apply(self, U, mu=None):
        assert U in self.source

        V_blocks = [None for i in range(self.num_range_blocks)]
        for (i, j), op in np.ndenumerate(self._blocks):
            Vi = op.apply(U.block(j), mu=mu)
            if V_blocks[i] is None:
                V_blocks[i] = Vi
            else:
                V_blocks[i] += Vi

        return self.range.make_array(V_blocks)

    def apply_transpose(self, V, mu=None):
        assert V in self.range

        U_blocks = [None for j in range(self.num_source_blocks)]
        for (i, j), op in np.ndenumerate(self._blocks):
            Uj = op.apply_transpose(V.block(i), mu=mu)
            if U_blocks[j] is None:
                U_blocks[j] = Uj
            else:
                U_blocks[j] += Uj

        U = self.source.make_array(U_blocks)

        return U

    def assemble(self, mu=None):
        blocks = np.empty(self._blocks.shape, dtype=object)
        for (i, j) in np.ndindex(self._blocks.shape):
            blocks[i, j] = self._blocks[i, j].assemble(mu)
        if np.all(blocks == self._blocks):
            return self
        else:
            return self.__class__(blocks)

    def assemble_lincomb(self,
                         operators,
                         coefficients,
                         solver_options=None,
                         name=None):
        assert operators[0] is self
        blocks = np.empty(self._blocks.shape, dtype=object)
        if len(operators) > 1:
            for (i, j) in np.ndindex(self._blocks.shape):
                operators_ij = [op._blocks[i, j] for op in operators]
                blocks[i, j] = operators_ij[0].assemble_lincomb(
                    operators_ij,
                    coefficients,
                    solver_options=solver_options,
                    name=name)
                if blocks[i, j] is None:
                    return None
            return self.__class__(blocks)
        else:
            c = coefficients[0]
            if c == 1:
                return self
            for (i, j) in np.ndindex(self._blocks.shape):
                blocks[i, j] = self._blocks[i, j] * c
            return self.__class__(blocks)
コード例 #20
0
ファイル: block.py プロジェクト: tobiasleibner/pymor
class BlockOperatorBase(OperatorBase):

    def _operators(self):
        """Iterator over operators."""
        for (i, j) in np.ndindex(self._blocks.shape):
            yield self._blocks[i, j]

    def __init__(self, blocks, source_id='STATE', range_id='STATE'):
        blocks = np.array(blocks)
        assert 1 <= blocks.ndim <= 2
        if self.blocked_source and self.blocked_range:
            assert blocks.ndim == 2
        elif self.blocked_source:
            if blocks.ndim == 1:
                blocks.shape = (1, len(blocks))
        else:
            if blocks.ndim == 1:
                blocks.shape = (len(blocks), 1)
        self._blocks = blocks
        assert all(isinstance(op, OperatorInterface) or op is None for op in self._operators())

        # check if every row/column contains at least one operator
        assert all(any(blocks[i, j] is not None for j in range(blocks.shape[1]))
                   for i in range(blocks.shape[0]))
        assert all(any(blocks[i, j] is not None for i in range(blocks.shape[0]))
                   for j in range(blocks.shape[1]))

        # find source/range spaces for every column/row
        source_spaces = [None for j in range(blocks.shape[1])]
        range_spaces = [None for i in range(blocks.shape[0])]
        for (i, j), op in np.ndenumerate(blocks):
            if op is not None:
                assert source_spaces[j] is None or op.source == source_spaces[j]
                source_spaces[j] = op.source
                assert range_spaces[i] is None or op.range == range_spaces[i]
                range_spaces[i] = op.range

        # turn Nones to ZeroOperators
        for (i, j) in np.ndindex(blocks.shape):
            if blocks[i, j] is None:
                self._blocks[i, j] = ZeroOperator(range_spaces[i], source_spaces[j])

        self.source = BlockVectorSpace(source_spaces, id_=source_id) if self.blocked_source else source_spaces[0]
        self.range = BlockVectorSpace(range_spaces, id_=range_id) if self.blocked_range else range_spaces[0]
        self.num_source_blocks = len(source_spaces)
        self.num_range_blocks = len(range_spaces)
        self.linear = all(op.linear for op in self._operators())
        self.build_parameter_type(*self._operators())

    @property
    def H(self):
        return self.adjoint_type(np.vectorize(lambda op: op.H if op else None)(self._blocks.T))

    def apply(self, U, mu=None):
        assert U in self.source

        V_blocks = [None for i in range(self.num_range_blocks)]
        for (i, j), op in np.ndenumerate(self._blocks):
            Vi = op.apply(U.block(j) if self.blocked_source else U, mu=mu)
            if V_blocks[i] is None:
                V_blocks[i] = Vi
            else:
                V_blocks[i] += Vi

        return self.range.make_array(V_blocks) if self.blocked_range else V_blocks[0]

    def apply_adjoint(self, V, mu=None):
        assert V in self.range

        U_blocks = [None for j in range(self.num_source_blocks)]
        for (i, j), op in np.ndenumerate(self._blocks):
            Uj = op.apply_adjoint(V.block(i) if self.blocked_range else V, mu=mu)
            if U_blocks[j] is None:
                U_blocks[j] = Uj
            else:
                U_blocks[j] += Uj

        return self.source.make_array(U_blocks) if self.blocked_source else U_blocks[0]

    def assemble(self, mu=None):
        blocks = np.empty(self._blocks.shape, dtype=object)
        for (i, j) in np.ndindex(self._blocks.shape):
            blocks[i, j] = self._blocks[i, j].assemble(mu)
        if np.all(blocks == self._blocks):
            return self
        else:
            return self.__class__(blocks)

    def _assemble_lincomb_preprocess_operators(self, operators):
        return [
            BlockDiagonalOperator([IdentityOperator(s) for s in op.source.subspaces],
                                  source_id=op.source.id, range_id=op.range.id) if isinstance(op, IdentityOperator) else
            op
            for op in operators if not isinstance(op, ZeroOperator)
        ]

    def assemble_lincomb(self, operators, coefficients, solver_options=None, name=None):

        operators = self._assemble_lincomb_preprocess_operators(operators)

        if not all(isinstance(op, BlockOperatorBase) for op in operators):
            return None

        assert operators[0] is self
        blocks = np.empty(self._blocks.shape, dtype=object)
        if len(operators) > 1:
            for (i, j) in np.ndindex(self._blocks.shape):
                operators_ij = [op._blocks[i, j] for op in operators]
                blocks[i, j] = operators_ij[0].assemble_lincomb(operators_ij, coefficients,
                                                                solver_options=solver_options, name=name)
                if blocks[i, j] is None:
                    return None
            return self.__class__(blocks)
        else:
            c = coefficients[0]
            if c == 1:
                return self
            for (i, j) in np.ndindex(self._blocks.shape):
                blocks[i, j] = self._blocks[i, j] * c
            return self.__class__(blocks)

    def as_range_array(self, mu=None):

        def process_row(row, space):
            R = space.empty()
            for op in row:
                if op is not None:
                    R.append(op.as_range_array(mu))
            return R

        blocks = [process_row(row, space) for row, space in zip(self._blocks, self.range.subspaces)]
        return self.range.make_array(blocks) if self.blocked_range else blocks[0]

    def as_source_array(self, mu=None):

        def process_col(col, space):
            R = space.empty()
            for op in col:
                if op is not None:
                    R.append(op.as_source_array(mu))
            return R

        blocks = [process_col(col, space) for col, space in zip(self._blocks.T, self.source.subspaces)]
        return self.source.make_array(blocks) if self.blocked_source else blocks[0]
コード例 #21
0
ファイル: block.py プロジェクト: renemilk/pyMor
class BlockOperator(OperatorBase):
    """A matrix of arbitrary |Operators|.

    This operator can be :meth:`applied <pymor.operators.interfaces.OperatorInterface.apply>`
    to a compatible :class:`BlockVectorArrays <pymor.vectorarrays.block.BlockVectorArray>`.

    Parameters
    ----------
    blocks
        Two-dimensional array-like where each entry is an |Operator| or `None`.
    """

    def _operators(self):
        """Iterator over operators."""
        for (i, j) in np.ndindex(self._blocks.shape):
            yield self._blocks[i, j]

    def __init__(self, blocks):
        blocks = np.array(blocks)
        assert isinstance(blocks, np.ndarray) and blocks.ndim == 2
        self._blocks = blocks
        assert all(isinstance(op, OperatorInterface) or op is None for op in self._operators())

        # check if every row/column contains at least one operator
        assert all(any(blocks[i, j] is not None for j in range(blocks.shape[1]))
                   for i in range(blocks.shape[0]))
        assert all(any(blocks[i, j] is not None for i in range(blocks.shape[0]))
                   for j in range(blocks.shape[1]))

        # find source/range types for every column/row
        source_types = [None for j in range(blocks.shape[1])]
        range_types = [None for i in range(blocks.shape[0])]
        for (i, j), op in np.ndenumerate(blocks):
            if op is not None:
                assert source_types[j] is None or op.source == source_types[j]
                source_types[j] = op.source
                assert range_types[i] is None or op.range == range_types[i]
                range_types[i] = op.range

        # turn Nones to ZeroOperators
        for (i, j) in np.ndindex(blocks.shape):
            if blocks[i, j] is None:
                self._blocks[i, j] = ZeroOperator(range_types[i], source_types[j])

        self.source = BlockVectorSpace(source_types)
        self.range = BlockVectorSpace(range_types)
        self.num_source_blocks = len(source_types)
        self.num_range_blocks = len(range_types)
        self.linear = all(op.linear for op in self._operators())
        self.build_parameter_type(*self._operators())

    @property
    def T(self):
        return type(self)(np.vectorize(lambda op: op.T if op else None)(self._blocks.T))

    @classmethod
    def hstack(cls, operators):
        """Horizontal stacking of |Operators|.

        Parameters
        ----------
        operators
            An iterable where each item is an |Operator| or `None`.
        """
        blocks = np.array([[op for op in operators]])
        return cls(blocks)

    @classmethod
    def vstack(cls, operators):
        """Vertical stacking of |Operators|.

        Parameters
        ----------
        operators
            An iterable where each item is an |Operator| or `None`.
        """
        blocks = np.array([[op] for op in operators])
        return cls(blocks)

    def apply(self, U, mu=None):
        assert U in self.source

        V_blocks = [None for i in range(self.num_range_blocks)]
        for (i, j), op in np.ndenumerate(self._blocks):
            Vi = op.apply(U.block(j), mu=mu)
            if V_blocks[i] is None:
                V_blocks[i] = Vi
            else:
                V_blocks[i] += Vi

        return self.range.make_array(V_blocks)

    def apply_transpose(self, V, mu=None):
        assert V in self.range

        U_blocks = [None for j in range(self.num_source_blocks)]
        for (i, j), op in np.ndenumerate(self._blocks):
            Uj = op.apply_transpose(V.block(i), mu=mu)
            if U_blocks[j] is None:
                U_blocks[j] = Uj
            else:
                U_blocks[j] += Uj

        U = self.source.make_array(U_blocks)

        return U

    def assemble(self, mu=None):
        blocks = np.empty(self._blocks.shape, dtype=object)
        for (i, j) in np.ndindex(self._blocks.shape):
            blocks[i, j] = self._blocks[i, j].assemble(mu)
        if np.all(blocks == self._blocks):
            return self
        else:
            return self.__class__(blocks)

    def assemble_lincomb(self, operators, coefficients, solver_options=None, name=None):
        assert operators[0] is self
        blocks = np.empty(self._blocks.shape, dtype=object)
        if len(operators) > 1:
            for (i, j) in np.ndindex(self._blocks.shape):
                operators_ij = [op._blocks[i, j] for op in operators]
                blocks[i, j] = operators_ij[0].assemble_lincomb(operators_ij, coefficients,
                                                                solver_options=solver_options, name=name)
                if blocks[i, j] is None:
                    return None
            return self.__class__(blocks)
        else:
            c = coefficients[0]
            if c == 1:
                return self
            for (i, j) in np.ndindex(self._blocks.shape):
                blocks[i, j] = self._blocks[i, j] * c
            return self.__class__(blocks)
 def __init__(self, *args, **kwargs):
     super().__init__(*args, **kwargs)
     assert self.subdomain == self.kk == self.jj
     self.range = BlockVectorSpace([self.global_space.subspaces[ii] for ii in self.neighborhood],
                                   'OI_{}'.format(self.subdomain))
コード例 #23
0
ファイル: block.py プロジェクト: danglive/pymor
class BlockOperatorBase(OperatorBase):
    def _operators(self):
        """Iterator over operators."""
        for (i, j) in np.ndindex(self.blocks.shape):
            yield self.blocks[i, j]

    def __init__(self, blocks):
        blocks = np.array(blocks)
        assert 1 <= blocks.ndim <= 2
        if self.blocked_source and self.blocked_range:
            assert blocks.ndim == 2
        elif self.blocked_source:
            if blocks.ndim == 1:
                blocks.shape = (1, len(blocks))
        else:
            if blocks.ndim == 1:
                blocks.shape = (len(blocks), 1)
        self.blocks = blocks
        assert all(
            isinstance(op, OperatorInterface) or op is None
            for op in self._operators())

        # check if every row/column contains at least one operator
        assert all(
            any(blocks[i, j] is not None for j in range(blocks.shape[1]))
            for i in range(blocks.shape[0]))
        assert all(
            any(blocks[i, j] is not None for i in range(blocks.shape[0]))
            for j in range(blocks.shape[1]))

        # find source/range spaces for every column/row
        source_spaces = [None for j in range(blocks.shape[1])]
        range_spaces = [None for i in range(blocks.shape[0])]
        for (i, j), op in np.ndenumerate(blocks):
            if op is not None:
                assert source_spaces[j] is None or op.source == source_spaces[j]
                source_spaces[j] = op.source
                assert range_spaces[i] is None or op.range == range_spaces[i]
                range_spaces[i] = op.range

        # turn Nones to ZeroOperators
        for (i, j) in np.ndindex(blocks.shape):
            if blocks[i, j] is None:
                self.blocks[i, j] = ZeroOperator(range_spaces[i],
                                                 source_spaces[j])

        self.source = BlockVectorSpace(
            source_spaces) if self.blocked_source else source_spaces[0]
        self.range = BlockVectorSpace(
            range_spaces) if self.blocked_range else range_spaces[0]
        self.num_source_blocks = len(source_spaces)
        self.num_range_blocks = len(range_spaces)
        self.linear = all(op.linear for op in self._operators())
        self.build_parameter_type(*self._operators())

    @property
    def H(self):
        return self.adjoint_type(
            np.vectorize(lambda op: op.H if op else None)(self.blocks.T))

    def apply(self, U, mu=None):
        assert U in self.source

        V_blocks = [None for i in range(self.num_range_blocks)]
        for (i, j), op in np.ndenumerate(self.blocks):
            Vi = op.apply(U.block(j) if self.blocked_source else U, mu=mu)
            if V_blocks[i] is None:
                V_blocks[i] = Vi
            else:
                V_blocks[i] += Vi

        return self.range.make_array(
            V_blocks) if self.blocked_range else V_blocks[0]

    def apply_adjoint(self, V, mu=None):
        assert V in self.range

        U_blocks = [None for j in range(self.num_source_blocks)]
        for (i, j), op in np.ndenumerate(self.blocks):
            Uj = op.apply_adjoint(V.block(i) if self.blocked_range else V,
                                  mu=mu)
            if U_blocks[j] is None:
                U_blocks[j] = Uj
            else:
                U_blocks[j] += Uj

        return self.source.make_array(
            U_blocks) if self.blocked_source else U_blocks[0]

    def assemble(self, mu=None):
        blocks = np.empty(self.blocks.shape, dtype=object)
        for (i, j) in np.ndindex(self.blocks.shape):
            blocks[i, j] = self.blocks[i, j].assemble(mu)
        if np.all(blocks == self.blocks):
            return self
        else:
            return self.__class__(blocks)

    def as_range_array(self, mu=None):
        def process_row(row, space):
            R = space.empty()
            for op in row:
                if op is not None:
                    R.append(op.as_range_array(mu))
            return R

        subspaces = self.range.subspaces if self.blocked_range else [
            self.range
        ]
        blocks = [
            process_row(row, space)
            for row, space in zip(self.blocks, subspaces)
        ]
        return self.range.make_array(
            blocks) if self.blocked_range else blocks[0]

    def as_source_array(self, mu=None):
        def process_col(col, space):
            R = space.empty()
            for op in col:
                if op is not None:
                    R.append(op.as_source_array(mu))
            return R

        subspaces = self.source.subspaces if self.blocked_source else [
            self.source
        ]
        blocks = [
            process_col(col, space)
            for col, space in zip(self.blocks.T, subspaces)
        ]
        return self.source.make_array(
            blocks) if self.blocked_source else blocks[0]
コード例 #24
0
ファイル: block.py プロジェクト: prklVIP/pymor
class BlockOperatorBase(OperatorBase):

    def _operators(self):
        """Iterator over operators."""
        for (i, j) in np.ndindex(self._blocks.shape):
            yield self._blocks[i, j]

    def __init__(self, blocks, source_id='STATE', range_id='STATE'):
        blocks = np.array(blocks)
        assert 1 <= blocks.ndim <= 2
        if self.blocked_source and self.blocked_range:
            assert blocks.ndim == 2
        elif self.blocked_source:
            if blocks.ndim == 1:
                blocks.shape = (1, len(blocks))
        else:
            if blocks.ndim == 1:
                blocks.shape = (len(blocks), 1)
        self._blocks = blocks
        assert all(isinstance(op, OperatorInterface) or op is None for op in self._operators())

        # check if every row/column contains at least one operator
        assert all(any(blocks[i, j] is not None for j in range(blocks.shape[1]))
                   for i in range(blocks.shape[0]))
        assert all(any(blocks[i, j] is not None for i in range(blocks.shape[0]))
                   for j in range(blocks.shape[1]))

        # find source/range spaces for every column/row
        source_spaces = [None for j in range(blocks.shape[1])]
        range_spaces = [None for i in range(blocks.shape[0])]
        for (i, j), op in np.ndenumerate(blocks):
            if op is not None:
                assert source_spaces[j] is None or op.source == source_spaces[j]
                source_spaces[j] = op.source
                assert range_spaces[i] is None or op.range == range_spaces[i]
                range_spaces[i] = op.range

        # turn Nones to ZeroOperators
        for (i, j) in np.ndindex(blocks.shape):
            if blocks[i, j] is None:
                self._blocks[i, j] = ZeroOperator(range_spaces[i], source_spaces[j])

        self.source = BlockVectorSpace(source_spaces, id_=source_id) if self.blocked_source else source_spaces[0]
        self.range = BlockVectorSpace(range_spaces, id_=range_id) if self.blocked_range else range_spaces[0]
        self.num_source_blocks = len(source_spaces)
        self.num_range_blocks = len(range_spaces)
        self.linear = all(op.linear for op in self._operators())
        self.build_parameter_type(*self._operators())

    @property
    def H(self):
        return self.adjoint_type(np.vectorize(lambda op: op.H if op else None)(self._blocks.T))

    def apply(self, U, mu=None):
        assert U in self.source

        V_blocks = [None for i in range(self.num_range_blocks)]
        for (i, j), op in np.ndenumerate(self._blocks):
            Vi = op.apply(U.block(j) if self.blocked_source else U, mu=mu)
            if V_blocks[i] is None:
                V_blocks[i] = Vi
            else:
                V_blocks[i] += Vi

        return self.range.make_array(V_blocks) if self.blocked_range else V_blocks[0]

    def apply_adjoint(self, V, mu=None):
        assert V in self.range

        U_blocks = [None for j in range(self.num_source_blocks)]
        for (i, j), op in np.ndenumerate(self._blocks):
            Uj = op.apply_adjoint(V.block(i) if self.blocked_range else V, mu=mu)
            if U_blocks[j] is None:
                U_blocks[j] = Uj
            else:
                U_blocks[j] += Uj

        return self.source.make_array(U_blocks) if self.blocked_source else U_blocks[0]

    def assemble(self, mu=None):
        blocks = np.empty(self._blocks.shape, dtype=object)
        for (i, j) in np.ndindex(self._blocks.shape):
            blocks[i, j] = self._blocks[i, j].assemble(mu)
        if np.all(blocks == self._blocks):
            return self
        else:
            return self.__class__(blocks)

    def _assemble_lincomb_preprocess_operators(self, operators):
        return [
            BlockDiagonalOperator([IdentityOperator(s) for s in op.source.subspaces],
                                  source_id=op.source.id, range_id=op.range.id) if isinstance(op, IdentityOperator) else
            op
            for op in operators if not isinstance(op, ZeroOperator)
        ]

    def assemble_lincomb(self, operators, coefficients, solver_options=None, name=None):

        operators = self._assemble_lincomb_preprocess_operators(operators)

        if not all(isinstance(op, BlockOperatorBase) for op in operators):
            return None

        assert operators[0] is self
        blocks = np.empty(self._blocks.shape, dtype=object)
        if len(operators) > 1:
            for (i, j) in np.ndindex(self._blocks.shape):
                operators_ij = [op._blocks[i, j] for op in operators]
                blocks[i, j] = operators_ij[0].assemble_lincomb(operators_ij, coefficients,
                                                                solver_options=solver_options, name=name)
                if blocks[i, j] is None:
                    return None
            return self.__class__(blocks)
        else:
            c = coefficients[0]
            if c == 1:
                return self
            for (i, j) in np.ndindex(self._blocks.shape):
                blocks[i, j] = self._blocks[i, j] * c
            return self.__class__(blocks)

    def as_range_array(self, mu=None):

        def process_row(row, space):
            R = space.empty()
            for op in row:
                if op is not None:
                    R.append(op.as_range_array(mu))
            return R

        blocks = [process_row(row, space) for row, space in zip(self._blocks, self.range.subspaces)]
        return self.range.make_array(blocks) if self.blocked_range else blocks[0]

    def as_source_array(self, mu=None):

        def process_col(col, space):
            R = space.empty()
            for op in col:
                if op is not None:
                    R.append(op.as_source_array(mu))
            return R

        blocks = [process_col(col, space) for col, space in zip(self._blocks.T, self.source.subspaces)]
        return self.source.make_array(blocks) if self.blocked_source else blocks[0]