AbstractIntervalDerivativeNumber.java

/*
 * Created on 2004/12/14
 * Copyright (C) 2004 Koga Laboratory. All rights reserved.
 *
 */
package org.mklab.cga.derivative;

import org.mklab.cga.interval.matrix.IntervalNumericalMatrix;
import org.mklab.cga.interval.scalar.IntervalNumericalScalar;
import org.mklab.nfc.matrix.NumericalMatrix;
import org.mklab.nfc.scalar.AbstractNumericalScalar;
import org.mklab.nfc.scalar.NumericalScalar;


/**
 * 微分値を精度保証付きで求めるクラスです。
 * 
 * <p>自動微分法を実装しています。
 * 
 * @author hiroki
 * @version $Revision: 1.27 $.2004/12/14
 * @param <IDS> 区間微分スカラーの型
 * @param <IDM> 区間微分行列の型
 * @param <IS> 区間スカラーの型
 * @param <IM> 区間行列の型
 * @param <S> スカラーの型
 * @param <M> の型
 */
public abstract class AbstractIntervalDerivativeNumber<IDS extends IntervalDerivativeNumber<IDS ,IDM,IS,IM,S,M>, IDM extends IntervalDerivativeMatrix<IDS,IDM,IS,IM,S,M>, IS extends IntervalNumericalScalar<IS,IM,S,M>,  IM extends IntervalNumericalMatrix<IS,IM,S,M>,  S extends NumericalScalar<S,M>, M extends NumericalMatrix<S,M> > extends AbstractNumericalScalar<IDS,IDM> implements IntervalDerivativeNumber<IDS,IDM,IS,IM,S,M> {

  /** シリアル番号 */
  private static final long serialVersionUID = 5155625854053176474L;

  /** 任意の区間 */
  private IS x;

  /** xの微分値の区間 */
  private IS dx;

  /**
   * コンストラクター 定数の場合。
   * 
   * @param x 値
   */
  public AbstractIntervalDerivativeNumber(IS x) {
    this.x = x.clone();
    this.dx = this.x.createZero();
  }

//  /**
//   * コンストラクタ
//   * 
//   * @param x 値
//   */
//  public AbstractIntervalDerivative(double x) {
//    this.x = (IS)new DoubleIntervalNumber(x);
//    this.dx = this.x.createZero();
//  }
//
//  /**
//   * コンストラクタ
//   * 
//   * @param x 値
//   */
//  public AbstractIntervalDerivative(DoubleComplexNumber x) {
//    this.x = (IS)new DoubleComplexIntervalNumber(x);
//    this.dx = this.x.createZero();
//  }
//
//  /**
//   * 新しく生成された<code>IntervalDerivative</code>オブジェクトを初期化します。
//   * 
//   * @param x 値
//   */
//  public AbstractIntervalDerivative(T x) {
//    if (x instanceof DoubleNumber) {
//      this.x = (IS)new DoubleIntervalNumber(((DoubleNumber)x).doubleValue());
//      this.dx = this.x.createZero();
//    } else {
//      this.x = new AbstractIntervalRealNumericalScalar<>(x);
//      this.dx = this.x.createZero();
//    }
//  }

//  /**
//   * コンストラクタ
//   * 
//   * @param x 値
//   * @param dx 微分値
//   */
//  public AbstractIntervalDerivative(IS x, IS dx) {
//    this.x = x;
//    this.dx = dx;
//  }

//  /**
//   * 新しく生成された<code>IntervalDerivative</code>オブジェクトを初期化します。
//   * 
//   * @param x 値
//   * @param dx 微分値
//   */
//  public AbstractIntervalDerivative(T x, T dx) {
//    if (x instanceof DoubleNumber) {
//      this.x = (IS)new DoubleIntervalNumber(((DoubleNumber)x).doubleValue());
//    } else {
//      this.x = new AbstractIntervalRealNumericalScalar<>(x);
//    }
//    if (dx instanceof DoubleNumber) {
//      this.dx = (IS)new DoubleIntervalNumber(((DoubleNumber)dx).doubleValue());
//    } else {
//      this.dx = new AbstractIntervalRealNumericalScalar<>(dx);
//    }
//  }
//
//  /**
//   * コンストラクタ
//   * 
//   * @param x 値
//   * @param dx 微分値
//   */
//  public AbstractIntervalDerivative(DoubleComplexNumber x, DoubleComplexNumber dx) {
//    this.x = (IS)new DoubleComplexIntervalNumber(x);
//    this.dx = (IS)new DoubleComplexIntervalNumber(dx);
//  }

