コード例 #1
0
SparseVector Basis::eval(const DenseVector &x) const
{
    // Set correct starting size and values: one element of 1.
    SparseMatrix tv1(1,1);  //tv1.resize(1);
    tv1.reserve(1);
    tv1.insert(0,0) = 1;
    SparseMatrix tv2 = tv1;

    // Evaluate all basisfunctions in each dimension i and generate the tensor product of the function values
    for (int dim = 0; dim < x.size(); dim++)
    {
        SparseVector xi = bases.at(dim).evaluate(x(dim));

        // Avoid matrix copy
        if (dim % 2 == 0)
        {
            tv1 = kroneckerProduct(tv2, xi); // tv1 = tv1 x xi
        }
        else
        {
            tv2 = kroneckerProduct(tv1, xi); // tv2 = tv1 x xi
        }
    }

    // Return correct vector
    if (tv1.size() == numBasisFunctions())
    {
        return tv1;
    }
    return tv2;
}
コード例 #2
0
SparseVector kroneckerProductVectors(const std::vector<SparseVector> &vectors)
{
    // Create two temp matrices
    SparseMatrix temp1(1,1);
    temp1.insert(0,0) = 1;
    SparseMatrix temp2 = temp1;

    // Multiply from left
    int counter = 0;
    for (const auto &vec : vectors)
    {
        // Avoid copy
        if (counter % 2 == 0)
            temp1 = kroneckerProduct(temp2, vec);
        else
            temp2 = kroneckerProduct(temp1, vec);

        ++counter;
    }

    // Return correct product
    if (counter % 2 == 0)
        return temp2;
    return temp1;
}
コード例 #3
0
ファイル: bsplinebasis.cpp プロジェクト: pmukherj/splinter
// Old implementation of Jacobian
DenseMatrix BSplineBasis::evalBasisJacobianOld(DenseVector &x) const
{
    // Jacobian basis matrix
    DenseMatrix J; J.setZero(getNumBasisFunctions(), numVariables);

    // Calculate partial derivatives
    for (unsigned int i = 0; i < numVariables; i++)
    {
        // One column in basis jacobian
        DenseVector bi; bi.setOnes(1);
        for (unsigned int j = 0; j < numVariables; j++)
        {
            DenseVector temp = bi;
            DenseVector xi;
            if (j == i)
            {
                // Differentiated basis
                xi = bases.at(j).evaluateFirstDerivative(x(j));
            }
            else
            {
                // Normal basis
                xi = bases.at(j).evaluate(x(j));
            }

            bi = kroneckerProduct(temp, xi);
        }

        // Fill out column
        J.block(0,i,bi.rows(),1) = bi.block(0,0,bi.rows(),1);
    }

    return J;
}
コード例 #4
0
ファイル: bsplinepoly.cpp プロジェクト: simudream/censo
/*
 * Calculate coefficients of B-spline representing a multivariate polynomial
 *
 * The polynomial f(x), with x in R^n, has m terms on the form
 * f(x) = c(0)*x(0)^E(0,0)*x(1)^E(0,1)*...*x(n-1)^E(0,n-1)
 *       +c(1)*x(0)^E(1,0)*x(1)^E(1,1)*...*x(n-1)^E(1,n-1)
 *       +...
 *       +c(m-1)*x(0)^E(m-1,0)*x(1)^E(m-1,1)*...*x(n-1)^E(m-1,n-1)
 * where c in R^m is a vector with coefficients for each of the m terms,
 * and E in N^(mxn) is a matrix with the exponents of each variable in each of the m terms,
 * e.g. the first row of E defines the first term with variable exponents E(0,0) to E(0,n-1).
 *
 * Note: E must be a matrix of nonnegative integers
 */
