code: def build_constraints(self, coefs, constraint_lam, constraint_l2):
          
          C = []
          for i, term in enumerate(self._terms):
              idxs = self.get_coef_indices(i=i)
              C.append(term.build_constraints(coefs[idxs], constraint_lam, constraint_l2))
          return sp.sparse.block_diag(C)
docs: builds the GAM block-diagonal constraint matrix in quadratic form
          out of constraint matrices specified for each feature.
  
          behaves like a penalty, but with a very large lambda value, ie 1e6.
  
          Parameters
          ---------
          coefs : array-like containing the coefficients of a term
  
          constraint_lam : float,
              penalty to impose on the constraint.
  
              typically this is a very large number.
  
          constraint_l2 : float,
              loading to improve the numerical conditioning of the constraint
              matrix.
  
              typically this is a very small number.
  
          Returns
          -------
          C : sparse CSC matrix containing the model constraints in quadratic form