  /**
   * コンストラクタ
   * 
   * @param x 値
   * @param dx 微分値
   */
  public AbstractIntervalDerivativeNumber(IS x, IS dx) {
    this.x = x;
    this.dx = dx;
  }

//  /**
//   * @see org.mklab.nfc.scalar.Scalar#create(int)
//   */
//  public IDS create(final int value) {
//    return create(value);
//  }

  /**
   * <code>y</code>との和を返します。
   * 
   * @param y 自動微分型の値
   * @return 自身とyの和
   */
  public IDS add(final IDS y) {
    return create(this.x.add(y.getX()), this.dx.add(y.getDX()));
  }

  /**
   * <code>y</code>との差を返します。
   * 
   * @param y 自動微分型の値
   * @return 自身とyの差
   */
  public IDS subtract(final IDS y) {
    return create(this.x.subtract(y.getX()), this.dx.subtract(y.getDX()));
  }

  /**
   * <code>y</code>との積を返します。
   * 
   * @param y 自動微分型の値
   * @return 自身とyの積
   */
  public IDS multiply(final IDS y) {
    return create(this.x.multiply(y.getX()), this.x.multiply(y.getDX()).add(this.dx.multiply(y.getX())));
  }

  /**
   * <code>y</code>との商を返します。
   * 
   * @param y 自動微分型の値
   * @return 自身とyの商
   */
  public IDS divide(final IDS y) {
    return create(this.x.divide(y.getX()), (this.dx.multiply(y.getX()).subtract(this.x.multiply(y.getDX()))).divide(y.getX().multiply(y.getX())));
  }

  /**
   * @see org.mklab.nfc.scalar.Scalar#unaryMinus()
   */
  public IDS unaryMinus() {
    return create(this.x.unaryMinus(), this.dx.unaryMinus());
  }

  /**
   * <code>x</code>を取得します。
   * 
   * @return x
   */
  public IS getX() {
    return this.x;
  }

  /**
   * <code>dx</code>を取得します。
   * 
   * @return dx
   */
  public IS getDX() {
    return this.dx;
  }

  /**
   * <code>x</code>をセットします。
   * 
   * @param x xの微分値の区間
   */
  public void setX(IS x) {
    this.x = x.clone();
  }

  /**
   * <code>dx</code>をセットします。
   * 
   * @param dx xの微分値の区間
   */
  public void setDX(IS dx) {
    this.dx = dx.clone();
  }

  /**
   * Returns <code>true</code> if this <code>IntervalDerivative</code> is the same as the o argument.
   * 
   * @return <code>true</code> if this <code>IntervalDerivative</code> is the same as the o argument.
   */
  @Override
  public boolean equals(Object o) {
    if (this == o) {
      return true;
    }
    if (o == null) {
      return false;
    }
    if (o.getClass() != getClass()) {
      return false;
    }
    IDS castedObj = (IDS)o;
    return ((this.x == null ? castedObj.getX() == null : this.x.equals(castedObj.getX())) && (this.dx == null ? castedObj.getDX() == null : this.dx.equals(castedObj.getDX())));
  }

  /**
   * Override hashCode.
   * 
   * @return the Objects hashcode.
   */
  @Override
  public int hashCode() {
    int hashCode = 1;
    hashCode = 31 * hashCode + (this.x == null ? 0 : this.x.hashCode());
    hashCode = 31 * hashCode + (this.dx == null ? 0 : this.dx.hashCode());
    return hashCode;
  }

//  /**
//   * @see org.mklab.nfc.scalar.Scalar#add(org.mklab.nfc.scalar.Scalar)
//   */
//  @Override
//  public IDS add(final Scalar<?> value) {
//    if (value instanceof AbstractIntervalDerivative) {
//      return create(this.x.add(((AbstractIntervalDerivative)value).getX()), this.dx.add(((AbstractIntervalDerivative)value).getDX()));
//    } else if (value instanceof IntervalScalar) {
//      return create(this.x.add((IntervalScalar)value), this.dx);
//    } else if (value instanceof DoubleComplexNumber) {
//      return create(this.x.add((DoubleComplexNumber)value), this.dx);
//    } else {
//      throw new UnsupportedOperationException();
//    }
//  }