DenseMatrix getBSplineBasisCoefficients(DenseVector c, DenseMatrix E, std::vector<double> lb, std::vector<double> ub)
{
    unsigned int dim = E.cols();
    unsigned int terms = E.rows();
    assert(dim >= 1); // At least one variable
    assert(terms >= 1); // At least one term (assumes that c is a column vector)
    assert(terms == c.rows());
    assert(dim == lb.size());
    assert(dim == ub.size());

    // Get highest power of each variable
    DenseVector powers = E.colwise().maxCoeff();

    // Store in std vector
    std::vector<unsigned int> powers2;
    for (unsigned int i = 0; i < powers.size(); ++i)
        powers2.push_back(powers(i));

    // Calculate tensor product transformation matrix T
    DenseMatrix T = getTransformationMatrix(powers2, lb, ub);

    // Compute power basis coefficients (lambda vector)
    SparseMatrix L(T.cols(),1);
    L.setZero();

    for (unsigned int i = 0; i < terms; i++)
    {
        SparseMatrix Li(1,1);
        Li.insert(0,0) = 1;

        for (unsigned int j = 0; j < dim; j++)
        {
            int e = E(i,j);
            SparseVector li(powers(j)+1);
            li.reserve(1);
            li.insert(e) = 1;

            SparseMatrix temp = Li;
            Li = kroneckerProduct(temp, li);
        }

        L += c(i)*Li;
    }

    // Compute B-spline coefficients
    DenseMatrix C = T*L;

    return C;
}
コード例 #5
0
SparseMatrix Basis::evalBasisJacobian(DenseVector &x) const
{
    // Jacobian basis matrix
    SparseMatrix J(numBasisFunctions(), numVariables);
    //J.setZero(numBasisFunctions(), numInputs);

    // Calculate partial derivatives
    for (unsigned int i = 0; i < numVariables; i++)
    {
        // One column in basis jacobian
        SparseMatrix Ji(1,1);
        Ji.insert(0,0) = 1;
        for (unsigned int j = 0; j < numVariables; j++)
        {
            SparseMatrix temp = Ji;
            SparseMatrix xi;
            if (j == i)
            {
                // Differentiated basis
                xi = bases.at(j).evaluateDerivative(x(j),1);
            }
            else
            {
                // Normal basis
                xi = bases.at(j).evaluate(x(j));
            }
            Ji = kroneckerProduct(temp, xi);
            //myKroneckerProduct(temp,xi,Ji);
            //Ji = kroneckerProduct(Ji, xi).eval();
        }

        // Fill out column
        for (int k = 0; k < Ji.outerSize(); ++k)
        for (SparseMatrix::InnerIterator it(Ji,k); it; ++it)
        {
            if (it.value() != 0)
                J.insert(it.row(),i) = it.value();
        }
        //J.block(0,i,Ji.rows(),1) = bi.block(0,0,Ji.rows(),1);
    }

    J.makeCompressed();

    return J;
}
コード例 #6
0
ファイル: bsplinepoly.cpp プロジェクト: simudream/censo
/*
 * Calculates the reparameterization matrix that changes the domain from [0,1] to [a,b]
 */
DenseMatrix getReparameterizationMatrixND(std::vector<unsigned int> degrees, std::vector<double> lb, std::vector<double> ub)
{
    unsigned int dim = degrees.size();
    assert(dim >= 1); // At least one variable
    assert(dim == lb.size());
    assert(dim == ub.size());

    // Calculate tensor product transformation matrix T
    SparseMatrix R(1,1);
    R.insert(0,0) = 1;

    for (unsigned int i = 0; i < dim; i++)
    {
        SparseMatrix temp(R);
        unsigned int deg = degrees.at(i);
        DenseMatrix Ri = getReparameterizationMatrix1D(deg, lb.at(i), ub.at(i));
        R = kroneckerProduct(temp, Ri);
    }
    return R;
}
コード例 #7
0
ファイル: bsplinepoly.cpp プロジェクト: simudream/censo
/*
 * Transformation matrix taking a power basis to a B-spline basis
 */
DenseMatrix getTransformationMatrix(std::vector<unsigned int> degrees, std::vector<double> lb, std::vector<double> ub)
{
    unsigned int dim = degrees.size();
    assert(dim >= 1); // At least one variable
    assert(dim == lb.size());
    assert(dim == ub.size());

    // Calculate tensor product transformation matrix T
    SparseMatrix T(1,1);
    T.insert(0,0) = 1;

    for (unsigned int i = 0; i < dim; i++)
    {
        SparseMatrix temp(T);
        unsigned int deg = degrees.at(i);
        DenseMatrix Mi = getBSplineToPowerBasisMatrix1D(deg);
        DenseMatrix Ri = getReparameterizationMatrix1D(deg, lb.at(i), ub.at(i));
        DenseMatrix Ti = Mi.colPivHouseholderQr().solve(Ri);

        T = kroneckerProduct(temp, Ti);
    }
    return T;
}
コード例 #8
0
ファイル: bspline.cpp プロジェクト: LStoleriu/splinter
/*
 * Returns the Hessian evaluated at x.
 * The Hessian is an n x n matrix,
 * where n is the dimension of x.
 */
