org.la4j.vector.sparse.CompressedVector Maven / Gradle / Ivy
Go to download
Show more of this group Show more artifacts with this name
Show all versions of la4j Show documentation
Show all versions of la4j Show documentation
A 100% Java sparse and dense matrix library.
/*
* Copyright 2011-2013, by Vladimir Kostyukov and Contributors.
*
* This file is part of la4j project (http://la4j.org)
*
* Licensed 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.
*
* Contributor(s): -
*
*/
package org.la4j.vector.sparse;
import java.io.IOException;
import java.io.ObjectInput;
import java.io.ObjectOutput;
import org.la4j.vector.AbstractVector;
import org.la4j.vector.Vector;
import org.la4j.vector.Vectors;
import org.la4j.vector.functor.VectorFunction;
import org.la4j.vector.functor.VectorProcedure;
import org.la4j.vector.source.VectorSource;
public class CompressedVector extends AbstractVector implements SparseVector {
private static final long serialVersionUID = 4071505L;
private static final int MINIMUM_SIZE = 32;
private double values[];
private int indices[];
private int cardinality;
public CompressedVector() {
this(0);
}
public CompressedVector(int length) {
this(length, 0);
}
public CompressedVector(Vector vector) {
this(Vectors.asUnsafeSource(vector));
}
public CompressedVector(double array[]) {
this(Vectors.asArraySource(array));
}
public CompressedVector(VectorSource source) {
this(source.length(), 0);
for (int i = 0; i < length; i++) {
double value = source.get(i);
if (Math.abs(value) > Vectors.EPS) {
if (values.length < cardinality + 1) {
growup();
}
values[cardinality] = value;
indices[cardinality] = i;
cardinality++;
}
}
}
public CompressedVector(int length, int cardinality) {
this(length, cardinality, new double[align(length, cardinality)],
new int[align(length, cardinality)]);
}
public CompressedVector(int length, int cardinality, double values[],
int indices[]) {
super(Vectors.COMPRESSED_FACTORY, length);
this.cardinality = cardinality;
this.values = values;
this.indices = indices;
}
@Override
public double get(int i) {
int k = searchForIndex(i, 0, cardinality);
if (k < cardinality && indices[k] == i) {
return values[k];
}
return 0.0;
}
@Override
public void set(int i, double value) {
int k = searchForIndex(i, 0, cardinality);
if (k < cardinality && indices[k] == i) {
if (Math.abs(value) > Vectors.EPS) {
values[k] = value;
} else {
remove(k);
}
} else {
insert(k, i, value);
}
}
@Override
public void swap(int i, int j) {
if (i == j) {
return;
}
int ii = searchForIndex(i, 0, cardinality);
int jj = searchForIndex(j, 0, cardinality);
if ((ii < cardinality && i == indices[ii])
&& (jj < cardinality && j == indices[jj])) {
double sd = values[ii];
values[ii] = values[jj];
values[jj] = sd;
} else {
boolean p = ii < cardinality && i == indices[ii];
if (p || jj < cardinality && j == indices[jj]) {
double sd = values[p ? ii : jj];
int min = ii < jj ? ii : jj;
int max = ii < jj ? ii : jj;
if ((p && min == ii) || (!p && min == jj)) {
System.arraycopy(values, min, values, min + 1,
cardinality - max);
System.arraycopy(indices, min, indices, min + 1,
cardinality - max);
values[max] = sd;
} else {
System.arraycopy(values, min + 1, values, min,
cardinality - max);
System.arraycopy(indices, min + 1, indices, min,
cardinality - max);
values[min] = sd;
}
indices[max] = p ? j : i;
}
}
}
@Override
public int cardinality() {
return cardinality;
}
@Override
public double density() {
return cardinality / length;
}
@Override
public Vector copy() {
return resize(length);
}
@Override
public Vector resize(int length) {
ensureLengthIsNotNegative(length);
int $cardinality = 0;
double $values[] = new double[align(length, 0)];
int $indices[] = new int[align(length, 0)];
if (length >= this.length) {
$cardinality = cardinality;
System.arraycopy(values, 0, $values, 0, cardinality);
System.arraycopy(indices, 0, $indices, 0, cardinality);
} else {
$cardinality = searchForIndex(length, 0, cardinality);
for (int i = 0; i < $cardinality; i++) {
$values[i] = values[i];
$indices[i] = indices[i];
}
}
return new CompressedVector(length, $cardinality, $values, $indices);
}
@Override
public void each(VectorProcedure procedure) {
for (int i = 0; i < cardinality; i++) {
procedure.apply(indices[i], values[i]);
}
}
@Override
public void update(int i, VectorFunction function) {
int k = searchForIndex(i, 0, cardinality);
if (k < cardinality && indices[k] == i) {
double value = function.evaluate(i, values[k]);
if (Math.abs(value) > Vectors.EPS) {
values[k] = value;
} else {
remove(k);
}
} else {
insert(k, i, function.evaluate(i, 0.0));
}
}
@Override
public Vector safe() {
return new SparseSafeVector(this);
}
@Override
public void writeExternal(ObjectOutput out) throws IOException {
out.writeInt(length);
out.writeInt(cardinality);
for (int i = 0; i < cardinality; i++) {
out.writeInt(indices[i]);
out.writeDouble(values[i]);
}
}
@Override
public void readExternal(ObjectInput in) throws IOException,
ClassNotFoundException {
length = in.readInt();
cardinality = in.readInt();
int alignedSize = align(length, cardinality);
values = new double[alignedSize];
indices = new int[alignedSize];
for (int i = 0; i < cardinality; i++) {
indices[i] = in.readInt();
values[i] = in.readDouble();
}
}
private int searchForIndex(int i, int left, int right) {
if (left == right) {
return left;
}
if (right - left < 8) {
int ii = left;
while (ii < right && indices[ii] < i) {
ii++;
}
return ii;
}
int p = (left + right) / 2;
if (indices[p] > i) {
return searchForIndex(i, left, p);
} else if (indices[p] < i) {
return searchForIndex(i, p + 1, right);
} else {
return p;
}
}
private void insert(int k, int i, double value) {
if (Math.abs(value) < Vectors.EPS) {
return;
}
if (values.length < cardinality + 1) {
growup();
}
System.arraycopy(values, k, values, k + 1, cardinality - k);
System.arraycopy(indices, k, indices, k + 1, cardinality - k);
// for (int kk = cardinality; kk > k; kk--) {
// values[kk] = values[kk - 1];
// indices[kk] = indices[kk - 1];
// }
values[k] = value;
indices[k] = i;
cardinality++;
}
private void remove(int k) {
cardinality--;
System.arraycopy(values, k + 1, values, k, cardinality - k);
System.arraycopy(indices, k + 1, indices, k, cardinality - k);
// for (int kk = k; kk < cardinality; kk++) {
// values[kk] = values[kk + 1];
// indices[kk] = indices[kk + 1];
// }
}
private void growup() {
if (values.length == length) {
throw new IllegalStateException("This vector can't grow up.");
}
int capacity = Math.min(length, (cardinality * 3) / 2 + 1);
double $values[] = new double[capacity];
int $indices[] = new int[capacity];
System.arraycopy(values, 0, $values, 0, cardinality);
System.arraycopy(indices, 0, $indices, 0, cardinality);
values = $values;
indices = $indices;
}
private static int align(int length, int cardinality) {
return Math.min(length, ((cardinality / MINIMUM_SIZE) + 1)
* MINIMUM_SIZE);
}
}