import java.util.*;
import java.util.zip.*;
import java.util.List;
import java.util.regex.*;
import java.util.concurrent.*;
import java.util.concurrent.atomic.*;
import java.util.concurrent.locks.*;
import javax.swing.*;
import javax.swing.event.*;
import javax.swing.text.*;
import javax.swing.table.*;
import java.io.*;
import java.net.*;
import java.lang.reflect.*;
import java.lang.ref.*;
import java.lang.management.*;
import java.security.*;
import java.security.spec.*;
import java.awt.*;
import java.awt.event.*;
import java.awt.image.*;
import javax.imageio.*;
import java.math.*;
class main {
static EditDistance newEditDistance_sparseArray2() {
EditDistance ed = new EditDistance();
ed.FKP = new SparseIntArray2D_65536(65536, 65536);
ed.brf = new EditDistance.LevenshteinBRF();
return ed;
}
/*******************************************************************************
* Copyright (c) 2010-2019 Haifeng Li
*
* Smile is free software: you can redistribute it and/or modify
* it under the terms of the GNU Lesser General Public License as
* published by the Free Software Foundation, either version 3 of
* the License, or (at your option) any later version.
*
* Smile is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public License
* along with Smile. If not, see .
*******************************************************************************/
/**
* The Edit distance between two strings is a metric for measuring the amount
* of difference between two sequences. The Levenshtein distance between two
* strings is given by the minimum number of operations needed to transform one
* string into the other, where an operation is an insertion, deletion, or
* substitution of a single character. A generalization of the Levenshtein
* distance (Damerau-Levenshtein distance) allows the transposition of two
* characters as an operation.
*
* Given two strings x and y of length m and n (suppose n ≥ m), this
* implementation takes O(ne) time and O(mn) space by an extended Ukkonen's
* algorithm in case of unit cost, where e is the edit distance between x and y.
* Thus this algorithm is output sensitive. The smaller the distance, the faster
* it runs.
*
* For weighted cost, this implements the regular dynamic programming algorithm,
* which takes O(mn) time and O(m) space.
*
* @author Haifeng Li
*/
final static class EditDistance /*implements Metric*/ {
/**
* Weight matrix for weighted Levenshtein distance.
*/
private IIntArray2D weight;
/**
* Radius of Sakoe-Chiba band
*/
private double r = -1;
/**
* Calculate Damerau or basic Levenshitein distance.
*/
private boolean damerau = false;
/**
* Cost matrix. Because Java automatically initialize arrays, it
* takes O(mn) to declare this cost matrix every time before
* calculate edit distance. But the whole point of Berghel & Roach
* algorithm is to calculate fewer cells than O(mn). Therefore,
* we create this cost matrix here. Therefore, the methods using
* this cost matrix is not multi-thread safe.
*/
private IIntArray2D FKP;
/**
* The lambda to calculate FKP array.
*/
private BRF brf;
/**
* Constructor. Multi-thread safe Levenshtein distance.
*/
public EditDistance() {
this(false);
}
/**
* Constructor. Multi-thread safe Damerau-Levenshtein distance.
* @param damerau if true, calculate Damerau-Levenshtein distance
* instead of plain Levenshtein distance.
*/
public EditDistance(boolean damerau) {
this.damerau = damerau;
}
/**
* Constructor. Highly efficient Levenshtein distance but not multi-thread safe.
* @param maxStringLength the maximum length of strings that will be
* feed to this algorithm.
*/
public EditDistance(int maxStringLength) {
this(maxStringLength, false);
}
/**
* Constructor. Highly efficient Damerau-Levenshtein distance but not multi-thread safe.
* @param maxStringLength the maximum length of strings that will be
* feed to this algorithm.
* @param damerau if true, calculate Damerau-Levenshtein distance
* instead of plain Levenshtein distance.
*/
public EditDistance(int maxStringLength, boolean damerau) {
this.damerau = damerau;
FKP = new IntArray2D(2*maxStringLength+1, maxStringLength+2);
brf = damerau ? new DamerauBRF() : new LevenshteinBRF();
}
/**
* Constructor. Weighted Levenshtein distance without path
* constraints. Only insertion, deletion, and substitution operations are
* supported.
*/
public EditDistance(int[][] weight) {
this(weight, -1);
}
/**
* Constructor. Weighted Levenshtein distance with
* Sakoe-Chiba band, which improve computational cost. Only
* insertion, deletion, and substitution operations are supported.
* @param radius the window width of Sakoe-Chiba band in terms of percentage of sequence length.
*/
public EditDistance(int[][] weight, double radius) {
this.weight = new IntArray2D(weight);
this.r = radius;
}
@Override
public String toString() {
if (damerau) {
if (weight != null)
return String.format("Damerau-Levenshtein Distance(radius = %d, weight = %s)", r, weight.toString());
else
return "Damerau-Levenshtein Distance";
} else {
if (weight != null)
return String.format("Levenshtein Distance(radius = %d, weight = %s)", r, weight.toString());
else
return "Levenshtein Distance";
}
}
/**
* Edit distance between two strings. O(mn) time and O(n) space for weighted
* edit distance. O(ne) time and O(mn) space for unit cost edit distance.
* For weighted edit distance, this method is multi-thread safe. However,
* it is NOT multi-thread safe for unit cost edit distance.
*/
public double d(String x, String y) {
if (weight != null)
return weightedEdit(x, y);
else if (FKP == null || x.length() == 1 || y.length() == 1)
return damerau ? damerau(x, y) : levenshtein(x, y);
else
return br(x, y);
}
/**
* Edit distance between two strings. O(mn) time and O(n) space for weighted
* edit distance. O(ne) time and O(mn) space for unit cost edit distance.
* For weighted edit distance, this method is multi-thread safe. However,
* it is NOT multi-thread safe for unit cost edit distance.
*/
public double d(char[] x, char[] y) {
if (weight != null)
return weightedEdit(x, y);
else if (FKP == null || x.length == 1 || y.length == 1)
return damerau ? damerau(x, y) : levenshtein(x, y);
else
return br(x, y);
}
/**
* Weighted edit distance.
*/
private double weightedEdit(char[] x, char[] y) {
// switch parameters to use the shorter one as y to save space.
if (x.length < y.length) {
char[] swap = x;
x = y;
y = swap;
}
int radius = (int) Math.round(r * Math.max(x.length, y.length));
double[][] d = new double[2][y.length + 1];
d[0][0] = 0.0;
for (int j = 1; j <= y.length; j++) {
d[0][j] = d[0][j - 1] + weight.get(0, y[j]);
}
for (int i = 1; i <= x.length; i++) {
d[1][0] = d[0][0] + weight.get(x[i], 0);
int start = 1;
int end = y.length;
if (radius > 0) {
start = i - radius;
if (start > 1)
d[1][start - 1] = Double.POSITIVE_INFINITY;
else
start = 1;
end = i + radius;
if (end < y.length)
d[1][end+1] = Double.POSITIVE_INFINITY;
else
end = y.length;
}
for (int j = start; j <= end; j++) {
double cost = weight.get(x[i - 1], y[j - 1]);
d[1][j] = min3(
d[0][j] + weight.get(x[i - 1], 0), // deletion
d[1][j - 1] + weight.get(0, y[j - 1]), // insertion
d[0][j - 1] + cost); // substitution
}
double[] swap = d[0];
d[0] = d[1];
d[1] = swap;
}
return d[0][y.length];
}
/**
* Weighted edit distance.
*/
private double weightedEdit(String x, String y) {
// switch parameters to use the shorter one as y to save space.
if (x.length() < y.length()) {
String swap = x;
x = y;
y = swap;
}
int radius = (int) Math.round(r * Math.max(x.length(), y.length()));
double[][] d = new double[2][y.length() + 1];
d[0][0] = 0.0;
for (int j = 1; j <= y.length(); j++) {
d[0][j] = d[0][j - 1] + weight.get(0, y.charAt(j));
}
for (int i = 1; i <= x.length(); i++) {
d[1][0] = d[0][0] + weight.get(x.charAt(i), 0);
int start = 1;
int end = y.length();
if (radius > 0) {
start = i - radius;
if (start > 1)
d[1][start - 1] = Double.POSITIVE_INFINITY;
else
start = 1;
end = i + radius;
if (end < y.length())
d[1][end+1] = Double.POSITIVE_INFINITY;
else
end = y.length();
}
for (int j = start; j <= end; j++) {
double cost = weight.get(x.charAt(i - 1), y.charAt(j - 1));
d[1][j] = min3(
d[0][j] + weight.get(x.charAt(i - 1), 0), // deletion
d[1][j - 1] + weight.get(0, y.charAt(j - 1)), // insertion
d[0][j - 1] + cost); // substitution
}
double[] swap = d[0];
d[0] = d[1];
d[1] = swap;
}
return d[0][y.length()];
}
/**
* Berghel & Roach's extended Ukkonen's algorithm.
*/
private int br(char[] x, char[] y) {
if (x.length > y.length) {
char[] swap = x;
x = y;
y = swap;
}
final int m = x.length;
final int n = y.length;
int ZERO_K = n;
if (n+2 > FKP.ncols())
FKP = new IntArray2D(2*n+1, n+2);
for (int k = -ZERO_K; k < 0; k++) {
int p = -k - 1;
FKP.set(k + ZERO_K, p + 1, Math.abs(k) - 1);
FKP.set(k + ZERO_K, p, Integer.MIN_VALUE);
}
FKP.set(ZERO_K, 0, -1);
for (int k = 1; k <= ZERO_K; k++) {
int p = k - 1;
FKP.set(k + ZERO_K, p + 1, -1);
FKP.set(k + ZERO_K, p, Integer.MIN_VALUE);
}
int p = n - m - 1;
do {
p++;
for (int i = (p - (n-m))/2; i >= 1; i--) {
brf.f(x, y, FKP, ZERO_K, n-m+i, p-i);
}
for (int i = (n-m+p)/2; i >= 1; i--) {
brf.f(x, y, FKP, ZERO_K, n-m-i, p-i);
}
brf.f(x, y, FKP, ZERO_K, n - m, p);
} while (FKP.get((n - m) + ZERO_K, p) != m);
return p - 1;
}
/**
* Berghel & Roach's extended Ukkonen's algorithm.
*/
private int br(String x, String y) {
if (x.length() > y.length()) {
String swap = x;
x = y;
y = swap;
}
final int m = x.length();
final int n = y.length();
int ZERO_K = n;
if (n+3 > FKP.ncols())
FKP = new IntArray2D(2*n+1, n+3);
for (int k = -ZERO_K; k < 0; k++) {
int p = -k - 1;
FKP.set(k + ZERO_K, p + 1, Math.abs(k) - 1);
FKP.set(k + ZERO_K, p, Integer.MIN_VALUE);
}
FKP.set(ZERO_K, 0, -1);
for (int k = 1; k <= ZERO_K; k++) {
int p = k - 1;
FKP.set(k + ZERO_K, p + 1, -1);
FKP.set(k + ZERO_K, p, Integer.MIN_VALUE);
}
int p = n - m - 1;
do {
p++;
for (int i = (p - (n-m))/2; i >= 1; i--) {
brf.f(x, y, FKP, ZERO_K, n-m+i, p-i);
}
for (int i = (n-m+p)/2; i >= 1; i--) {
brf.f(x, y, FKP, ZERO_K, n-m-i, p-i);
}
brf.f(x, y, FKP, ZERO_K, n - m, p);
} while (FKP.get((n - m) + ZERO_K, p) != m);
return p - 1;
}
private static class LevenshteinBRF implements BRF {
@Override
public void f(char[] x, char[] y, IIntArray2D FKP, int ZERO_K, int k, int p) {
int t = max3(FKP.get(k + ZERO_K, p) + 1, FKP.get(k - 1 + ZERO_K, p), FKP.get(k + 1 + ZERO_K, p) + 1);
int mnk = Math.min(x.length, y.length - k);
while (t < mnk && x[t] == y[t + k]) {
t++;
}
FKP.set(k + ZERO_K, p + 1, t);
}
@Override
public void f(String x, String y, IIntArray2D FKP, int ZERO_K, int k, int p) {
int t = max3(FKP.get(k + ZERO_K, p) + 1, FKP.get(k - 1 + ZERO_K, p), FKP.get(k + 1 + ZERO_K, p) + 1);
int mnk = Math.min(x.length(), y.length() - k);
while (t < mnk && x.charAt(t) == y.charAt(t + k)) {
t++;
}
FKP.set(k + ZERO_K, p + 1, t);
}
}
/**
* Calculate FKP arrays in BR's algorithm with support of transposition operation.
*/
private static class DamerauBRF implements BRF {
@Override
public void f(char[] x, char[] y, IIntArray2D FKP, int ZERO_K, int k, int p) {
int t = FKP.get(k + ZERO_K, p) + 1;
int mnk = Math.min(x.length, y.length - k);
if (t >= 1 && k + t >= 1 && t < mnk) {
if (x[t - 1] == y[k + t] && x[t] == y[k + t - 1]) {
t++;
}
}
t = max3(FKP.get(k - 1 + ZERO_K, p), FKP.get(k + 1 + ZERO_K, p) + 1, t);
while (t < mnk && x[t] == y[t + k]) {
t++;
}
FKP.set(k + ZERO_K, p + 1, t);
}
@Override
public void f(String x, String y, IIntArray2D FKP, int ZERO_K, int k, int p) {
int t = FKP.get(k + ZERO_K, p) + 1;
int mnk = Math.min(x.length(), y.length() - k);
if (t >= 1 && k + t >= 1 && t < mnk) {
if (x.charAt(t - 1) == y.charAt(k + t) && x.charAt(t) == y.charAt(k + t - 1)) {
t++;
}
}
t = max3(FKP.get(k - 1 + ZERO_K, p), FKP.get(k + 1 + ZERO_K, p) + 1, t);
while (t < mnk && x.charAt(t) == y.charAt(t + k)) {
t++;
}
FKP.set(k + ZERO_K, p + 1, t);
}
}
static interface BRF {
/**
* Calculate FKP arrays in BR's algorithm.
*/
void f(char[] x, char[] y, IIntArray2D FKP, int ZERO_K, int k, int p);
/**
* Calculate FKP arrays in BR's algorithm.
*/
void f(String x, String y, IIntArray2D FKP, int ZERO_K, int k, int p);
}
/**
* Levenshtein distance between two strings allows insertion, deletion,
* or substitution of characters. O(mn) time and O(n) space.
* Multi-thread safe.
*/
public static int levenshtein(String x, String y) {
// switch parameters to use the shorter one as y to save space.
if (x.length() < y.length()) {
String swap = x;
x = y;
y = swap;
}
int[][] d = new int[2][y.length() + 1];
for (int j = 0; j <= y.length(); j++) {
d[0][j] = j;
}
for (int i = 1; i <= x.length(); i++) {
d[1][0] = i;
for (int j = 1; j <= y.length(); j++) {
int cost = x.charAt(i - 1) == y.charAt(j - 1) ? 0 : 1;
d[1][j] = min3(
d[0][j] + 1, // deletion
d[1][j - 1] + 1, // insertion
d[0][j - 1] + cost); // substitution
}
int[] swap = d[0];
d[0] = d[1];
d[1] = swap;
}
return d[0][y.length()];
}
/**
* Levenshtein distance between two strings allows insertion, deletion,
* or substitution of characters. O(mn) time and O(n) space.
* Multi-thread safe.
*/
public static int levenshtein(char[] x, char[] y) {
// switch parameters to use the shorter one as y to save space.
if (x.length < y.length) {
char[] swap = x;
x = y;
y = swap;
}
int[][] d = new int[2][y.length + 1];
for (int j = 0; j <= y.length; j++) {
d[0][j] = j;
}
for (int i = 1; i <= x.length; i++) {
d[1][0] = i;
for (int j = 1; j <= y.length; j++) {
int cost = x[i - 1] == y[j - 1] ? 0 : 1;
d[1][j] = min3(
d[0][j] + 1, // deletion
d[1][j - 1] + 1, // insertion
d[0][j - 1] + cost); // substitution
}
int[] swap = d[0];
d[0] = d[1];
d[1] = swap;
}
return d[0][y.length];
}
/**
* Damerau-Levenshtein distance between two strings allows insertion,
* deletion, substitution, or transposition of characters.
* O(mn) time and O(n) space. Multi-thread safe.
*/
public static int damerau(String x, String y) {
// switch parameters to use the shorter one as y to save space.
if (x.length() < y.length()) {
String swap = x;
x = y;
y = swap;
}
int[][] d = new int[3][y.length() + 1];
for (int j = 0; j <= y.length(); j++) {
d[1][j] = j;
}
for (int i = 1; i <= x.length(); i++) {
d[2][0] = i;
for (int j = 1; j <= y.length(); j++) {
int cost = x.charAt(i-1) == y.charAt(j-1) ? 0 : 1;
d[2][j] = min3(
d[1][j] + 1, // deletion
d[2][j-1] + 1, // insertion
d[1][j-1] + cost); // substitution
if (i > 1 && j > 1) {
if (x.charAt(i-1) == y.charAt(j-2) && x.charAt(i-2) == y.charAt(j-1))
d[2][j] = Math.min(d[2][j], d[0][j-2] + cost); // damerau
}
}
int[] swap = d[0];
d[0] = d[1];
d[1] = d[2];
d[2] = swap;
}
return d[1][y.length()];
}
/**
* Damerau-Levenshtein distance between two strings allows insertion,
* deletion, substitution, or transposition of characters.
* O(mn) time and O(n) space. Multi-thread safe.
*/
public static int damerau(char[] x, char[] y) {
// switch parameters to use the shorter one as y to save space.
if (x.length < y.length) {
char[] swap = x;
x = y;
y = swap;
}
int[][] d = new int[3][y.length + 1];
for (int j = 0; j <= y.length; j++) {
d[1][j] = j;
}
for (int i = 1; i <= x.length; i++) {
d[2][0] = i;
for (int j = 1; j <= y.length; j++) {
int cost = x[i-1] == y[j-1] ? 0 : 1;
d[2][j] = min3(
d[1][j] + 1, // deletion
d[2][j-1] + 1, // insertion
d[1][j-1] + cost); // substitution
if (i > 1 && j > 1) {
if (x[i-1] == y[j-2] && x[i-2] == y[j-1])
d[2][j] = Math.min(d[2][j], d[0][j-2] + cost); // damerau
}
}
int[] swap = d[0];
d[0] = d[1];
d[1] = d[2];
d[2] = swap;
}
return d[1][y.length];
}
}
final static class SparseIntArray2D_65536 implements IIntArray2D {
int nrows, ncols;
IntIntMap entries = new IntIntMap(256, 0.75f);
SparseIntArray2D_65536() {}
SparseIntArray2D_65536(int nrows, int ncols) {
this.ncols = ncols;
this.nrows = nrows;}
public int nrows() { return nrows; }
public int ncols() { return ncols; }
/** Returns A(i, j). */
public int get(int i, int j) {
return or0(entries.get(combine(i, j)));
}
/** Sets A(i, j). */
public int set(int i, int j, int x) {
if (x == 0)
entries.remove(combine(i, j));
else
entries.put(combine(i, j), x);
return x;
}
static int combine(int i, int j) {
return i << 16 | j;
}
}
static class IntIntMap implements IIntIntMap {
private static final int FREE_KEY = 0;
public static final int NO_VALUE = 0;
/** Keys and values */
private int[] m_data;
/** Do we have 'free' key in the map? */
private boolean m_hasFreeKey = false;
/** Value of 'free' key */
private int m_freeValue;
/** Fill factor, must be between (0 and 1) */
private final float m_fillFactor;
/** We will resize a map once it reaches this size */
private int m_threshold;
/** Current map size */
private int m_size;
/** Mask to calculate the original position */
private int m_mask;
private int m_mask2;
IntIntMap( final int size, final float fillFactor )
{
if ( fillFactor <= 0 || fillFactor >= 1 )
throw new IllegalArgumentException( "FillFactor must be in (0, 1)" );
if ( size <= 0 )
throw new IllegalArgumentException( "Size must be positive!" );
final int capacity = arraySize(size, fillFactor);
m_mask = capacity - 1;
m_mask2 = capacity*2 - 1;
m_fillFactor = fillFactor;
m_data = new int[capacity * 2];
m_threshold = (int) (capacity * fillFactor);
}
public int get( final int key )
{
int ptr = ( phiMix( key ) & m_mask) << 1;
if ( key == FREE_KEY )
return m_hasFreeKey ? m_freeValue : NO_VALUE;
int k = m_data[ ptr ];
if ( k == FREE_KEY )
return NO_VALUE; //end of chain already
if ( k == key ) //we check FREE prior to this call
return m_data[ ptr + 1 ];
while ( true )
{
ptr = (ptr + 2) & m_mask2; //that's next index
k = m_data[ ptr ];
if ( k == FREE_KEY )
return NO_VALUE;
if ( k == key )
return m_data[ ptr + 1 ];
}
}
public int put( final int key, final int value )
{
if ( key == FREE_KEY )
{
final int _ret = m_freeValue;
if ( !m_hasFreeKey )
++m_size;
m_hasFreeKey = true;
m_freeValue = value;
return _ret;
}
int ptr = ( phiMix( key ) & m_mask) << 1;
int k = m_data[ptr];
if ( k == FREE_KEY ) //end of chain already
{
m_data[ ptr ] = key;
m_data[ ptr + 1 ] = value;
if ( m_size >= m_threshold )
rehash( m_data.length * 2 ); //size is set inside
else
++m_size;
return NO_VALUE;
}
else if ( k == key ) //we check FREE prior to this call
{
final int _ret = m_data[ ptr + 1 ];
m_data[ ptr + 1 ] = value;
return _ret;
}
while ( true )
{
ptr = ( ptr + 2 ) & m_mask2; //that's next index calculation
k = m_data[ ptr ];
if ( k == FREE_KEY )
{
m_data[ ptr ] = key;
m_data[ ptr + 1 ] = value;
if ( m_size >= m_threshold )
rehash( m_data.length * 2 ); //size is set inside
else
++m_size;
return NO_VALUE;
}
else if ( k == key )
{
final int _ret = m_data[ ptr + 1 ];
m_data[ ptr + 1 ] = value;
return _ret;
}
}
}
public int remove( final int key )
{
if ( key == FREE_KEY )
{
if ( !m_hasFreeKey )
return NO_VALUE;
m_hasFreeKey = false;
--m_size;
return m_freeValue; //value is not cleaned
}
int ptr = ( phiMix( key ) & m_mask) << 1;
int k = m_data[ ptr ];
if ( k == key ) //we check FREE prior to this call
{
final int res = m_data[ ptr + 1 ];
shiftKeys( ptr );
--m_size;
return res;
}
else if ( k == FREE_KEY )
return NO_VALUE; //end of chain already
while ( true )
{
ptr = ( ptr + 2 ) & m_mask2; //that's next index calculation
k = m_data[ ptr ];
if ( k == key )
{
final int res = m_data[ ptr + 1 ];
shiftKeys( ptr );
--m_size;
return res;
}
else if ( k == FREE_KEY )
return NO_VALUE;
}
}
private int shiftKeys(int pos)
{
// Shift entries with the same hash.
int last, slot;
int k;
final int[] data = this.m_data;
while ( true )
{
pos = ((last = pos) + 2) & m_mask2;
while ( true )
{
if ((k = data[pos]) == FREE_KEY)
{
data[last] = FREE_KEY;
return last;
}
slot = ( phiMix( k ) & m_mask) << 1; //calculate the starting slot for the current key
if (last <= pos ? last >= slot || slot > pos : last >= slot && slot > pos) break;
pos = (pos + 2) & m_mask2; //go to the next entry
}
data[last] = k;
data[last + 1] = data[pos + 1];
}
}
public int size()
{
return m_size;
}
private void rehash( final int newCapacity )
{
m_threshold = (int) (newCapacity/2 * m_fillFactor);
m_mask = newCapacity/2 - 1;
m_mask2 = newCapacity - 1;
final int oldCapacity = m_data.length;
final int[] oldData = m_data;
m_data = new int[ newCapacity ];
m_size = m_hasFreeKey ? 1 : 0;
for ( int i = 0; i < oldCapacity; i += 2 ) {
final int oldKey = oldData[ i ];
if( oldKey != FREE_KEY )
put( oldKey, oldData[ i + 1 ]);
}
}
static int arraySize( final int expected, final float f ) {
final long s = Math.max( 2, nextPowerOfTwo( (long)Math.ceil( expected / f ) ) );
if ( s > (1 << 30) ) throw new IllegalArgumentException( "Too large (" + expected + " expected elements with load factor " + f + ")" );
return (int)s;
}
static final int INT_PHI = 0x9E3779B9;
static int phiMix( final int x ) {
final int h = x * INT_PHI;
return h ^ (h >> 16);
}
}
static interface IIntArray2D {
public int nrows();
public int ncols();
/** Returns A(i, j). */
public int get(int i, int j);
/** Sets A(i, j). */
public int set(int i, int j, int x);
}/*******************************************************************************
* Copyright (c) 2010-2019 Haifeng Li
*
* Smile is free software: you can redistribute it and/or modify
* it under the terms of the GNU Lesser General Public License as
* published by the Free Software Foundation, either version 3 of
* the License, or (at your option) any later version.
*
* Smile is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public License
* along with Smile. If not, see .
*******************************************************************************/
static class IntArray2D implements IIntArray2D {
private int[] A;
private int nrows;
private int ncols;
public IntArray2D(int[][] A) {
this.nrows = A.length;
this.ncols = A[0].length;
this.A = new int[nrows*ncols];
int pos = 0;
for (int i = 0; i < nrows; i++) {
System.arraycopy(A[i], 0, this.A, pos, ncols);
pos += ncols;
}
}
/**
* Constructor of all-zero matrix.
*/
public IntArray2D(int rows, int cols) {
this.nrows = rows;
this.ncols = cols;
A = new int[rows*cols];
}
/**
* Constructor. Fill the matrix with given value.
*/
public IntArray2D(int rows, int cols, int value) {
this(rows, cols);
if (value != 0.0)
Arrays.fill(A, value);
}
/**
* Constructor.
* @param value the array of matrix values arranged in row major format
*/
public IntArray2D(int rows, int cols, int[] value) {
this.nrows = rows;
this.ncols = cols;
this.A = value;
}
public int nrows() {
return nrows;
}
public int ncols() {
return ncols;
}
/** Returns A(i, j). Useful in Scala. */
public int apply(int i, int j) {
return A[i*ncols + j];
}
/** Returns A(i, j). */
public int get(int i, int j) {
return A[i*ncols + j];
}
/** Sets A(i, j). */
public int set(int i, int j, int x) {
return A[i*ncols + j] = x;
}
public int add(int i, int j, int x) {
return A[i*ncols + j] += x;
}
public int sub(int i, int j, int x) {
return A[i*ncols + j] -= x;
}
public int mul(int i, int j, int x) {
return A[i*ncols + j] *= x;
}
public int div(int i, int j, int x) {
return A[i*ncols + j] /= x;
}
public IntArray2D add(IntArray2D b) {
if (nrows() != b.nrows() || ncols() != b.ncols()) {
throw new IllegalArgumentException("Matrix is not of same size.");
}
for (int i = 0; i < A.length; i++) {
A[i] += b.A[i];
}
return this;
}
public IntArray2D sub(IntArray2D b) {
if (nrows() != b.nrows() || ncols() != b.ncols()) {
throw new IllegalArgumentException("Matrix is not of same size.");
}
for (int i = 0; i < A.length; i++) {
A[i] -= b.A[i];
}
return this;
}
public IntArray2D mul(IntArray2D b) {
if (nrows() != b.nrows() || ncols() != b.ncols()) {
throw new IllegalArgumentException("Matrix is not of same size.");
}
for (int i = 0; i < A.length; i++) {
A[i] *= b.A[i];
}
return this;
}
public IntArray2D div(IntArray2D b) {
if (nrows() != b.nrows() || ncols() != b.ncols()) {
throw new IllegalArgumentException("Matrix is not of same size.");
}
for (int i = 0; i < A.length; i++) {
A[i] /= b.A[i];
}
return this;
}
public IntArray2D add(int x) {
for (int i = 0; i < A.length; i++) {
A[i] += x;
}
return this;
}
public IntArray2D sub(int x) {
for (int i = 0; i < A.length; i++) {
A[i] -= x;
}
return this;
}
public IntArray2D mul(int x) {
for (int i = 0; i < A.length; i++) {
A[i] *= x;
}
return this;
}
public IntArray2D div(int x) {
for (int i = 0; i < A.length; i++) {
A[i] /= x;
}
return this;
}
public long sum() {
long s = 0;
for (int i = 0; i < A.length; i++) {
s += A[i];
}
return s;
}
@Override
public String toString() {
return toString(false);
}
/**
* Returns the string representation of matrix.
* @param full Print the full matrix if true. Otherwise,
* print only top left 7 x 7 submatrix.
*/
public String toString(boolean full) {
return full ? toString(nrows(), ncols()) : toString(7, 7);
}
/**
* Returns the string representation of matrix.
* @param m the number of rows to print.
* @param n the number of columns to print.
*/
public String toString(int m, int n) {
StringBuilder sb = new StringBuilder();
m = Math.min(m, nrows());
n = Math.min(n, ncols());
String newline = n < ncols() ? "...\n" : "\n";
for (int i = 0; i < m; i++) {
for (int j = 0; j < n; j++) {
sb.append(String.format("%d ", get(i, j)));
}
sb.append(newline);
}
if (m < nrows()) {
sb.append(" ...\n");
}
return sb.toString();
}
}
static interface IIntIntMap {
public int get( final int key );
public int put( final int key, final int value );
public int remove( final int key );
public int size();
}
static int min3(int a, int b, int c) {
return min(min(a, b), c);
}
static double min3(double a, double b, double c) {
return min(min(a, b), c);
}
static int max3(int a, int b, int c) {
return max(max(a, b), c);
}
static double max3(double a, double b, double c) {
return max(max(a, b), c);
}
static int or0(Integer i) { return i == null ? 0 : i; }
static long or0(Long l) { return l == null ? 0L : l; }
static double or0(Double d) { return d == null ? 0.0 : d; }
static void put(Map map, A a, B b) {
if (map != null) map.put(a, b);
}
static void put(List l, int i, A a) {
if (l != null && i >= 0 && i < l(l)) l.set(i, a);
}
/** Return the least power of two greater than or equal to the specified value.
*
*