12 MonotoneExpansion::MonotoneExpansion(std::shared_ptr<BasisExpansion> monotonePartsIn,
13 bool coeffInput) : MonotoneExpansion({std::make_shared<BasisExpansion>(std::vector<std::shared_ptr<IndexedScalarBasis>>({std::make_shared<Monomial>()}))},
19 MonotoneExpansion::MonotoneExpansion(std::vector<std::shared_ptr<BasisExpansion>>
const& generalPartsIn,
20 std::vector<std::shared_ptr<BasisExpansion>>
const& monotonePartsIn,
21 bool coeffInput) : ModPiece(GetInputSizes(monotonePartsIn, generalPartsIn, coeffInput),
22 monotonePartsIn.size()*Eigen::VectorXi::Ones(1)),
23 generalParts(generalPartsIn),
24 monotoneParts(monotonePartsIn)
26 assert(generalPartsIn.size() == monotonePartsIn.size());
27 assert(generalPartsIn.at(0)->Multis()->GetMaxOrders().maxCoeff()==0);
33 for(
int i=0; i<monotoneParts.size(); ++i)
34 maxOrder = std::max(maxOrder, monotoneParts.at(i)->Multis()->GetMaxOrders()(i) );
38 int numQuadPts = ceil(0.5*(2.0*maxOrder + 1.0));
40 gqSolver.Compute(numQuadPts-1);
42 quadPts = 0.5*(gqSolver.Points().transpose()+Eigen::VectorXd::Ones(numQuadPts));
43 quadWeights = 0.5*gqSolver.Weights();
46 std::shared_ptr<MonotoneExpansion> MonotoneExpansion::Head(
int numRows)
const
48 assert(numRows<=generalParts.size());
50 std::vector<std::shared_ptr<BasisExpansion>> newGenerals(numRows);
51 std::vector<std::shared_ptr<BasisExpansion>> newMonotones(numRows);
53 for(
int i=0; i<numRows; ++i){
54 newGenerals.at(i) = generalParts.at(i);
55 newMonotones.at(i) = monotoneParts.at(i);
58 return std::make_shared<MonotoneExpansion>(newGenerals, newMonotones);
61 Eigen::VectorXd MonotoneExpansion::EvaluateInverse(Eigen::VectorXd
const& refPt)
const{
62 Eigen::VectorXd tgtPt0 = Eigen::VectorXd::Zero(refPt.size());
63 return EvaluateInverse(refPt, tgtPt0);
66 Eigen::VectorXd MonotoneExpansion::EvaluateInverse(Eigen::VectorXd
const& refPt,
67 Eigen::VectorXd
const& tgtPt0)
const{
69 Eigen::VectorXd tgtPt = tgtPt0;
70 Eigen::VectorXd mappedPt, resid, step, newPt;
71 double residNorm = 1e4;
73 const int maxLineIts = 20;
75 while(residNorm>1
e-11){
76 resid = EvaluateForward(tgtPt) - refPt;
77 step = JacobianWrtX(tgtPt).triangularView<Eigen::Lower>().solve(resid);
79 double stepSize = 1.0;
80 newPt = tgtPt - stepSize * step;
82 for(
int lineIt=0; lineIt<maxLineIts; ++lineIt){
83 newResidNorm = (EvaluateForward(newPt) - refPt).norm();
84 if(newResidNorm<(1.0-1
e-9)*residNorm)
87 newPt = tgtPt - stepSize * step;
90 residNorm = newResidNorm;
98 unsigned MonotoneExpansion::NumTerms()
const{
100 unsigned numTerms = 0;
101 for(
int i=0; i<generalParts.size(); ++i)
102 numTerms += generalParts.at(i)->NumTerms();
103 for(
int i=0; i<monotoneParts.size(); ++i)
104 numTerms += monotoneParts.at(i)->NumTerms();
109 Eigen::VectorXd MonotoneExpansion::GetCoeffs()
const
111 Eigen::VectorXd output(NumTerms());
113 unsigned currInd = 0;
115 for(
int i=0; i<generalParts.size(); ++i){
116 output.segment(currInd, generalParts.at(i)->NumTerms()) = generalParts.at(i)->GetCoeffs().transpose();
117 currInd += generalParts.at(i)->NumTerms();
120 for(
int i=0; i<monotoneParts.size(); ++i){
121 output.segment(currInd, monotoneParts.at(i)->NumTerms()) = monotoneParts.at(i)->GetCoeffs().transpose();
122 currInd += monotoneParts.at(i)->NumTerms();
128 void MonotoneExpansion::SetCoeffs(Eigen::VectorXd
const& allCoeffs)
130 unsigned currInd = 0;
132 for(
int i=0; i<generalParts.size(); ++i){
133 generalParts.at(i)->SetCoeffs(allCoeffs.segment(currInd, generalParts.at(i)->NumTerms()).transpose());
134 currInd += generalParts.at(i)->NumTerms();
137 for(
int i=0; i<monotoneParts.size(); ++i){
138 monotoneParts.at(i)->SetCoeffs(allCoeffs.segment(currInd, monotoneParts.at(i)->NumTerms()).transpose());
139 currInd += monotoneParts.at(i)->NumTerms();
143 Eigen::VectorXd MonotoneExpansion::EvaluateForward(Eigen::VectorXd
const& x)
const{
145 Eigen::VectorXd refPt = Eigen::VectorXd::Zero(x.size());
148 for(
int i=0; i<generalParts.size(); ++i)
149 refPt(i) += generalParts.at(i)->Evaluate(x).at(0)(0);
152 Eigen::VectorXd quadEvals(quadPts.size());
153 for(
int i=0; i<monotoneParts.size(); ++i){
156 Eigen::VectorXd evalPt = x;
157 evalPt(i) = x(i) * quadPts(0);
159 double polyEval = monotoneParts.at(i)->Evaluate(evalPt).at(0)(0);
161 quadEvals(0) = polyEval*polyEval;
162 for(
int k=1;
k<quadPts.size(); ++
k){
163 evalPt(i) = x(i) * quadPts(
k);
164 polyEval = monotoneParts.at(i)->Evaluate(evalPt).at(0)(0);
165 quadEvals(
k) = polyEval*polyEval;
167 refPt(i) += quadEvals.dot(quadWeights)*x(i);
176 SetCoeffs(inputs.at(1).get());
180 outputs.at(0) = EvaluateForward(inputs.at(0).get());
184 Eigen::MatrixXd MonotoneExpansion::JacobianWrtX(Eigen::VectorXd
const& x)
const{
186 Eigen::MatrixXd jac = Eigen::MatrixXd::Zero(x.size(), x.size());
189 Eigen::MatrixXd polyGrad;
192 for(
int i=0; i<generalParts.size(); ++i){
193 Eigen::MatrixXd partialJac = generalParts.at(i)->Jacobian(0,0,x);
194 jac.block(i,0,1,i) += partialJac.block(0,0,1,i);
198 for(
int i=0; i<monotoneParts.size(); ++i){
199 Eigen::VectorXd evalPt = x;
201 for(
int k=0;
k<quadPts.size(); ++
k){
202 evalPt(i) = x(i) * quadPts(
k);
203 polyEval = monotoneParts.at(i)->Evaluate(evalPt).at(0)(0);
204 polyGrad = monotoneParts.at(i)->Jacobian(0,0,evalPt);
205 jac.block(i,0,1,i) += 2.0 * x(i) * quadWeights(
k) * polyEval * polyGrad.block(0,0,1,i);
206 jac(i,i) += quadWeights(
k) * (polyEval * polyEval + 2.0*x(i)*polyGrad(i)*polyEval*quadPts(
k));
214 void MonotoneExpansion::JacobianImpl(
unsigned int const wrtIn,
215 unsigned int const wrtOut,
219 SetCoeffs(inputs.at(1).get());
222 Eigen::VectorXd
const& x = inputs.at(0);
223 assert(x.size()==monotoneParts.size());
228 jac = JacobianWrtX(x);
233 unsigned numTerms = NumTerms();
236 jac = Eigen::MatrixXd::Zero(x.size(), numTerms);
239 unsigned currCoeff = 0;
240 for(
int i=0; i<generalParts.size(); ++i){
241 Eigen::MatrixXd partialJac = generalParts.at(i)->Jacobian(0,1,x);
242 jac.block(i, currCoeff, 1, generalParts.at(i)->NumTerms()) += partialJac;
243 currCoeff += generalParts.at(i)->NumTerms();
248 Eigen::MatrixXd polyGrad;
249 for(
int i=0; i<monotoneParts.size(); ++i){
250 Eigen::VectorXd evalPt = x;
252 for(
int k=0;
k<quadPts.size(); ++
k){
253 evalPt(i) = x(i) * quadPts(
k);
254 polyEval = monotoneParts.at(i)->Evaluate(evalPt).at(0)(0);
255 polyGrad = monotoneParts.at(i)->Jacobian(0,1,evalPt);
256 jac.block(i,currCoeff,1,monotoneParts.at(i)->NumTerms()) += 2.0 * x(i) * quadWeights(
k) * polyEval * polyGrad;
259 currCoeff += monotoneParts.at(i)->NumTerms();
274 double MonotoneExpansion::LogDeterminant(Eigen::VectorXd
const& evalPt,
275 Eigen::VectorXd
const& coeffs)
278 return LogDeterminant(evalPt);
280 double MonotoneExpansion::LogDeterminant(Eigen::VectorXd
const& evalPt)
282 assert(evalPt.rows() == inputSizes(0));
284 vecIn.push_back(std::cref(evalPt));
285 JacobianImpl(0,0,vecIn);
286 return jacobian.diagonal().array().log().sum();
290 Eigen::VectorXd MonotoneExpansion::GradLogDeterminant(Eigen::VectorXd
const& evalPt,
291 Eigen::VectorXd
const& coeffs)
294 return GradLogDeterminant(evalPt);
297 Eigen::VectorXd MonotoneExpansion::GradLogDeterminant(Eigen::VectorXd
const& x)
300 Eigen::VectorXd output = Eigen::VectorXd::Zero(NumTerms());
303 Eigen::MatrixXd polyGradX, polyGradC, polyD2;
306 unsigned currInd = 0;
307 for(
int i=0; i<generalParts.size(); ++i)
308 currInd += generalParts.at(i)->NumTerms();
311 for(
int i=0; i<monotoneParts.size(); ++i){
312 Eigen::VectorXd evalPt = x;
315 Eigen::VectorXd part2 = Eigen::VectorXd::Zero(monotoneParts.at(i)->NumTerms());
317 for(
int k=0;
k<quadPts.size(); ++
k){
318 evalPt(i) = x(i) * quadPts(
k);
319 polyEval = monotoneParts.at(i)->Evaluate(evalPt).at(0)(0);
320 polyGradX = monotoneParts.at(i)->Jacobian(0,0,evalPt);
321 polyGradC = monotoneParts.at(i)->Jacobian(0,1,evalPt);
322 polyD2 = monotoneParts.at(i)->SecondDerivative(0, 0, 1, evalPt);
324 part1 += quadWeights(
k) * (polyEval * polyEval + 2.0*x(i)*polyGradX(i)*polyEval*quadPts(
k));
325 part2 += 2.0 * quadWeights(
k) * (polyEval * polyGradC + x(i) * quadPts(
k) * (polyEval*polyD2.row(i) + polyGradX(i)*polyGradC)).transpose();
328 output.segment(currInd, monotoneParts.at(i)->NumTerms()) = part2/part1;
330 currInd += monotoneParts.at(i)->NumTerms();
338 Eigen::VectorXi MonotoneExpansion::GetInputSizes(std::vector<std::shared_ptr<BasisExpansion>>
const& generalPartsIn,
339 std::vector<std::shared_ptr<BasisExpansion>>
const& monotonePartsIn,
342 Eigen::VectorXi output;
346 for(
int i=0; i<generalPartsIn.size(); ++i)
347 numCoeffs += generalPartsIn.at(i)->NumTerms();
348 for(
int i=0; i<monotonePartsIn.size(); ++i)
349 numCoeffs += monotonePartsIn.at(i)->NumTerms();
352 output << monotonePartsIn.size(), numCoeffs;
356 output << monotonePartsIn.size();
Class for computing Gauss Quadrature rules from an orthogonal polynomial family.
std::vector< std::reference_wrapper< const T > > ref_vector
A vector of references to something ...