/*
* This program 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 2 of the License, or
* (at your option) any later version.
*
* This program 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 this program; if not, write to the Free Software
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*/
/*
* AlgVector.java
* Copyright (C) 2002 University of Waikato
*
*/
package weka.clusterers;
import weka.core.*;
import java.util.Random;
//import java.io.Writer;
//import java.io.Reader;
//import java.io.LineNumberReader;
import java.io.Serializable;
//import java.util.StringTokenizer;
/**
* Class for performing operations on an algebraic vector
* of floating-point values.
*
* @author Gabi Schmidberger (gabi@cs.waikato.ac.nz)
* @version $Revision: 1.1.1.1 $
*/
public class AlgVector implements Cloneable, Serializable {
/**
* The values of the matrix */
protected double [] m_Elements;
/**
* Constructs a vector and initializes it with default values.
*
* @param n the number of elements
*/
public AlgVector(int n) {
m_Elements = new double[n];
initialize();
}
/**
* Constructs a vector using a given array.
*
* @param array the values of the matrix
*/
public AlgVector(double[] array) throws Exception {
m_Elements = new double[array.length];
for (int i = 0; i < array.length; i++) {
m_Elements[i] = array[i];
}
}
/**
* Constructs a vector using a given data format.
* The vector has an element for each numerical attribute.
* The other attributes (nominal, string) are ignored.
* Random is used to initialize the attributes.
*
* @param array the values of the matrix
*/
public AlgVector(Instances format, Random random) throws Exception {
int len = format.numAttributes();
for (int i = 0; i < format.numAttributes(); i++) {
if (!format.attribute(i).isNumeric()) len--;
}
if (len > 0) {
m_Elements = new double[len];
initialize(random);
}
}
/**
* Constructs a vector using an instance.
* The vector has an element for each numerical attribute.
* The other attributes (nominal, string) are ignored.
*
* @param instance with numeric attributes, that AlgVector gets build from
* @exception if instance doesn't have access to the data format
*/
public AlgVector(Instance instance) throws Exception {
int len = instance.numAttributes();
for (int i = 0; i < instance.numAttributes(); i++) {
if (!instance.attribute(i).isNumeric()) len--;
}
if (len > 0) {
m_Elements = new double[len];
for (int i = 0; i < len; i++) {
m_Elements[i] = instance.valueSparse(i);
}
}
}
/**
* Creates and returns a clone of this object.
*
* @return a clone of this instance.
* @exception CloneNotSupportedException if an error occurs
*
public Object clone() throws CloneNotSupportedException {
Matrix m = (Matrix)super.clone();
m.m_Elements = new double[numRows()][numColumns()];
for (int r = 0; r < numRows(); r++) {
for (int c = 0; c < numColumns(); c++) {
m.m_Elements[r][c] = m_Elements[r][c];
}
}
return m;
}
/**
* Writes out a matrix.
*
* @param w the output Writer
* @exception Exception if an error occurs
*
public void write(Writer w) throws Exception {
w.write("% Rows\tColumns\n");
w.write("" + numRows() + "\t" + numColumns() + "\n");
w.write("% Matrix elements\n");
for(int i = 0; i < numRows(); i++) {
for(int j = 0; j < numColumns(); j++) {
w.write("" + m_Elements[i][j] + "\t");
}
w.write("\n");
}
w.flush();
}
/**
* Resets the elements to the default value which is 0.0.
*/
protected void initialize() {
for (int i = 0; i < m_Elements.length; i++) {
m_Elements[i] = 0.0;
}
}
/**
* Resets the elements to the default value which is 0.0.
*/
protected void initialize(Random random) {
for (int i = 0; i < m_Elements.length; i++) {
m_Elements[i] = random.nextDouble();
}
}
/**
* Returns the value of a cell in the matrix.
*
* @param index the row's index
* @return the value of the cell of the vector
*/
public final double getElement(int index) {
return m_Elements[index];
}
/**
* Returns the number of elements in the vector.
*
* @return the number of rows
*/
public final int numElements() {
return m_Elements.length;
}
/**
* Sets an element of the matrix to the given value.
*
* @param index the elements index
* @param value the new value
*/
public final void setElement(int index, double value) {
m_Elements[index] = value;
}
/**
* Sets the elements of the vector to values of the given array.
* Performs a deep copy.
*
* @param elements an array of doubles
*/
public final void setElements(double[] elements) {
for (int i = 0; i < elements.length; i++) {
m_Elements[i] = elements[i];
}
}
/**
* Gets the elements of the vector and returns them as double array.
*
* @return an array of doubles
*/
public double[] getElements(int index) {
double [] elements = new double[this.numElements()];
for (int i = 0; i < elements.length; i++) {
elements[i] = m_Elements[i];
}
return elements;
}
/**
* Gets the elements of the vector as an instance.
*
* !! NON-numeric data is ignored sofar
* @return an array of doubles
* @exception if length of vector is not number of numerical attributes
*/
public Instance getAsInstance(Instances model)
throws Exception {
Instance newInst = new Instance(model.numAttributes());
newInst.setDataset(model);
for (int i = 0, j = 0; i < model.numAttributes(); i++) {
if (model.attribute(i).isNumeric()) {
if (j >= m_Elements.length)
throw new Exception("Datatypes are not compatible.");
newInst.setValue(i, m_Elements[j++]);
}
if (model.attribute(i).isNominal()) {
newInst.setValue(i, 0);
}
}
return newInst;
}
/**
* Converts a vector to a string
*
* @return the converted string
*/
public String toString() {
StringBuffer text = new StringBuffer();
for (int i = 0; i < m_Elements.length; i++) {
if (i > 0) text.append(",");
text.append(Utils.doubleToString(m_Elements[i],6));
}
text.append("\n");
return text.toString();
}
/**
* Returns the sum of this vector with another.
*
* @return a vector containing the sum.
*/
public final AlgVector add(AlgVector other) {
int n = m_Elements.length;
AlgVector b;
try {
b = (AlgVector)clone();
} catch (CloneNotSupportedException ex) {
b = new AlgVector(n);
}
for(int i = 0; i < n; i++) {
b.m_Elements[i] = m_Elements[i] + other.m_Elements[i];
}
return b;
}
/**
* Returns the difference of this vector minus another.
*
* @return a vector containing the difference vector.
*/
public final AlgVector substract(AlgVector other) {
int n = m_Elements.length;
AlgVector b;
try {
b = (AlgVector)clone();
} catch (CloneNotSupportedException ex) {
b = new AlgVector(n);
}
for(int i = 0; i < n; i++) {
b.m_Elements[i] = m_Elements[i] - other.m_Elements[i];
}
return b;
}
/**
* Returns the inner (or dot) product of two vectors
*
* @param b the multiplication matrix
* @return the double representing the dot product
*/
public final double dotMultiply(AlgVector b) {
int n = m_Elements.length;
int bn = b.m_Elements.length;
double sum = 0.0;
for(int i = 0; i < n; i++) {
sum += m_Elements[i] * b.m_Elements[i];
}
return sum;
}
/**
* Computes the scalar product of this vector with a scalar
*
* @param s the scalar
*/
public final void scalarMultiply(double s) {
int n = m_Elements.length;
for(int i = 0; i < n; i++) {
m_Elements[i] = s * m_Elements[i];
}
}
/**
* Changes the length of a vector.
*
* @param the new length of the vector
* @return the norm of the vector
*/
public void changeLength(double len) {
double factor = this.norm();
factor = len / factor;
scalarMultiply(factor);
}
/**
* Returns the norm of the vector
*
* @return the norm of the vector
*/
public double norm() {
int n = m_Elements.length;
double sum = 0.0;
for(int i = 0; i < n; i++) {
sum += m_Elements[i] * m_Elements[i];
}
return Math.pow(sum, 0.5);
}
/**
* Norms this vector to length 1.0
*
*/
public final void normVector() {
double len = this.norm();
this.scalarMultiply(1 / len);
}
/**
* Main method for testing this class.
*/
public static void main(String[] ops) {
double[] first = {2.3, 1.2, 5.0};
try {
AlgVector test = new AlgVector(first);
System.out.println("test:\n " + test);
} catch (Exception e) {
e.printStackTrace();
}
}
}