ComplexNonlinearEquationVerifier.java
/*
* Created on 2004/12/02
* Copyright (C) 2004 Koga Laboratory. All rights reserved.
*
*/
package org.mklab.cga.nonlinear;
import java.util.List;
import org.mklab.cga.derivative.IntervalDerivativeComplexMatrix;
import org.mklab.cga.derivative.IntervalDerivativeComplexNumber;
import org.mklab.cga.derivative.IntervalDerivativeFunction;
import org.mklab.cga.derivative.IntervalDerivativeFunctionEvaluation;
import org.mklab.cga.derivative.IntervalDerivativeRealMatrix;
import org.mklab.cga.derivative.IntervalDerivativeRealNumber;
import org.mklab.cga.interval.matrix.IntervalComplexNumericalMatrix;
import org.mklab.cga.interval.matrix.IntervalRealNumericalMatrix;
import org.mklab.cga.interval.scalar.IntervalComplexNumericalScalar;
import org.mklab.cga.interval.scalar.IntervalRealNumericalScalar;
import org.mklab.cga.util.IntervalUtil;
import org.mklab.nfc.matrix.ComplexNumericalMatrix;
import org.mklab.nfc.matrix.NormType;
import org.mklab.nfc.matrix.RealNumericalMatrix;
import org.mklab.nfc.scalar.ComplexNumericalScalar;
import org.mklab.nfc.scalar.RealNumericalScalar;
/**
* 非線形方程式の精度保証を行うクラスです。
*
* @author hiroki
* @version $Revision: 1.24 $.2004/12/02
* @param <RIDS> 実区間微分スカラーの型
* @param <RIDM> 実区間微分行列の型
* @param <CIDS> 複素区間微分スカラーの型
* @param <CIDM> 複素区間微分行列の型
* @param <RIS> 実区間スカラーの型
* @param <RIM> 実区間行列の型
* @param <CIS> 複素区間スカラーの型
* @param <CIM> 複素区間行列の型
* @param <RS> 実スカラーの型
* @param <RM> 実行列の型
* @param <CS> 複素スカラーの型
* @param <CM> 複素行列の型
*/
public class ComplexNonlinearEquationVerifier<RIDS extends IntervalDerivativeRealNumber<RIDS,RIDM,CIDS,CIDM,RIS,RIM,CIS,CIM,RS,RM,CS,CM>, RIDM extends IntervalDerivativeRealMatrix<RIDS,RIDM,CIDS,CIDM,RIS,RIM,CIS,CIM,RS,RM,CS,CM>, CIDS extends IntervalDerivativeComplexNumber<RIDS,RIDM,CIDS,CIDM,RIS,RIM,CIS,CIM,RS,RM,CS,CM>, CIDM extends IntervalDerivativeComplexMatrix<RIDS,RIDM,CIDS,CIDM,RIS,RIM,CIS,CIM,RS,RM,CS,CM>, RIS extends IntervalRealNumericalScalar<RIS,RIM,CIS,CIM,RS,RM,CS,CM>, RIM extends IntervalRealNumericalMatrix<RIS,RIM,CIS,CIM,RS,RM,CS,CM>, CIS extends IntervalComplexNumericalScalar<RIS,RIM,CIS,CIM,RS,RM,CS,CM>, CIM extends IntervalComplexNumericalMatrix<RIS,RIM,CIS,CIM,RS,RM,CS,CM>, RS extends RealNumericalScalar<RS,RM,CS,CM>, RM extends RealNumericalMatrix<RS,RM,CS,CM>, CS extends ComplexNumericalScalar<RS,RM,CS,CM>, CM extends ComplexNumericalMatrix<RS,RM,CS,CM>>{
/** 関数オブジェクト */
private IntervalDerivativeFunction<CIDS,CIDM,CIS,CIM,CS,CM> function;
// /** 初期値 */
// private M initialValue;
//
// /** 初期値区間 */
// private IM intervalInitialValue;
/** 非線形方程式の解 */
private CIM solution;
/**
* コンストラクタ
*
* @param function 関数オブジェクト
*/
public ComplexNonlinearEquationVerifier(IntervalDerivativeFunction<CIDS,CIDM,CIS,CIM,CS,CM> function) {
this.function = function;
}
/**
* 非線型方程式の解を精度保証付きで求めます。
*
* @param xs 初期値
* @param idm idm
* @return 非線形方程式の解
*/
public CIM solve(CM xs, CIDM idm) {
CIDS ids = idm.getElement(1,1);
CIS is = ids.getX();
CIM im = idm.getX();
int n = xs.getRowSize();
double sqrtN = Math.sqrt(n);
CM xss = xs.createClone();
CM xsold = xss;
CS element = xs.getElement(1);
CM dxs = xs.createZero();
CM dxsnew = (xs).absElementWise();
int k = 0;
CM y_x;
CM y_dx = null;
CIDS[] idxss = ids.createArray(xs.getRowSize());
IntervalDerivativeFunctionEvaluation<CIDS,CIDM,CIS,CIM,CS,CM> nee = new IntervalDerivativeFunctionEvaluation<>(this.function);
List<CIM> value1;
while (dxsnew.compareElementWise(".<", dxs.multiply(5)).anyTrue() //$NON-NLS-1$
&& (dxsnew).norm(NormType.TWO).isGreaterThan((xs).norm(NormType.TWO).multiply(sqrtN * 1e-14)) && k < 100 || k < 3) {
k = k + 1;
dxs = dxsnew.createClone();
xsold = xss.createClone();
for (int i = 0; i < xss.getRowSize(); i++) {
idxss[i] = ids.create(is.create((xss).getElement(i + 1)), is.create(element.createUnit()));
}
value1 = nee.getValues(idxss);
// f(x)
y_x = value1.get(0).getMiddle();
// ヤコビ行列
y_dx = value1.get(2).getMiddle();
xss = xss.subtract(y_dx.leftDivide(y_x));
dxsnew = xss.subtract(xsold).absElementWise();
}
CIM ixss = im.create(xss);
for (int i = 0; i < xss.getRowSize(); i++) {
idxss[i] = ids.create(ixss.getElement(i + 1), is.create(element.createUnit()));
}
// f(xss)とdf(xss)とヤコビ行列を求める
List<CIM> values = nee.getValues(idxss);
// apporoximate inver of IntervalDerivativeFunctionEvaluation
// TODO 区間にしてから、逆行列?
CIM R = im.create(y_dx.inverse());
// initialization of interval iteration
// TODO 多倍長だと?
CIM Z = R.unaryMinus().multiply(values.get(0));
CIM X = Z.createClone();
boolean ready = false;
k = 0;
CIM Y = null;
while (ready == false && k < 10) {
CM xRadius = X.getSupremum().subtract(X.getInfimum()).divide(2);
CIM E = im.create(xRadius.multiply(element.createUnit().divide(element.createUnit().multiply(10)))).multiply(is.createInfSup(element.createUnit().unaryMinus(), element.createUnit()))
.addElementWise(is.createInfSup(element.getMachineEpsilon().unaryMinus(), element.getMachineEpsilon()));
k = k + 1;
// TODO 本当はhull(X+E,0)?
Y = X.add(E);
CIM Yold = Y.createClone();
for (int i = 0; i < xs.getColumnSize(); i++) {
idxss[i] = ids.create(Y.add(im.create(xss)).getElement(i + 1), is.create(element.createUnit()));
}
values = nee.getValues(idxss);
// f(xs+Y)
// ? IntervalMatrix Iy_x = values[0];
// ヤコビ行列
CIM Iy_dx = values.get(2);
CIM C = im.create(xs.createUnit(n)).subtract(R.multiply(Iy_dx));
int i = 0;
// improved interval iteration
while (!ready && i < 2) {
i = i + 1;
X = Z.add(C.multiply(Y));
ready = IntervalUtil.in0forRump(X, Y).allTrue();
Y = IntervalUtil.intersect(X, Yold);
}
}
if (ready) {
X = Y.add(im.create(xss));
} else {
throw new IllegalArgumentException();
// TODO 例外投げるか、NaNを返すようにする
}
return X;
}
/**
* 非線型方程式の解を精度保証付きで求めます。
*
* <p>初期値区間に真の解が含まれる場合、非線形方程式の真の解を含むより小さな区間を返します。
*
* @param xs 初期値区間
* @param idm idm
* @return 非線形方程式の解
*/
public CIM solve(CIM xs, CIDM idm) {
CIDS ids = idm.getElement(1,1);
CIS is = ids.getX();
CIM im = idm.getX();
IntervalDerivativeFunctionEvaluation<CIDS,CIDM,CIS,CIM,CS,CM> nee = new IntervalDerivativeFunctionEvaluation<>(this.function);
CIM X = xs.createClone();
CS element = (xs.getMiddle()).getElement(1);
boolean ready = false;
int k = 0;
// TODO kの値はどれくらい?
while (ready == false && k < 10) {
k = k + 1;
CIDS[] idxs = ids.createArray(X.getRowSize());
for (int i = 0; i < X.getRowSize(); i++) {
idxs[i] = ids.create(is.create(X.getMiddle().getElement(i + 1)), is.create(element.createUnit()));
}
// f(xs)とdf(xs)とヤコビ行列を求める
List<CIM> values = nee.getValues(idxs);
CM y_dx = values.get(2).getMiddle();
// apporoximate inver of IntervalDerivativeFunctionEvaluation
CIM R = im.create(y_dx.inverse());
// initialization of interval iteration
CIM Z = R.unaryMinus().multiply(values.get(0));
CIM Y = X.subtract(im.create(X.getMiddle()));
CIDS[] idX = ids.createArray(X.getRowSize());
for (int i = 0; i < X.getRowSize(); i++) {
idX[i] = ids. create(X.getElement(i + 1), is.create(element.createUnit()));
}
values = nee.getValues(idX);
// ヤコビ行列 f'(X)
CIM Iy_dx = values.get(2);
int n = X.getRowSize();
CIM C = im.create(xs.getMiddle().createUnit(n)).subtract(R.multiply(Iy_dx));
CIM nextX = Z.add(C.multiply(Y)).add(im.create(X.getMiddle()));
ready = IntervalUtil.in0forRump(nextX, X).allTrue();
// 不動点定理によれば、元の集合を返すべき
// if (ready) {
// X = (IntervalMatrix)nextX.clone();
// }
}
// if (ready == false) {
// throw new IllegalArgumentException();
// }
return X;
}
// /**
// *
// */
// public void solve() {
// if (this.initialValue != null) {
// this.solution = this.solve(this.initialValue);
// } else {
// this.solution = this.solve(this.intervalInitialValue);
// }
// }
// /**
// * 初期値を設定します。
// *
// * @param initialValue 初期値
// */
// public void setInitialValue(M initialValue) {
// this.initialValue = initialValue;
// }
//
// /**
// * 初期値区間を設定します。
// *
// * @param intervalInitialValue 初期値区間
// */
// public void setIntervalInitialValue(IM intervalInitialValue) {
// this.intervalInitialValue = intervalInitialValue;
// }
}