code: def Satisfy_Constraints(U, B, BtBinv):
      
      RowsPerBlock = U.blocksize[0]
      ColsPerBlock = U.blocksize[1]
      num_block_rows = int(U.shape[0]/RowsPerBlock)
  
      UB = np.ravel(U*B)
  
      # Apply constraints, noting that we need the conjugate of B
      # for use as Bi.H in local projection
      pyamg.amg_core.satisfy_constraints_helper(RowsPerBlock, ColsPerBlock,
                                                num_block_rows, B.shape[1],
                                                np.conjugate(np.ravel(B)),
                                                UB, np.ravel(BtBinv),
                                                U.indptr, U.indices,
                                                np.ravel(U.data))
  
      return U
docs: U is the prolongator update.  Project out components of U such that U*B = 0.
  
      Parameters
      ----------
      U : bsr_matrix
          m x n sparse bsr matrix
          Update to the prolongator
      B : array
          n x k array of the coarse grid near nullspace vectors
      BtBinv : array
          Local inv(B_i.H*B_i) matrices for each supernode, i
          B_i is B restricted to the sparsity pattern of supernode i in U
  
      Returns
      -------
      Updated U, so that U*B = 0.
      Update is computed by orthogonally (in 2-norm) projecting
      out the components of span(B) in U in a row-wise fashion.
  
      See Also
      --------
      The principal calling routine,
      pyamg.aggregation.smooth.energy_prolongation_smoother