/** * Return gradient term of quadratic. This instance will be in the vector space of the * perturbModel, if provided. Otherwise, uses an instance of the referenceModel. * * @return Value of <code> b = -F' N [data - f(m)] + Mm </code> if dampOnlyPerturbation is false, * and <code> b = -F' N [data - f(m)] </code> if dampOnlyPerturbation is true. */ public Vect getB() { Vect data = VectUtil.cloneZero(_data); // data is data with zeros _transform.forwardNonlinear(data, _referenceModel); // data is f(m) data.add(1., -1., _data); // data is -e = -(d - f(m)) _transform.adjustRobustErrors(data); // (remove outliers from e) data.multiplyInverseCovariance(); // data is -Ne Vect b = null; if (_dampOnlyPerturbation) { if (_perturbModel != null) { b = VectUtil.cloneZero(_perturbModel); // b is 0 } else { b = VectUtil.cloneZero(_referenceModel); // b is 0 } } else { if (_perturbModel != null) { b = _perturbModel.clone(); b.project(0., 1., _referenceModel); // b is m } else { b = _referenceModel.clone(); // b is m } b.multiplyInverseCovariance(); // b is M m } _transform.addTranspose(data, b, _referenceModel); // b is -F'Ne [+ Mm] data.dispose(); return b; }
/** * Multiply by Hessian <code> H = F'NF + M </code> * * @param x Vector to be multiplied and modified */ public void multiplyHessian(Vect x) { Vect data = _data.clone(); _transform.forwardLinearized(data, x, _referenceModel); // data is Fx data.multiplyInverseCovariance(); // data is NFx x.multiplyInverseCovariance(); // x is Mx _transform.addTranspose(data, x, _referenceModel); // x is (F'NF +M)x data.dispose(); }
/** * Evaluate the full objective function without approximation. Provide a model in the vector space * of the referenceModel. perturbModel is unused. Useful for line-search of best scale factor. If * dampedPerturbation, evaluates * * <pre> * [f(m)-data]'N[f(m)-data] + (m-m0)'M(m-m0) * </pre> * * where m0 is the reference model. Otherwise evaluates * * <pre> * [f(m)-data]'N[f(m)-data] + m'M m * </pre> * * @param m Model to be evaluated. * @return Value of objective function. */ public double evalFullObjectiveFunction(VectConst m) { Vect data = VectUtil.cloneZero(_data); // data is zeros Vect model = m.clone(); // model is m model.constrain(); // may have been done already _transform.forwardNonlinear(data, model); // data is f(m) data.add(1., -1., _data); // data is e = f(m) - data _transform.adjustRobustErrors(data); double eNe = data.magnitude(); // eNe is e'Ne checkNaN(eNe); data.dispose(); // damp perturbation if requested if (_dampOnlyPerturbation) { model.add(1., -1., _referenceModel); // model is (m-m0) } double mMm = model.magnitude(); // mMm is (m-m0)'M(m-m0) checkNaN(mMm); model.dispose(); return (eNe + mMm); }
// Quadratic public void inverseHessian(Vect x) { _transform.inverseHessian(x, _referenceModel); }
/** * Run a few tests to ensure that transpose satisfies definition. This is expensive and intended * only for test code. * * @return number of sigficant digits of precision in transpose. Expect 5 or 6. Unacceptable if * not 3 or more. A value of 3 or 4 probably indicates a subtle error. */ public int getTransposePrecision() { VectConst d = _data; // arbitrary nonzero data Vect b = this.getB(); // arbitrary nonzero model double bb = b.dot(b); checkNaN(bb); assert !Almost.FLOAT.zero(bb) : "Cannot test with zero-magnitude b"; // Get forward transform of b Vect Fb = VectUtil.cloneZero(d); Vect bSave = b.clone(); _transform.forwardLinearized(Fb, b, _referenceModel); // make sure didn't step on wrong vector assert VectUtil.areSame(b, bSave) : "model was changed by forward model"; bSave.dispose(); // check that forward zeros output data. Vect test = d.clone(); _transform.forwardLinearized(test, b, _referenceModel); assert VectUtil.areSame(test, Fb) : "forwardLinearized should zero data"; test.dispose(); // Get transpose of d Vect Ad = VectUtil.cloneZero(b); Vect dSave = d.clone(); _transform.addTranspose(d, Ad, _referenceModel); double transposeMagnitude = Ad.dot(Ad); checkNaN(transposeMagnitude); // make sure didn't step on wrong vector assert VectUtil.areSame(d, dSave) : "data was changed by transpose"; dSave.dispose(); // ensure that transpose adds to existing model test = b.clone(); // make initial size comparable to transpose double scaleTest = 1.1 * Math.sqrt(transposeMagnitude / bb); VectUtil.scale(test, scaleTest); _transform.addTranspose(d, test, _referenceModel); assert !VectUtil.areSame(Ad, test) : "Transpose should not zero model. " + "Magnitude: b=" + bb + "trans=" + transposeMagnitude + " test=" + test.dot(test); test.add(1., -1., Ad); VectUtil.scale(test, 1. / scaleTest); assert VectUtil.areSame(test, b) : "Transpose did not add to model vector"; test.dispose(); // get dot products that should be equal double dFb = d.dot(Fb); double Adb = Ad.dot(b); assert !Almost.FLOAT.zero(dFb) : "zero magnitude test: dFb is zero"; assert !Almost.FLOAT.zero(Adb) : "zero magnitude test: Adb is zero"; checkNaN(dFb); checkNaN(Adb); int significantDigits = 10; boolean matches = false; while (!matches && significantDigits > 0) { Almost almost = new Almost(significantDigits); matches = almost.equal(dFb, Adb); if (!matches) { --significantDigits; } } if (significantDigits < 3) { LOG.severe("Transpose precision is unacceptable: dFb=" + dFb + " Adb=" + Adb); } Ad.dispose(); Fb.dispose(); b.dispose(); return significantDigits; }