  /**
   * @see org.mklab.nfc.scalar.Scalar#add(double)
   */
  public IDS add(final double value) {
    return create(this.x.add(value), this.dx);
  }

  /**
   * @see org.mklab.nfc.scalar.Scalar#add(int)
   */
  public IDS add(final int value) {
    return create(this.x.add(value), this.dx);
  }

  //  /**
  //   * 自身に微分値を加えます。
  //   * 
  //   * @param value 加える微分値
  //   * @return 自身
  //   */
  //  public IntervalDerivative<?> addSelf(final IntervalDerivative<?> value) {
  //    this.x = (IS)this.x.add(value.x);
  //    this.dx = (IS)this.dx.add(value.dx);
  //    return this;
  //  }

  //  /**
  //   * @see org.mklab.nfc.scalar.Scalar#addSelf(org.mklab.nfc.scalar.Scalar)
  //   */
  //  public IntervalDerivative<?> addSelf(final Scalar<?> value) {
  //    return addSelf((IntervalDerivative<?>)value);
  //  }

  /**
   * @see org.mklab.nfc.scalar.Scalar#compare(java.lang.String, int)
   */
  public boolean compare(String operator, int opponent) {
    return false;
  }

  /**
   * @see org.mklab.nfc.scalar.Scalar#compare(java.lang.String, double)
   */
  public boolean compare(String operator, double opponent) {
    return false;
  }

  /**
   * @see org.mklab.nfc.scalar.Scalar#conjugate()
   */
  public IDS conjugate() {
    return (IDS)this;
  }

//  /**
//   * @see org.mklab.nfc.scalar.Scalar#createGrid(int, int, org.mklab.nfc.scalar.Scalar[][])
//   */
//  public IDM createGrid(int rowSize, int columnSize, Scalar<? extends Scalar<?>>[][] elements) {
//    return new AbstractIntervalDerivativeMatrix(rowSize, columnSize, (AbstractIntervalDerivative[][])elements);
//  }
//
//  /**
//   * @see org.mklab.nfc.scalar.Scalar#createGrid(org.mklab.nfc.scalar.Scalar[])
//   */
//  public IDM createGrid(Scalar<? extends Scalar<?>>[] elements) {
//    return new AbstractIntervalDerivativeMatrix(new AbstractIntervalDerivative[][] {(AbstractIntervalDerivative[])elements});
//  }

  /**
   * @see org.mklab.nfc.scalar.Scalar#createUnit()
   */
  public IDS createUnit() {
    return create(this.x.createUnit(), this.dx.createZero());
  }

//  /**
//   * @see org.mklab.nfc.scalar.Scalar#divide(org.mklab.nfc.scalar.Scalar)
//   */
//  @Override
//  public IDS divide(final Scalar<?> value) {
//    if (value instanceof AbstractIntervalDerivative) {
//      return new AbstractIntervalDerivative(this.x.divide(((AbstractIntervalDerivative)value).getX()), this.dx.multiply(((AbstractIntervalDerivative)value).getX())
//          .subtract(this.x.multiply(((AbstractIntervalDerivative)value).getDX())).divide(((AbstractIntervalDerivative)value).getX().multiply(((AbstractIntervalDerivative)value).getX())));
//    } else if (value instanceof IntervalScalar) {
//      return new AbstractIntervalDerivative(this.x.multiply((IntervalScalar)value), this.dx);
//    } else if (value instanceof DoubleComplexNumber) {
//      return new AbstractIntervalDerivative(this.x.multiply((DoubleComplexNumber)value), this.dx);
//    } else {
//      throw new UnsupportedOperationException();
//    }
//  }

  /**
   * @see org.mklab.nfc.scalar.Scalar#divide(double)
   */
  public IDS divide(final double value) {
    return create(this.x.divide(value), this.dx);
  }

  /**
   * @see org.mklab.nfc.scalar.Scalar#divide(int)
   */
  public IDS divide(final int value) {
    return create(this.x.divide(value), this.dx);
  }

//  /**
//   * @see org.mklab.nfc.scalar.Scalar#equals(org.mklab.nfc.scalar.Scalar, double)
//   */
//  @Override
//  public boolean equals(Scalar<?> opponent, double tolerance) {
//    if (!(opponent instanceof AbstractIntervalDerivative)) return false;
//    return equals((IDS)opponent, tolerance);
//  }

