blob: 9f81ca186147b99b9cf6dde3e78fbfac91cc40f9 [file] [log] [blame]
// Licensed to the Apache Software Foundation (ASF) under one
// or more contributor license agreements. See the NOTICE file
// distributed with this work for additional information
// regarding copyright ownership. The ASF licenses this file
// to you under the Apache License, Version 2.0 (the
// "License"); you may not use this file except in compliance
// with the License. You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing,
// software distributed under the License is distributed on an
// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
// KIND, either express or implied. See the License for the
// specific language governing permissions and limitations
// under the License.
package org.spaceroots.mantissa.algebra;
import java.io.Serializable;
import java.math.BigInteger;
import java.util.Arrays;
/** This class implements polynomials with one unknown.
* <p>This is an abstract class that only declares general methods but
* does not hold the coefficients by themselves. Specific subclasses
* are used to handle exact rational coefficients or approximate real
* coefficients. This design is taken from the various java.awt.geom
* classes (Point2D, Rectangle2D ...)</p>
* <p>The methods implemented deal mainly with the polynomials algebra
* (addition, multiplication ...) but the analysis aspects are also
* considered (value of the polynom for a given unknown,
* derivative).</p>
* <p>Instances of this class are immutable.</p>
* @version $Id$
* @author L. Maisonobe
*/
public abstract class Polynomial implements Serializable {
/** Check if the instance is the null polynomial.
* @return true if the polynomial is null
*/
public abstract boolean isZero();
/** Check if the instance is the constant unit polynomial.
* @return true if the polynomial is the constant unit polynomial
*/
public abstract boolean isOne();
/** Check if the instance is the identity polynomial.
* @return true if the polynomial is the identity polynomial
*/
public abstract boolean isIdentity();
/** Get the polynomial degree.
* @return degree
*/
public abstract int getDegree();
/** Negate the instance.
* @return a new polynomial
*/
public abstract Polynomial negate();
/** Multiply the instance by a constant.
* @param r constant to multiply by
* @return a new polynomial
*/
public abstract Polynomial multiply(RationalNumber r);
/** Multiply the instance by a constant.
* @param l constant to multiply by
* @return a new Polynomial
*/
public abstract Polynomial multiply(long l);
/** Multiply the instance by a constant.
* @param i constant to multiply by
* @return a new Polynomial
*/
public Polynomial multiply(BigInteger i) {
return multiply(new RationalNumber(i));
}
/** Divide the instance by a constant.
* @param l constant to multiply by
* @return a new polynomial
* @exception ArithmeticException if the constant is zero
*/
public Polynomial divide(long l) {
return divide(new RationalNumber(l));
}
/** Divide the instance by a constant.
* @param r constant to multiply by
* @return a new polynomial
* @exception ArithmeticException if the constant is zero
*/
public Polynomial divide(RationalNumber r) {
return multiply(r.invert());
}
/** Divide the instance by a constant.
* @param i constant to multiply by
* @return a new polynomial
* @exception ArithmeticException if the constant is zero
*/
public Polynomial divide(BigInteger i) {
return divide(new RationalNumber(i));
}
/** Get the value of the polynomial for a specified unknown.
* @param x value of the unknown
* @return value of the polynomial
*/
public abstract double valueAt(double x);
/** Get the derivative of the instance with respect to the unknown.
* The derivative of a n degree polynomial is a n-1 degree polynomial of
* the same type.
* @return a new polynomial which is the derivative of the instance
*/
public abstract Polynomial getDerivative();
/** This class implements polynomials with one unknown and rational
* coefficients.
* <p>In addition to classical algebra operations, euclidian
* division and remainder are handled.</p>
*/
public static class Rational extends Polynomial {
/** Simple constructor.
* Build a null polynomial
*/
public Rational() {
a = new RationalNumber[] { RationalNumber.ZERO };
}
/** Simple constructor.
* Build a constant polynomial
* @param value constant value of the polynomial
*/
public Rational(long value) {
this(new RationalNumber(value));
}
/** Simple constructor.
* Build a constant polynomial
* @param value constant value of the polynomial
*/
public Rational(RationalNumber value) {
a = new RationalNumber[] { value };
}
/** Simple constructor.
* Build a first degree polynomial
* @param a1 leeding degree coefficient
* @param a0 constant term
*/
public Rational(long a1, long a0) {
this(new RationalNumber(a1), new RationalNumber(a0));
}
/** Simple constructor.
* Build a first degree polynomial
* @param a1 leeding degree coefficient
* @param a0 constant term
*/
public Rational(RationalNumber a1, RationalNumber a0) {
if (! a1.isZero()) {
a = new RationalNumber[] { a0, a1 };
} else {
a = new RationalNumber[] { a0 };
}
}
/** Simple constructor.
* Build a second degree polynomial
* @param a2 leeding degree coefficient
* @param a1 first degree coefficient
* @param a0 constant term
*/
public Rational(long a2, long a1, long a0) {
this(new RationalNumber(a2),
new RationalNumber(a1),
new RationalNumber(a0));
}
/** Simple constructor.
* Build a second degree polynomial
* @param a2 leeding degree coefficient
* @param a1 first degree coefficient
* @param a0 constant term
*/
public Rational(RationalNumber a2, RationalNumber a1, RationalNumber a0) {
if (! a2.isZero()) {
a = new RationalNumber[] { a0, a1, a2 };
} else {
if (! a1.isZero()) {
a = new RationalNumber[] { a0, a1 };
} else {
a = new RationalNumber[] { a0 };
}
}
}
/** Simple constructor.
* Build a third degree polynomial
* @param a3 leeding degree coefficient
* @param a2 second degree coefficient
* @param a1 first degree coefficient
* @param a0 constant term
*/
public Rational(long a3, long a2, long a1, long a0) {
this(new RationalNumber(a3),
new RationalNumber(a2),
new RationalNumber(a1),
new RationalNumber(a0));
}
/** Simple constructor.
* Build a third degree polynomial
* @param a3 leeding degree coefficient
* @param a2 second degree coefficient
* @param a1 first degree coefficient
* @param a0 constant term
*/
public Rational(RationalNumber a3, RationalNumber a2,
RationalNumber a1, RationalNumber a0) {
if (! a3.isZero()) {
a = new RationalNumber[] { a0, a1, a2, a3 };
} else {
if (! a2.isZero()) {
a = new RationalNumber[] { a0, a1, a2 };
} else {
if (! a1.isZero()) {
a = new RationalNumber[] { a0, a1 };
} else {
a = new RationalNumber[] { a0 };
}
}
}
}
/** Simple constructor.
* Build a polynomial from its coefficients
* @param a coefficients array, the a[0] array element is the
* constant term while the a[a.length-1] element is the leeding
* degree coefficient. The array is copied in a new array, so it
* can be changed once the constructor as returned.
*/
public Rational(RationalNumber[] a) {
// remove null high degree coefficients
int i = a.length - 1;
while ((i > 0) && (a[i].isZero())) {
--i;
}
// copy the remaining coefficients
this.a = new RationalNumber[i + 1];
System.arraycopy(a, 0, this.a, 0, i + 1);
}
/** Simple constructor.
* Build a one term polynomial from one coefficient and the corresponding degree
* @param c coefficient
* @param degree degree associated with the coefficient
*/
public Rational(RationalNumber c, int degree) {
if (c.isZero() || degree < 0) {
a = new RationalNumber[] { RationalNumber.ZERO };
} else {
a = new RationalNumber[degree + 1];
Arrays.fill(a, 0, degree, RationalNumber.ZERO);
a[degree] = c;
}
}
/** Check if the instance is the null polynomial.
* @return true if the polynomial is null
*/
public boolean isZero() {
return (a.length == 1) && a[0].isZero();
}
/** Check if the instance is the constant unit polynomial.
* @return true if the polynomial is the constant unit polynomial
*/
public boolean isOne() {
return (a.length == 1) && a[0].isOne();
}
/** Check if the instance is the identity polynomial.
* @return true if the polynomial is the identity polynomial
*/
public boolean isIdentity() {
return (a.length == 2) && a[0].isZero() && a[1].isOne();
}
/** Get the polynomial degree.
* @return degree
*/
public int getDegree() {
return a.length - 1;
}
/** Get the coefficients of the polynomial.
* @return a copy of the coefficients array, the array
* element at index 0 is the constant term while the element at
* index a.length-1 is the leading degree coefficient
*/
public RationalNumber[] getCoefficients() {
return (RationalNumber[]) a.clone();
}
/** Add a polynomial to the instance
* @param p polynomial to add
* @return a new polynomial which is the sum of the instance and p
*/
public Rational add(Rational p) {
// identify the lowest degree polynomial
int lowLength = Math.min(a.length, p.a.length);
int highLength = Math.max(a.length, p.a.length);
// build the coefficients array
RationalNumber[] newA = new RationalNumber[highLength];
for (int i = 0; i < lowLength; ++i) {
newA[i] = a[i].add(p.a[i]);
}
System.arraycopy((a.length < p.a.length) ? p.a : a,
lowLength, newA, lowLength, highLength - lowLength);
return new Rational(newA);
}
/** Subtract a polynomial from the instance.
* @param p polynomial to subtract
* @return a new polynomial which is the difference the instance minus p
*/
public Rational subtract(Rational p) {
// identify the lowest degree polynomial
int lowLength = Math.min(a.length, p.a.length);
int highLength = Math.max(a.length, p.a.length);
// build the coefficients array
RationalNumber[] newA = new RationalNumber[highLength];
for (int i = 0; i < lowLength; ++i) {
newA[i] = a[i].subtract(p.a[i]);
}
if (a.length < p.a.length) {
for (int i = lowLength; i < highLength; ++i) {
newA[i] = p.a[i].negate();
}
} else {
System.arraycopy(a, lowLength, newA, lowLength, highLength - lowLength);
}
return new Rational(newA);
}
/** Negate the instance.
* @return a new polynomial
*/
public Polynomial negate() {
RationalNumber[] newA = new RationalNumber[a.length];
for (int i = 0; i < a.length; ++i) {
newA[i] = a[i].negate();
}
return new Rational(newA);
}
/** Multiply the instance by a polynomial.
* @param p polynomial to multiply by
* @return a new polynomial
*/
public Rational multiply(Rational p) {
RationalNumber[] newA = new RationalNumber[a.length + p.a.length - 1];
for (int i = 0; i < newA.length; ++i) {
newA[i] = RationalNumber.ZERO;
for (int j = Math.max(0, i + 1 - p.a.length);
j < Math.min(a.length, i + 1);
++j) {
newA[i] = newA[i].add(a[j].multiply(p.a[i-j]));
}
}
return new Rational(newA);
}
/** Multiply the instance by a constant.
* @param l constant to multiply by
* @return a new polynomial
*/
public Polynomial multiply(long l) {
return multiply(new RationalNumber(l));
}
/** Multiply the instance by a constant.
* @param r constant to multiply by
* @return a new polynomial
*/
public Polynomial multiply(RationalNumber r) {
if (r.isZero()) {
return new Rational(new RationalNumber[] { RationalNumber.ZERO });
}
if (r.isOne()) {
return this;
}
RationalNumber[] newA = new RationalNumber[a.length];
for (int i = 0; i < a.length; ++i) {
newA[i] = a[i].multiply(r);
}
return new Rational(newA);
}
/** Get the value of the polynomial for a specified unknown.
* @param x value of the unknown
* @return value of the polynomial
*/
public double valueAt(double x) {
double y = 0;
for (int i = a.length - 1; i >= 0; --i) {
y = y * x + a[i].doubleValue();
}
return y;
}
/** Get the derivative of the instance with respect to the unknown.
* The derivative of a n degree polynomial is a n-1 degree polynomial of
* the same type.
* @return a new polynomial which is the derivative of the instance
*/
public Polynomial getDerivative() {
if (a.length == 1) {
return new Rational();
}
RationalNumber[] newA = new RationalNumber[a.length - 1];
for (int i = 1; i < a.length; ++i) {
newA[i - 1] = a[i].multiply(i);
}
return new Rational(newA);
}
/** Perform the euclidian division of two polynomials.
* @param dividend numerator polynomial
* @param divisor denominator polynomial
* @return an object containing the quotient and the remainder of the division
*/
public static DivisionResult euclidianDivision(Rational dividend,
Rational divisor) {
Rational quotient = new Rational(0l);
Rational remainder = dividend;
int divisorDegree = divisor.getDegree();
int remainderDegree = remainder.getDegree();
while ((! remainder.isZero()) && (remainderDegree >= divisorDegree)) {
RationalNumber c =
remainder.a[remainderDegree].divide(divisor.a[divisorDegree]);
Rational monomial = new Rational(c, remainderDegree - divisorDegree);
remainder = remainder.subtract(monomial.multiply(divisor));
quotient = quotient.add(monomial);
remainderDegree = remainder.getDegree();
}
return new DivisionResult(quotient, remainder);
}
/** Get the Least Common Multiple of the coefficients denominators.
* This number is the smallest integer by which we should multiply
* the instance to get a polynomial whose coefficients are all integers.
* @return the Least Common Multiple of the coefficients denominators
*/
public BigInteger getDenominatorsLCM() {
BigInteger lcm = BigInteger.ONE;
for (int i = 0; i < a.length; ++i) {
RationalNumber newCoeff = a[i].multiply(lcm);
if (! newCoeff.isInteger()) {
lcm = lcm.multiply(newCoeff.getDenominator());
}
}
return lcm;
}
/** Returns a string representation of the polynomial.
* <p>The representation is user oriented. Terms are displayed lowest
* degrees first. The multiplications signs, coefficients equals to
* one and null terms are not displayed (except if the polynomial is 0,
* in which case the 0 constant term is displayed). Addition of terms
* with negative coefficients are replaced by subtraction of terms
* with positive coefficients except for the first displayed term
* (i.e. we display <code>-3</code> for a constant negative polynomial,
* but <code>1 - 3 x + x^2</code> if the negative coefficient is not
* the first one displayed).</p>
* @return a string representation of the polynomial
*/
public String toString() {
StringBuffer s = new StringBuffer();
if (a[0].isZero()) {
if (a.length == 1) {
return "0";
}
} else {
s.append(a[0].toString());
}
for (int i = 1; i < a.length; ++i) {
if (! a[i].isZero()) {
if (s.length() > 0) {
if (a[i].isNegative()) {
s.append(" - ");
} else {
s.append(" + ");
}
} else {
if (a[i].isNegative()) {
s.append("-");
}
}
RationalNumber absAi = RationalNumber.abs(a[i]);
if (! absAi.isOne()) {
s.append(absAi.toString());
s.append(' ');
}
s.append("x");
if (i > 1) {
s.append('^');
s.append(Integer.toString(i));
}
}
}
return s.toString();
}
/** Coefficients array. */
protected RationalNumber[] a;
private static final long serialVersionUID = -794133890636181115L;
}
/** This class stores the result of the euclidian division of two polynomials.
* This class is a simple placeholder, it does not provide any
* processing method
* @see Polynomial.Rational#euclidianDivision
*/
public static class DivisionResult {
/** The quotient of the division. */
public final Rational quotient;
/** The remainder of the division. */
public final Rational remainder;
/** Simple constructor. */
public DivisionResult(Rational quotient, Rational remainder) {
this.quotient = quotient;
this.remainder = remainder;
}
}
/** This class implements polynomials with one unknown and real
* coefficients.
*/
public static class Double extends Polynomial {
/** Simple constructor.
* Build a null polynomial
*/
public Double() {
a = new double[] { 0.0 };
}
/** Simple constructor.
* Build a constant polynomial
* @param value constant value of the polynomial
*/
public Double(long value) {
this((double) value);
}
/** Simple constructor.
* Build a constant polynomial
* @param value constant value of the polynomial
*/
public Double(double value) {
a = new double[] { value };
}
/** Simple constructor.
* Build a first degree polynomial
* @param a1 leeding degree coefficient
* @param a0 constant term
*/
public Double(long a1, long a0) {
this((double) a1, (double) a0);
}
/** Simple constructor.
* Build a first degree polynomial
* @param a1 leeding degree coefficient
* @param a0 constant term
*/
public Double(double a1, double a0) {
if (a1 != 0) {
a = new double[] { a0, a1 };
} else {
a = new double[] { a0 };
}
}
/** Simple constructor.
* Build a second degree polynomial
* @param a2 leeding degree coefficient
* @param a1 first degree coefficient
* @param a0 constant term
*/
public Double(long a2, long a1, long a0) {
this((double) a2, (double) a1, (double) a0);
}
/** Simple constructor.
* Build a second degree polynomial
* @param a2 leeding degree coefficient
* @param a1 first degree coefficient
* @param a0 constant term
*/
public Double(double a2, double a1, double a0) {
if (a2 != 0) {
a = new double[] { a0, a1, a2 };
} else {
if (a1 != 0) {
a = new double[] { a0, a1 };
} else {
a = new double[] { a0 };
}
}
}
/** Simple constructor.
* Build a third degree polynomial
* @param a3 leeding degree coefficient
* @param a2 second degree coefficient
* @param a1 first degree coefficient
* @param a0 constant term
*/
public Double(long a3, long a2, long a1, long a0) {
this((double) a3, (double) a2, (double) a1, (double) a0);
}
/** Simple constructor.
* Build a third degree polynomial
* @param a3 leeding degree coefficient
* @param a2 second degree coefficient
* @param a1 first degree coefficient
* @param a0 constant term
*/
public Double(double a3, double a2, double a1, double a0) {
if (a3 != 0) {
a = new double[] { a0, a1, a2, a3 };
} else {
if (a2 != 0) {
a = new double[] { a0, a1, a2 };
} else {
if (a1 != 0) {
a = new double[] { a0, a1 };
} else {
a = new double[] { a0 };
}
}
}
}
/** Simple constructor.
* Build a polynomial from its coefficients
* @param a coefficients array, the a[0] array element is the
* constant term while the a[a.length-1] element is the leeding
* degree coefficient. The array is copied in a new array, so it
* can be changed once the constructor as returned.
*/
public Double(double[] a) {
// remove null high degree coefficients
int i = a.length - 1;
while ((i > 0) && (a[i] == 0)) {
--i;
}
// copy the remaining coefficients
this.a = new double[i + 1];
System.arraycopy(a, 0, this.a, 0, i + 1);
}
/** Simple constructor.
* Build a one term polynomial from one coefficient and the corresponding degree
* @param c coefficient
* @param degree degree associated with the coefficient
*/
public Double(double c, int degree) {
if ((c == 0) || degree < 0) {
a = new double[] { 0.0 };
} else {
a = new double[degree + 1];
Arrays.fill(a, 0, degree, 0.0);
a[degree] = c;
}
}
/** Simple constructor.
* Build a {@link Polynomial.Double Polynomial.Double} from a
* {@link Polynomial.Rational Polynomial.Rational}
* @param r a rational polynomial
*/
public Double(Rational r) {
// convert the coefficients
a = new double[r.a.length];
for (int i = 0; i < a.length; ++i) {
a[i] = r.a[i].doubleValue();
}
}
/** Check if the instance is the null polynomial.
* @return true if the polynomial is null
*/
public boolean isZero() {
return (a.length == 1) && (a[0] == 0);
}
/** Check if the instance is the constant unit polynomial.
* @return true if the polynomial is the constant unit polynomial
*/
public boolean isOne() {
return (a.length == 1) && ((a[0] - 1.0) == 0);
}
/** Check if the instance is the identity polynomial.
* @return true if the polynomial is the identity polynomial
*/
public boolean isIdentity() {
return (a.length == 2) && (a[0] == 0) && ((a[1] - 1.0) == 0);
}
/** Get the polynomial degree.
* @return degree
*/
public int getDegree() {
return a.length - 1;
}
/** Get the coefficients of the polynomial.
* @return a copy of the coefficients array, the array
* element at index 0 is the constant term while the element at
* index a.length-1 is the leading degree coefficient
*/
public double[] getCoefficients() {
return (double[]) a.clone();
}
/** Add a polynomial to the instance
* @param p polynomial to add
* @return a new polynomial which is the sum of the instance and p
*/
public Double add(Double p) {
// identify the lowest degree polynomial
int lowLength = Math.min(a.length, p.a.length);
int highLength = Math.max(a.length, p.a.length);
// build the coefficients array
double[] newA = new double[highLength];
for (int i = 0; i < lowLength; ++i) {
newA[i] = a[i] + p.a[i];
}
System.arraycopy((a.length < p.a.length) ? p.a : a,
lowLength, newA, lowLength, highLength - lowLength);
return Double.valueOf(newA);
}
/** Subtract a polynomial from the instance.
* @param p polynomial to subtract
* @return a new polynomial which is the difference the instance minus p
*/
public Double subtract(Double p) {
// identify the lowest degree polynomial
int lowLength = Math.min(a.length, p.a.length);
int highLength = Math.max(a.length, p.a.length);
// build the coefficients array
double[] newA = new double[highLength];
for (int i = 0; i < lowLength; ++i) {
newA[i] = a[i] - p.a[i];
}
if (a.length < p.a.length) {
for (int i = lowLength; i < highLength; ++i) {
newA[i] = -p.a[i];
}
} else {
System.arraycopy(a, lowLength, newA, lowLength, highLength - lowLength);
}
return Double.valueOf(newA);
}
/** Negate the instance.
* @return a new polynomial
*/
public Polynomial negate() {
double[] newA = new double[a.length];
for (int i = 0; i < a.length; ++i) {
newA[i] = -a[i];
}
return Double.valueOf(newA);
}
/** Multiply the instance by a polynomial.
* @param p polynomial to multiply by
* @return a new polynomial
*/
public Double multiply(Double p) {
double[] newA = new double[a.length + p.a.length - 1];
for (int i = 0; i < newA.length; ++i) {
newA[i] = 0.0;
for (int j = Math.max(0, i + 1 - p.a.length);
j < Math.min(a.length, i + 1);
++j) {
newA[i] += a[j] * p.a[i-j];
}
}
return Double.valueOf(newA);
}
/** Multiply the instance by a constant.
* @param l constant to multiply by
* @return a new polynomial
*/
public Polynomial multiply(long l) {
return multiply((double) l);
}
/** Multiply the instance by a constant.
* @param r constant to multiply by
* @return a new polynomial
*/
public Polynomial multiply(RationalNumber r) {
return multiply(r.doubleValue());
}
/** Multiply the instance by a constant.
* @param r constant to multiply by
* @return a new polynomial
*/
public Polynomial multiply(double r) {
if (r == 0) {
return Double.valueOf(new double[] { 0.0 });
}
double[] newA = new double[a.length];
for (int i = 0; i < a.length; ++i) {
newA[i] = a[i] * r;
}
return Double.valueOf(newA);
}
/** Get the value of the polynomial for a specified unknown.
* @param x value of the unknown
* @return value of the polynomial
*/
public double valueAt(double x) {
double y = 0;
for (int i = a.length - 1; i >= 0; --i) {
y = y * x + a[i];
}
return y;
}
/** Get the derivative of the instance with respect to the unknown.
* The derivative of a n degree polynomial is a n-1 degree polynomial of
* the same type.
* @return a new polynomial which is the derivative of the instance
*/
public Polynomial getDerivative() {
if (a.length == 1) {
return Double.valueOf();
}
double[] newA = new double[a.length - 1];
for (int i = 1; i < a.length; ++i) {
newA[i - 1] = a[i] * i;
}
return Double.valueOf(newA);
}
/** Returns a string representation of the polynomial.
* <p>The representation is user oriented. Terms are displayed lowest
* degrees first. The multiplications signs, coefficients equals to
* one and null terms are not displayed (except if the polynomial is 0,
* in which case the 0 constant term is displayed). Addition of terms
* with negative coefficients are replaced by subtraction of terms
* with positive coefficients except for the first displayed term
* (i.e. we display <code>-3</code> for a constant negative polynomial,
* but <code>1 - 3 x + x^2</code> if the negative coefficient is not
* the first one displayed).</p>
* @return a string representation of the polynomial
*/
public String toString() {
StringBuffer s = new StringBuffer();
if (a[0] == 0.0) {
if (a.length == 1) {
return "0";
}
} else {
s.append(java.lang.Double.toString(a[0]));
}
for (int i = 1; i < a.length; ++i) {
if (a[i] != 0) {
if (s.length() > 0) {
if (a[i] < 0) {
s.append(" - ");
} else {
s.append(" + ");
}
} else {
if (a[i] < 0) {
s.append("-");
}
}
double absAi = Math.abs(a[i]);
if ((absAi - 1) != 0) {
s.append(java.lang.Double.toString(absAi));
s.append(' ');
}
s.append("x");
if (i > 1) {
s.append('^');
s.append(Integer.toString(i));
}
}
}
return s.toString();
}
/** Coefficients array. */
protected double[] a;
private static final long serialVersionUID = -4210522025715687648L;
}
}