builds the GAM block-diagonal constraint matrix in quadratic form
        out of constraint matrices specified for each feature.

        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

def build_constraints(self, coef, constraint_lam, constraint_l2):
        """
        builds the GAM block-diagonal constraint matrix in quadratic form
        out of constraint matrices specified for each feature.

        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
        """
        C = sp.sparse.csc_matrix(np.zeros((self.n_coefs, self.n_coefs)))
        for i in range(len(self._terms)):
            C += self._build_marginal_constraints(i, coef, constraint_lam, constraint_l2)

        return sp.sparse.csc_matrix(C)