DenseMatrix BSpline::evalHessian(DenseVector x) const
{
    checkInput(x);

    #ifndef NDEBUG
    if (!pointInDomain(x))
        throw Exception("BSpline::evalHessian: Evaluation at point outside domain.");
    #endif // NDEBUG

    DenseMatrix H;
    H.setZero(1,1);
    DenseMatrix identity = DenseMatrix::Identity(numVariables, numVariables);
    DenseMatrix caug = kroneckerProduct(identity, coefficients.transpose());
    DenseMatrix DB = basis.evalBasisHessian(x);
    H = caug*DB;

    // Fill in upper triangular of Hessian
    for (size_t i = 0; i < numVariables; ++i)
        for (size_t j = i+1; j < numVariables; ++j)
            H(i,j) = H(j,i);

    return H;
}
コード例 #9
0
ファイル: kronecker_product.cpp プロジェクト: 23119841/openbr
void test_kronecker_product()
{
  // DM = dense matrix; SM = sparse matrix
  Matrix<double, 2, 3> DM_a;
  MatrixXd             DM_b(3,2);
  SparseMatrix<double> SM_a(2,3);
  SparseMatrix<double> SM_b(3,2);
  SM_a.insert(0,0) = DM_a(0,0) = -0.4461540300782201;
  SM_a.insert(0,1) = DM_a(0,1) = -0.8057364375283049;
  SM_a.insert(0,2) = DM_a(0,2) =  0.3896572459516341;
  SM_a.insert(1,0) = DM_a(1,0) = -0.9076572187376921;
  SM_a.insert(1,1) = DM_a(1,1) =  0.6469156566545853;
  SM_a.insert(1,2) = DM_a(1,2) = -0.3658010398782789;
  SM_b.insert(0,0) = DM_b(0,0) =  0.9004440976767099;
  SM_b.insert(0,1) = DM_b(0,1) = -0.2368830858139832;
  SM_b.insert(1,0) = DM_b(1,0) = -0.9311078389941825;
  SM_b.insert(1,1) = DM_b(1,1) =  0.5310335762980047;
  SM_b.insert(2,0) = DM_b(2,0) = -0.1225112806872035;
  SM_b.insert(2,1) = DM_b(2,1) =  0.5903998022741264;
  SparseMatrix<double,RowMajor> SM_row_a(SM_a), SM_row_b(SM_b);

  // test kroneckerProduct(DM_block,DM,DM_fixedSize)
  Matrix<double, 6, 6> DM_fix_ab;
  DM_fix_ab(0,0)=37.0;
  kroneckerProduct(DM_a.block(0,0,2,3),DM_b,DM_fix_ab);
  CALL_SUBTEST(check_kronecker_product(DM_fix_ab));

  // test kroneckerProduct(DM,DM,DM_block)
  MatrixXd DM_block_ab(10,15);
  DM_block_ab(0,0)=37.0;
  kroneckerProduct(DM_a,DM_b,DM_block_ab.block(2,5,6,6));
  CALL_SUBTEST(check_kronecker_product(DM_block_ab.block(2,5,6,6)));

  // test kroneckerProduct(DM,DM,DM)
  MatrixXd DM_ab(1,5);
  DM_ab(0,0)=37.0;
  kroneckerProduct(DM_a,DM_b,DM_ab);
  CALL_SUBTEST(check_kronecker_product(DM_ab));

  // test kroneckerProduct(SM,DM,SM)
  SparseMatrix<double> SM_ab(1,20);
  SM_ab.insert(0,0)=37.0;
  kroneckerProduct(SM_a,DM_b,SM_ab);
  CALL_SUBTEST(check_kronecker_product(SM_ab));
  SparseMatrix<double,RowMajor> SM_ab2(10,3);
  SM_ab2.insert(0,0)=37.0;
  kroneckerProduct(SM_a,DM_b,SM_ab2);
  CALL_SUBTEST(check_kronecker_product(SM_ab2));

  // test kroneckerProduct(DM,SM,SM)
  SM_ab.insert(0,0)=37.0;
  kroneckerProduct(DM_a,SM_b,SM_ab);
  CALL_SUBTEST(check_kronecker_product(SM_ab));
  SM_ab2.insert(0,0)=37.0;
  kroneckerProduct(DM_a,SM_b,SM_ab2);
  CALL_SUBTEST(check_kronecker_product(SM_ab2));

  // test kroneckerProduct(SM,SM,SM)
  SM_ab.resize(2,33);
  SM_ab.insert(0,0)=37.0;
  kroneckerProduct(SM_a,SM_b,SM_ab);
  CALL_SUBTEST(check_kronecker_product(SM_ab));
  SM_ab2.resize(5,11);
  SM_ab2.insert(0,0)=37.0;
  kroneckerProduct(SM_a,SM_b,SM_ab2);
  CALL_SUBTEST(check_kronecker_product(SM_ab2));

  // test kroneckerProduct(SM,SM,SM) with sparse pattern
  SM_a.resize(4,5);
  SM_b.resize(3,2);
  SM_a.resizeNonZeros(0);
  SM_b.resizeNonZeros(0);
  SM_a.insert(1,0) = -0.1;
  SM_a.insert(0,3) = -0.2;
  SM_a.insert(2,4) =  0.3;
  SM_a.finalize();
  SM_b.insert(0,0) =  0.4;
  SM_b.insert(2,1) = -0.5;
  SM_b.finalize();
  SM_ab.resize(1,1);
  SM_ab.insert(0,0)=37.0;
  kroneckerProduct(SM_a,SM_b,SM_ab);
  CALL_SUBTEST(check_sparse_kronecker_product(SM_ab));

  // test dimension of result of kroneckerProduct(DM,DM,DM)
  MatrixXd DM_a2(2,1);
  MatrixXd DM_b2(5,4);
  MatrixXd DM_ab2;
  kroneckerProduct(DM_a2,DM_b2,DM_ab2);
  CALL_SUBTEST(check_dimension(DM_ab2,2*5,1*4));
  DM_a2.resize(10,9);
  DM_b2.resize(4,8);
  kroneckerProduct(DM_a2,DM_b2,DM_ab2);
  CALL_SUBTEST(check_dimension(DM_ab2,10*4,9*8));
}
コード例 #10
0
ファイル: bsplinebasis.cpp プロジェクト: pmukherj/splinter
SparseMatrix BSplineBasis::evalBasisHessian(DenseVector &x) const
{
    // Hessian basis matrix
    /* Hij = B1 x ... x DBi x ... x DBj x ... x Bn
     * (Hii = B1 x ... x DDBi x ... x Bn)
     * Where B are basis functions evaluated at x,
     * DB are the derivative of the basis functions,
     * and x is the kronecker product.
     * Hij is in R^(numBasisFunctions x 1)
     * so that basis hessian H is in R^(numBasisFunctions*numInputs x numInputs)
     * The real B-spline Hessian is calculated as (c^T x 1^(numInputs x 1))*H
     */
    SparseMatrix H(getNumBasisFunctions()*numVariables, numVariables);
    //H.setZero(numBasisFunctions()*numInputs, numInputs);

    // Calculate partial derivatives
    // Utilizing that Hessian is symmetric
    // Filling out lower left triangular
    for (unsigned int i = 0; i < numVariables; i++) // row
    {
        for (unsigned int j = 0; j <= i; j++) // col
        {
            // One column in basis jacobian
            SparseMatrix Hi(1,1);
            Hi.insert(0,0) = 1;

            for (unsigned int k = 0; k < numVariables; k++)
            {
                SparseMatrix temp = Hi;
                SparseMatrix Bk;
                if (i == j && k == i)
                {
                    // Diagonal element
                    Bk = bases.at(k).evaluateDerivative(x(k),2);
                }
                else if (k == i || k == j)
                {
                    Bk = bases.at(k).evaluateDerivative(x(k),1);
                }
                else
                {
                    Bk = bases.at(k).evaluate(x(k));
                }
                Hi = kroneckerProduct(temp, Bk);
            }

            // Fill out column
            for (int k = 0; k < Hi.outerSize(); ++k)
            for (SparseMatrix::InnerIterator it(Hi,k); it; ++it)
            {
                if (it.value() != 0)
                {
                    int row = i*getNumBasisFunctions()+it.row();
                    int col = j;
                    H.insert(row,col) = it.value();
                }
            }
        }
    }

    H.makeCompressed();

    return H;
}
コード例 #11
0
ファイル: constraintbspline.cpp プロジェクト: simudream/censo
bool ConstraintBSpline::controlPointBoundsDeduction() const
{
    // Get variable bounds
    auto xlb = bspline.getDomainLowerBound();
    auto xub = bspline.getDomainUpperBound();

    // Use these instead?
//    for (unsigned int i = 0; i < bspline.getNumVariables(); i++)
//    {
//        xlb.at(i) = variables.at(i)->getLowerBound();
//        xub.at(i) = variables.at(i)->getUpperBound();
//    }

    double lowerBound = variables.back()->getLowerBound(); // f(x) = y > lowerBound
    double upperBound = variables.back()->getUpperBound(); // f(x) = y < upperBound

    // Get knot vectors and basis degrees
    auto knotVectors = bspline.getKnotVectors();
    auto basisDegrees = bspline.getBasisDegrees();

    // Compute n value for each variable
    // Total number of control points is ns(0)*...*ns(d-1)
    std::vector<unsigned int> numBasisFunctions = bspline.getNumBasisFunctions();

    // Get matrix of coefficients
    DenseMatrix cps = controlPoints;
    DenseMatrix coeffs = cps.block(bspline.getNumVariables(), 0, 1, cps.cols());

    for (unsigned int d = 0; d < bspline.getNumVariables(); d++)
    {
        if (assertNear(xlb.at(d), xub.at(d)))
            continue;

        auto n = numBasisFunctions.at(d);
        auto p = basisDegrees.at(d);
        std::vector<double> knots = knotVectors.at(d);
        assert(knots.size() == n+p+1);

        // Tighten lower bound
        unsigned int i = 1;
        for (; i <= n; i++)
        {
            // Knot interval of interest: [t_0, t_i]

            // Selection matrix
            DenseMatrix S = DenseMatrix::Ones(1,1);

            for (unsigned int d2 = 0; d2 < bspline.getNumVariables(); d2++)
            {
                DenseMatrix temp(S);

                DenseMatrix Sd_full = DenseMatrix::Identity(numBasisFunctions.at(d2),numBasisFunctions.at(d2));
                DenseMatrix Sd(Sd_full);
                if (d == d2)
                    Sd = Sd_full.block(0,0,n,i);

                S = kroneckerProduct(temp, Sd);
            }

            // Control points that have support in [t_0, t_i]
            DenseMatrix selc = coeffs*S;
            DenseVector minCP = selc.rowwise().minCoeff();
            DenseVector maxCP = selc.rowwise().maxCoeff();
            double minv = minCP(0);
            double maxv = maxCP(0);

            // Investigate feasibility
            if (minv > upperBound || maxv < lowerBound)
                continue; // infeasible
            else
                break; // feasible
        }

        // New valid lower bound on x(d) is knots(i-1)
        if (i > 1)
        {
            if (!variables.at(d)->updateLowerBound(knots.at(i-1)))
                return false;
        }

        // Tighten upper bound
        i = 1;
        for (; i <= n; i++)
        {
            // Knot interval of interest: [t_{n+p-i}, t_{n+p}]

            // Selection matrix
            DenseMatrix S = DenseMatrix::Ones(1,1);

            for (unsigned int d2 = 0; d2 < bspline.getNumVariables(); d2++)
            {
                DenseMatrix temp(S);

                DenseMatrix Sd_full = DenseMatrix::Identity(numBasisFunctions.at(d2),numBasisFunctions.at(d2));
                DenseMatrix Sd(Sd_full);
                if (d == d2)
                    Sd = Sd_full.block(0,n-i,n,i);

                S = kroneckerProduct(temp, Sd);
            }

            // Control points that have support in [t_{n+p-i}, t_{n+p}]
            DenseMatrix selc = coeffs*S;
            DenseVector minCP = selc.rowwise().minCoeff();
            DenseVector maxCP = selc.rowwise().maxCoeff();
            double minv = minCP(0);
            double maxv = maxCP(0);

            // Investigate feasibility
            if (minv > upperBound || maxv < lowerBound)
                continue; // infeasible
            else
                break; // feasible
        }

        // New valid lower bound on x(d) is knots(n+p-(i-1))
        if (i > 1)
        {
            if (!variables.at(d)->updateUpperBound(knots.at(n+p-(i-1))))
                return false;
            // NOTE: the upper bound seems to not be tight! can we use knots.at(n+p-i)?
        }

    }

    return true;
}
コード例 #12
0
ファイル: kronecker_product.cpp プロジェクト: 52nlp/pyhsmm
void test_kronecker_product()
{
  // DM = dense matrix; SM = sparse matrix

  Matrix<double, 2, 3> DM_a;
  SparseMatrix<double> SM_a(2,3);
  SM_a.insert(0,0) = DM_a.coeffRef(0,0) = -0.4461540300782201;
  SM_a.insert(0,1) = DM_a.coeffRef(0,1) = -0.8057364375283049;
  SM_a.insert(0,2) = DM_a.coeffRef(0,2) =  0.3896572459516341;
  SM_a.insert(1,0) = DM_a.coeffRef(1,0) = -0.9076572187376921;
  SM_a.insert(1,1) = DM_a.coeffRef(1,1) =  0.6469156566545853;
  SM_a.insert(1,2) = DM_a.coeffRef(1,2) = -0.3658010398782789;
 
  MatrixXd             DM_b(3,2);
  SparseMatrix<double> SM_b(3,2);
  SM_b.insert(0,0) = DM_b.coeffRef(0,0) =  0.9004440976767099;
  SM_b.insert(0,1) = DM_b.coeffRef(0,1) = -0.2368830858139832;
  SM_b.insert(1,0) = DM_b.coeffRef(1,0) = -0.9311078389941825;
  SM_b.insert(1,1) = DM_b.coeffRef(1,1) =  0.5310335762980047;
  SM_b.insert(2,0) = DM_b.coeffRef(2,0) = -0.1225112806872035;
  SM_b.insert(2,1) = DM_b.coeffRef(2,1) =  0.5903998022741264;

  SparseMatrix<double,RowMajor> SM_row_a(SM_a), SM_row_b(SM_b);

  // test DM_fixedSize = kroneckerProduct(DM_block,DM)
  Matrix<double, 6, 6> DM_fix_ab = kroneckerProduct(DM_a.topLeftCorner<2,3>(),DM_b);

  CALL_SUBTEST(check_kronecker_product(DM_fix_ab));
  CALL_SUBTEST(check_kronecker_product(kroneckerProduct(DM_a.topLeftCorner<2,3>(),DM_b)));

  for(int i=0;i<DM_fix_ab.rows();++i)
    for(int j=0;j<DM_fix_ab.cols();++j)
       VERIFY_IS_APPROX(kroneckerProduct(DM_a,DM_b).coeff(i,j), DM_fix_ab(i,j));

  // test DM_block = kroneckerProduct(DM,DM)
  MatrixXd DM_block_ab(10,15);
  DM_block_ab.block<6,6>(2,5) = kroneckerProduct(DM_a,DM_b);
  CALL_SUBTEST(check_kronecker_product(DM_block_ab.block<6,6>(2,5)));

  // test DM = kroneckerProduct(DM,DM)
  MatrixXd DM_ab = kroneckerProduct(DM_a,DM_b);
  CALL_SUBTEST(check_kronecker_product(DM_ab));
  CALL_SUBTEST(check_kronecker_product(kroneckerProduct(DM_a,DM_b)));

  // test SM = kroneckerProduct(SM,DM)
  SparseMatrix<double> SM_ab = kroneckerProduct(SM_a,DM_b);
  CALL_SUBTEST(check_kronecker_product(SM_ab));
  SparseMatrix<double,RowMajor> SM_ab2 = kroneckerProduct(SM_a,DM_b);
  CALL_SUBTEST(check_kronecker_product(SM_ab2));
  CALL_SUBTEST(check_kronecker_product(kroneckerProduct(SM_a,DM_b)));

  // test SM = kroneckerProduct(DM,SM)
  SM_ab.setZero();
  SM_ab.insert(0,0)=37.0;
  SM_ab = kroneckerProduct(DM_a,SM_b);
  CALL_SUBTEST(check_kronecker_product(SM_ab));
  SM_ab2.setZero();
  SM_ab2.insert(0,0)=37.0;
  SM_ab2 = kroneckerProduct(DM_a,SM_b);
  CALL_SUBTEST(check_kronecker_product(SM_ab2));
  CALL_SUBTEST(check_kronecker_product(kroneckerProduct(DM_a,SM_b)));

  // test SM = kroneckerProduct(SM,SM)
  SM_ab.resize(2,33);
  SM_ab.insert(0,0)=37.0;
  SM_ab = kroneckerProduct(SM_a,SM_b);
  CALL_SUBTEST(check_kronecker_product(SM_ab));
  SM_ab2.resize(5,11);
  SM_ab2.insert(0,0)=37.0;
  SM_ab2 = kroneckerProduct(SM_a,SM_b);
  CALL_SUBTEST(check_kronecker_product(SM_ab2));
  CALL_SUBTEST(check_kronecker_product(kroneckerProduct(SM_a,SM_b)));

  // test SM = kroneckerProduct(SM,SM) with sparse pattern
  SM_a.resize(4,5);
  SM_b.resize(3,2);
  SM_a.resizeNonZeros(0);
  SM_b.resizeNonZeros(0);
  SM_a.insert(1,0) = -0.1;
  SM_a.insert(0,3) = -0.2;
  SM_a.insert(2,4) =  0.3;
  SM_a.finalize();
  
  SM_b.insert(0,0) =  0.4;
  SM_b.insert(2,1) = -0.5;
  SM_b.finalize();
  SM_ab.resize(1,1);
  SM_ab.insert(0,0)=37.0;
  SM_ab = kroneckerProduct(SM_a,SM_b);
  CALL_SUBTEST(check_sparse_kronecker_product(SM_ab));

  // test dimension of result of DM = kroneckerProduct(DM,DM)
  MatrixXd DM_a2(2,1);
  MatrixXd DM_b2(5,4);
  MatrixXd DM_ab2 = kroneckerProduct(DM_a2,DM_b2);
  CALL_SUBTEST(check_dimension(DM_ab2,2*5,1*4));
  DM_a2.resize(10,9);
  DM_b2.resize(4,8);
  DM_ab2 = kroneckerProduct(DM_a2,DM_b2);
  CALL_SUBTEST(check_dimension(DM_ab2,10*4,9*8));
  
  for(int i = 0; i < g_repeat; i++)
  {
    double density = Eigen::internal::random<double>(0.01,0.5);
    int ra = Eigen::internal::random<int>(1,50);
    int ca = Eigen::internal::random<int>(1,50);
    int rb = Eigen::internal::random<int>(1,50);
    int cb = Eigen::internal::random<int>(1,50);
    SparseMatrix<float,ColMajor> sA(ra,ca), sB(rb,cb), sC;
    SparseMatrix<float,RowMajor> sC2;
    MatrixXf dA(ra,ca), dB(rb,cb), dC;
    initSparse(density, dA, sA);
    initSparse(density, dB, sB);
    
    sC = kroneckerProduct(sA,sB);
    dC = kroneckerProduct(dA,dB);
    VERIFY_IS_APPROX(MatrixXf(sC),dC);
    
    sC = kroneckerProduct(sA.transpose(),sB);
    dC = kroneckerProduct(dA.transpose(),dB);
    VERIFY_IS_APPROX(MatrixXf(sC),dC);
    
    sC = kroneckerProduct(sA.transpose(),sB.transpose());
    dC = kroneckerProduct(dA.transpose(),dB.transpose());
    VERIFY_IS_APPROX(MatrixXf(sC),dC);
    
    sC = kroneckerProduct(sA,sB.transpose());
    dC = kroneckerProduct(dA,dB.transpose());
    VERIFY_IS_APPROX(MatrixXf(sC),dC);
    
    sC2 = kroneckerProduct(sA,sB);
    dC = kroneckerProduct(dA,dB);
    VERIFY_IS_APPROX(MatrixXf(sC2),dC);
  }
}