/*
* Copyright 2008-2013, ETH Zürich, Samuel Welten, Michael Kuhn, Tobias Langner,
* Sandro Affentranger, Lukas Bossard, Michael Grob, Rahul Jain,
* Dominic Langenegger, Sonia Mayor Alonso, Roger Odermatt, Tobias Schlueter,
* Yannick Stucki, Sebastian Wendland, Samuel Zehnder, Samuel Zihlmann,
* Samuel Zweifel
*
* This file is part of Jukefox.
*
* Jukefox 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 any later version. Jukefox 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
* Jukefox. If not, see <http://www.gnu.org/licenses/>.
*/
package ch.ethz.dcg.jukefox.commons.utils;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Random;
import ch.ethz.dcg.jukefox.commons.Constants;
/**
* A collection of mathematical functions.
*/
public class MathUtils {
private final static String TAG = MathUtils.class.getSimpleName();
public static float distance(float x1, float y1, float x2, float y2) {
float d1 = x1 - x2;
float d2 = y1 - y2;
return (float) Math.sqrt((float) Math.pow(d1, 2) + Math.pow(d2, 2));
}
public static float squareDistance(float[] p1, float[] p2) throws ArrayIndexOutOfBoundsException {
if (p1.length != p2.length) {
throw new ArrayIndexOutOfBoundsException(Math.max(p1.length, p2.length));
}
float sum = 0;
for (int i = 0; i < p1.length; i++) {
float d = p1[i] - p2[i];
sum += d * d;
}
return sum;
}
public static float distance(float[] p1, float[] p2) {
return (float) Math.sqrt(squareDistance(p1, p2));
}
public static float scalarProduct(float[] v1, float[] v2) {
float s = 0;
for (int i = 0; i < Constants.DIM; i++) {
s += v1[i] * v2[i];
}
return s;
}
public static float[] normalizeCoordsSum(float[] vector, float newSum) {
float sum = 0;
for (int i = 0; i < vector.length; i++) {
sum += vector[i];
}
for (int i = 0; i < vector.length; i++) {
vector[i] /= sum * newSum;
}
return vector;
}
public static float[] getMean(float[] coords1, float[] coords2) {
if (coords1.length != coords2.length) {
Log.wtf(TAG, new NullPointerException());
return null;
}
float[] mean = new float[coords1.length];
for (int i = 0; i < coords1.length; i++) {
mean[i] = (coords1[i] + coords2[i]) / 2;
}
return mean;
}
public static ArrayList<Integer> getRandomNumbers(int range, int count, Random rnd) {
// long t1 = System.currentTimeMillis();
if (count > range) {
return null;
}
if (count < 0 || range < 0) {
return null;
}
ArrayList<Integer> indices = new ArrayList<Integer>();
if (count < range / 2) {
HashMap<Integer, Integer> used = new HashMap<Integer, Integer>();
int n = range;
while (indices.size() < count) {
Integer r = Integer.valueOf(rnd.nextInt(n));
if (used.containsKey(r)) {
indices.add(used.get(r));
} else {
indices.add(r);
}
addToUsed(used, r, n - 1);
n--;
}
} else {
ArrayList<Integer> unused = new ArrayList<Integer>(range);
for (int i = 0; i < range; i++) {
// Log.v(TAG, "TT" + i + " " + (System.currentTimeMillis() - t1));
unused.add(i);
}
int u = 0;
while (indices.size() < count) {
// Log.v(TAG, "TD" + u + " " + (System.currentTimeMillis() - t1));
Integer r = unused.remove(rnd.nextInt(unused.size()));
indices.add(r);
u++;
}
}
return indices;
}
private static void addToUsed(HashMap<Integer, Integer> used, Integer key, Integer value) {
if (used.containsKey(value)) {
value = used.get(value);
addToUsed(used, key, value);
}
used.put(key, value);
}
/**
* Returns a random subset of the given list. The subset is of size not bigger than count.
*
* @param list
* @param count
* @param rnd
* Random generator
* @return
*/
public static <T> List<T> getRandomElements(List<T> list, int count, Random rnd) {
count = Math.min(count, list.size());
List<Integer> positions = getRandomNumbers(list.size(), count, rnd);
List<T> ret = new ArrayList<T>(count);
for (Integer pos : positions) {
ret.add(list.get(pos));
}
return ret;
}
/**
* @see #getRandomElements(List, int, Random)
*/
public static <T> List<T> getRandomElements(List<T> list, int count) {
return getRandomElements(list, count, RandomProvider.getRandom());
}
public static float dotProduct(float[] vector1, float[] vector2) {
if (vector1 == null || vector2 == null) {
return 0;
}
float sum = 0;
for (int i = 0; i < vector1.length; i++) {
float float1 = vector1[i];
float float2 = vector2[i];
// sum += vector1[i] * vector2[i];
sum += float1 * float2;
}
return sum;
}
public static float norm2(float[] vec) {
float sum = 0;
for (float f : vec) {
sum += Math.pow(f, 2);
}
return (float) Math.sqrt(sum);
}
/**
* Add a weighted vector to another resultVec = resultVec + (summand*weight)
*
* @param resultVec
* @param summand
*/
public static void addWeightedVector(float[] resultVec, float[] summand, float weight) {
for (int i = 0; i < resultVec.length; i++) {
resultVec[i] += summand[i] * weight;
}
}
/**
* Divide all element of a vector by a scalar
*
* @param resultVec
* @param divisor
*/
public static void divideVector(float[] resultVec, float divisor) {
for (int i = 0; i < resultVec.length; i++) {
resultVec[i] /= divisor;
}
}
public static boolean equals(float[] p1, float[] p2) {
if (p1 == null) {
return p2 == null;
}
if (p2 == null) {
return false;
}
if (p1.length != p2.length) {
return false;
}
for (int i = 0; i < p1.length; i++) {
if (p1[i] != p2[i]) {
return false;
}
}
return true;
}
public static int getHashCode(float[] p) {
if (p == null) {
return 0;
}
int hash = 0;
for (Float f : p) {
hash ^= f.hashCode();
}
return hash;
}
}