  /**
   * 許容範囲内で等しいか判定します。
   * 
   * @param opponent 比較する微分値成分
   * @param tolerance 許容誤差
   * @return 許容範囲内で等しければtrue、そうでなければfalse
   */
  public boolean equals(IDS opponent, double tolerance) {
    return this.x.subtract(opponent.getX()).abs().getSupremum().isLessThan(tolerance) && this.dx.subtract(opponent.getDX()).abs().getSupremum().isLessThan(tolerance);
  }

  /**
   * @see org.mklab.nfc.scalar.Scalar#inverse()
   */
  public IDS inverse() {
    IS one = this.x.createUnit(); // new DoubleIntervalNumber(1.0);
    return create(one.divide(this.x), one.divide(this.dx));
  }

  /**
   * @see org.mklab.nfc.scalar.Scalar#isFinite()
   */
  public boolean isFinite() {
    return (!isInfinite()) && (!isNaN());
  }

  /**
   * @see org.mklab.nfc.scalar.Scalar#isInfinite()
   */
  public boolean isInfinite() {
    return this.x.isFinite() || this.dx.isFinite();
  }

  /**
   * @see org.mklab.nfc.scalar.Scalar#isNaN()
   */
  public boolean isNaN() {
    return this.x.isNaN() || this.dx.isNaN();
  }

  /**
   * @see org.mklab.nfc.scalar.Scalar#isUnit()
   */
  public boolean isUnit() {
    return this.x.isUnit() && this.dx.isZero();
  }

  /**
   * @see org.mklab.nfc.scalar.Scalar#isUnit(double)
   */
  public boolean isUnit(double tolerance) {
    return this.x.isUnit(tolerance) && this.dx.isZero(tolerance);
  }

  /**
   * {@inheritDoc}
   */
  public boolean isUnit(IDS tolerance) {
    return this.x.isUnit(tolerance.getX()) && this.dx.isZero(tolerance.getX());
  }

  /**
   * @see org.mklab.nfc.scalar.Scalar#isZero(double)
   */
  public boolean isZero(double tolerance) {
    return this.x.isZero(tolerance) && this.dx.isZero(tolerance);
  }

  /**
   * {@inheritDoc}
   */
  public boolean isZero(IDS tolerance) {
    return this.x.isZero(tolerance.getX()) && this.dx.isZero(tolerance.getX());
  }

  /**
   * @see org.mklab.nfc.scalar.Scalar#leftDivide(org.mklab.nfc.scalar.Scalar)
   */
  @Override
  public IDS leftDivide(IDS value) {
    throw new UnsupportedOperationException();
  }

  /**
   * @see org.mklab.nfc.scalar.Scalar#leftDivide(double)
   */
  public IDS leftDivide(double value) {
    return this.inverse().multiply(value);
  }

  /**
   * @see org.mklab.nfc.scalar.Scalar#leftDivide(int)
   */
  public IDS leftDivide(int value) {
    return this.inverse().multiply(value);
  }

//  /**
//   * @see org.mklab.nfc.scalar.Scalar#multiply(org.mklab.nfc.scalar.Scalar)
//   */
//  @Override
//  public IDS multiply(final Scalar<?> value) {
//    if (value instanceof AbstractIntervalDerivative) {
//      return new AbstractIntervalDerivative(this.x.multiply(((AbstractIntervalDerivative)value).getX()), this.x.multiply(((AbstractIntervalDerivative)value).getDX()).add(this.dx.multiply(((AbstractIntervalDerivative)value).getX())));
//    } else if (value instanceof IntervalScalar) {
//      return new AbstractIntervalDerivative(this.x.multiply((IntervalScalar)value), this.dx);
//    } else if (value instanceof DoubleComplexNumber) {
//      return new AbstractIntervalDerivative(this.x.multiply((DoubleComplexNumber)value), this.dx);
//    } else {
//      throw new UnsupportedOperationException();
//    }
//  }

  /**
   * @see org.mklab.nfc.scalar.Scalar#multiply(double)
   */
  public IDS multiply(final double value) {
    return create(this.x.multiply(value), this.dx);
  }

