/* This file is part of Eternity II Editor.
*
* Eternity II Editor is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* Eternity II Editor 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 General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with Eternity II Editor. If not, see <http://www.gnu.org/licenses/>.
*
* Eternity II Editor project is hosted on SourceForge:
* http://sourceforge.net/projects/eternityii/
* and maintained by Yannick Kirschhoffer <alcibiade@alcibiade.org>
*/
package org.alcibiade.eternity.editor.solver.swap;
import java.util.Iterator;
import java.util.Random;
import org.alcibiade.eternity.editor.solver.RandomFactory;
public class WeightMatrix implements Iterable<Long> {
private long[] weights;
private Random rand;
private int size;
public WeightMatrix(int size) {
assert size > 1;
this.weights = new long[size * size];
this.rand = RandomFactory.getRandom();
this.size = size;
}
public long getWeight(int offset) {
return weights[offset];
}
public long getWeight(int x, int y) {
return weights[x + y * size];
}
public void setWeight(int offset, long weight) {
assert weight >= 0;
weights[offset] = weight;
}
public void setWeight(int x, int y, long weight) {
assert weight >= 0;
weights[x + y * size] = weight;
}
public void multiplyWeight(int offset, long ratio) {
assert ratio >= 0;
weights[offset] *= ratio;
}
public void addIfNotZero(WeightMatrix matrix) {
for (int i = 0; i < weights.length; i++) {
if (weights[i] != 0) {
weights[i] += matrix.weights[i];
}
}
}
public void addToAll(long weight) {
for (int i = 0; i < weights.length; i++) {
weights[i] += weight;
}
}
public void multiplyWeight(int x, int y, long ratio) {
assert ratio >= 0;
weights[x + y * size] *= ratio;
}
public long getTotalWeight() {
long total = 0;
for (long weight : weights) {
total += weight;
}
return total;
}
public int pick() {
long totalWeight = getTotalWeight();
if (totalWeight < 1) {
dumpMatrix();
throw new ArithmeticException("Total weight of the matrix is < 1");
}
long abspos = Math.abs(rand.nextLong()) % totalWeight;
// System.out.println(String.format("%d/%d avg: %d", abspos,
// totalWeight,
// totalWeight / weights.length));
int pos = -1;
while (abspos >= 0) {
pos++;
abspos -= weights[pos];
}
return pos;
}
public void dumpMatrix() {
for (int y = 0; y < size; y++) {
for (int x = 0; x < size; x++) {
System.out.print(String.format("%6d", weights[x + size * y]));
}
System.out.println("");
}
}
public Iterator<Long> iterator() {
return new ArrayIterator(weights);
}
}