void centerMatrix(DenseMatrix& matrix) { DenseVector col_means = matrix.colwise().mean().transpose(); DenseMatrix::Scalar grand_mean = matrix.mean(); matrix.array() += grand_mean; matrix.rowwise() -= col_means.transpose(); matrix.colwise() -= col_means; }
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; }