  /**
   * @see org.mklab.nfc.scalar.Scalar#multiply(int)
   */
  public IDS multiply(final int value) {
    return create(this.x.multiply(value), this.dx);
  }

  /**
   * @see org.mklab.nfc.scalar.Scalar#power(int)
   */
  public IDS power(int scalar) {
    IDS value = this.clone();
    for (int i = 0; i < scalar; i++) {
      value = value.multiply(value);
    }
    return value;
  }

//  /**
//   * @see org.mklab.nfc.scalar.Scalar#subtract(org.mklab.nfc.scalar.Scalar)
//   */
//  @Override
//  public IDS subtract(final Scalar<?> value) {
//    if (value instanceof AbstractIntervalDerivative) {
//      return new AbstractIntervalDerivative(this.x.subtract(((AbstractIntervalDerivative)value).getX()), this.dx.subtract(((AbstractIntervalDerivative)value).getDX()));
//    } else if (value instanceof IntervalScalar) {
//      return new AbstractIntervalDerivative(this.x.subtract((IntervalScalar)value), this.dx);
//    } else if (value instanceof DoubleComplexNumber) {
//      return new AbstractIntervalDerivative(this.x.subtract((DoubleComplexNumber)value), this.dx);
//    } else {
//      throw new UnsupportedOperationException();
//    }
//  }

  /**
   * @see org.mklab.nfc.scalar.Scalar#subtract(double)
   */
  public IDS subtract(final double value) {
    return create(this.x.subtract(value), this.dx);
  }

  /**
   * @see org.mklab.nfc.scalar.Scalar#subtract(int)
   */
  public IDS subtract(final int value) {
    return create(this.x.subtract(value), this.dx);
  }

//  /**
//   * @see org.mklab.nfc.scalar.Scalar#transformFrom(int)
//   */
//  public IDS transformFrom(int value) {
//    return null;
//  }
//
//  /**
//   * @see org.mklab.nfc.scalar.Scalar#transformFrom(double)
//   */
//  public IDS transformFrom(double value) {
//    return null;
//  }

  /**
   * {@inheritDoc}
   */
  public boolean compare(String operator, IDS opponent) {
    return false;
  }

//  /**
//   * @see org.mklab.nfc.matrix.GridElement#createArray(int)
//   */
//  public IDS[] createArray(int size) {
//    return new AbstractIntervalDerivative[size];
//  }
//
//  /**
//   * @see org.mklab.nfc.matrix.GridElement#createArray(int, int)
//   */
//  public IDS[][] createArray(int rowSize, int columnSize) {
//    return new AbstractIntervalDerivative[rowSize][columnSize];
//  }

//  /**
//   * @see org.mklab.nfc.matrix.GridElement#createArray(org.mklab.nfc.matrix.GridElement[])
//   */
//  public IDS[] createArray(GridElement<?>[] elements) {
//    final int size = elements.length;
//    final IDS[] array = (IDS[])elements[0].createArray(size);
//    System.arraycopy(elements, 0, array, 0, size);
//    return array;
//  }
//
//  /**
//   * @see org.mklab.nfc.matrix.GridElement#createArray(GridElement[][])
//   */
//  public IDS[][] createArray(GridElement<?>[][] elements) {
//    final int rowSize = elements.length;
//    final int columnSize = rowSize == 0 ? 0 : elements[0].length;
//    final IDS[][] array = (IDS[][])elements[0][0].createArray(rowSize, columnSize);
//    for (int row = 0; row < rowSize; row++) {
//      System.arraycopy(elements[row], 0, array[row], 0, columnSize);
//    }
//    return array;
//  }

  /**
   * @see org.mklab.nfc.matrix.GridElement#createZero()
   */
  public IDS createZero() {
    return create(this.x.createZero(), this.dx.createZero());
  }

//  /**
//   * @see org.mklab.nfc.scalar.AbstractScalar#isTransformableFrom(org.mklab.nfc.matrix.GridElement)
//   */
//  @Override
//  public boolean isTransformableFrom(GridElement<?> value) {
//    return false;
//  }
//
//  /**
//   * @see org.mklab.nfc.scalar.AbstractScalar#isTransformableTo(org.mklab.nfc.matrix.GridElement)
//   */
//  @Override
//  public boolean isTransformableTo(GridElement<?> value) {
//    return false;
//  }

  /**
   * @see org.mklab.nfc.matrix.GridElement#isZero()
   */
  public boolean isZero() {
    return this.x.isZero() && this.dx.isZero();
  }

//  /**
//   * @see org.mklab.nfc.scalar.AbstractScalar#transformFrom(org.mklab.nfc.matrix.GridElement)
//   */
//  @Override
//  public IDS transformFrom(GridElement<?> value) {
//    return null;
//  }
//
//  /**
//   * @see org.mklab.nfc.scalar.AbstractScalar#transformTo(org.mklab.nfc.matrix.GridElement)
//   */
//  @Override
//  public GridElement<?> transformTo(GridElement<?> value) {
//    return null;
//  }

  /**
   * @see org.mklab.nfc.scalar.RoundableToInteger#ceil()
   */
  public IDS ceil() {
    return create(this.x.ceil(), this.dx.ceil());
  }

  /**
   * @see org.mklab.nfc.scalar.RoundableToInteger#fix()
   */
  public IDS fix() {
    return create(this.x.fix(), this.dx.fix());
  }

  /**
   * @see org.mklab.nfc.scalar.RoundableToInteger#floor()
   */
  public IDS floor() {
    return create(this.x.floor(), this.dx.floor());
  }

  /**
   * @see org.mklab.nfc.scalar.RoundableToInteger#round()
   */
  public IDS round() {
    return create(this.x.round(), this.dx.round());
  }

  /**
   * @see org.mklab.nfc.scalar.RoundableToInteger#roundToZero(double)
   */
  public IDS roundToZero(double tolerance) {
    return create(this.x.roundToZero(tolerance), this.dx.roundToZero(tolerance));
  }

  /**
   * {@inheritDoc}
   */
  public IDS roundToZero(IDS tolerance) {
    return create(this.x.roundToZero(tolerance.getX()), this.dx.roundToZero(tolerance.getX()));
  }

//  /**
//   * @see org.mklab.nfc.scalar.Scalar#getAddOperator()
//   */
//  public ScalarOperator getAddOperator() {
//    throw new UnsupportedOperationException();
//  }
//
//  /**
//   * @see org.mklab.nfc.scalar.Scalar#getDivideOperator()
//   */
//  public ScalarOperator getDivideOperator() {
//    throw new UnsupportedOperationException();
//  }
//
//  /**
//   * @see org.mklab.nfc.scalar.Scalar#getLeftDivideOperator()
//   */
//  public ScalarOperator getLeftDivideOperator() {
//    throw new UnsupportedOperationException();
//  }
//
//  /**
//   * @see org.mklab.nfc.scalar.Scalar#getMultiplyOperator()
//   */
//  public ScalarOperator getMultiplyOperator() {
//    throw new UnsupportedOperationException();
//  }
//
//  /**
//   * @see org.mklab.nfc.scalar.Scalar#getSubtractOperator()
//   */
//  public ScalarOperator getSubtractOperator() {
//    throw new UnsupportedOperationException();
//  }
//
//  /**
//   * @see org.mklab.nfc.scalar.Scalar#getEqualOperator()
//   */
//  public ScalarEqual getEqualOperator() {
//    throw new UnsupportedOperationException();
//  }

  /**
   * @see org.mklab.nfc.scalar.Scalar#toString(java.lang.String)
   */
  public String toString(String valueFormat) {
    throw new UnsupportedOperationException();
  }

  /**
   * @see org.mklab.nfc.scalar.Scalar#isComplex()
   */
  public boolean isComplex() {
    return false;
  }

  /**
   * @see org.mklab.nfc.scalar.Scalar#isReal()
   */
  public boolean isReal() {
    return true;
  }

//  /**
//   * @see org.mklab.nfc.scalar.Scalar#setRealPart(org.mklab.nfc.scalar.Scalar)
//   */
//  public void setRealPart(Scalar<?> realPart) {
//    throw new UnsupportedOperationException();
//  }

//  /**
//   * @see org.mklab.nfc.scalar.Scalar#setImaginaryPart(org.mklab.nfc.scalar.Scalar)
//   */
//  public void setImaginaryPart(Scalar<?> imagPart) {
//    throw new UnsupportedOperationException();
//  }

  /**
   * @return result
   */
  public IDS toComplex() {
    throw new UnsupportedOperationException();
  }
}