/** * Copyright (c) 2011 Michael Kutschke. * All rights reserved. This program and the accompanying materials * are made available under the terms of the Eclipse Public License v1.0 * which accompanies this distribution, and is available at * http://www.eclipse.org/legal/epl-v10.html * * Contributors: * Michael Kutschke - initial API and implementation. */ package org.eclipse.recommenders.jayes.util; import org.eclipse.recommenders.jayes.factor.arraywrapper.IArrayWrapper; public final class MathUtils { private MathUtils() { // Not meant to be instantiated } public static void exp(double[] vector) { for (int i = 0; i < vector.length; i++) { vector[i] = Math.exp(vector[i]); } } public static void exp(IArrayWrapper array) { for (int i = 0; i < array.length(); i++) { array.set(i, Math.exp(array.getDouble(i))); } } public static void log(double[] vector) { for (int i = 0; i < vector.length; i++) { vector[i] = Math.log(vector[i]); } } public static void log(IArrayWrapper vector) { for (int i = 0; i < vector.length(); i++) { vector.set(i, Math.log(vector.getDouble(i))); } } public static double[] normalize(double[] vector) { double normFactor = MathUtils.sum(vector); if (normFactor == 0) { throw new IllegalArgumentException("Cannot normalize a zero-Vector!"); } for (int i = 0; i < vector.length; i++) { vector[i] /= normFactor; } return vector; } public static double sum(double[] vector) { double result = 0; for (double d : vector) { result += d; } return result; } /** * computes c := a / b , but avoids division by zero. In the context of the JTA, this is valid because it holds that * b == 0 -> a == 0 * * @param a * @param b * @param c */ public static void secureDivide(double[] a, double[] b, double[] c) { for (int i = 0; i < a.length; i++) { if (b[i] != 0) { c[i] = a[i] / b[i]; } } } public static void secureSubtract(double[] a, double[] b, double[] c) { for (int i = 0; i < a.length; i++) { if (b[i] != Double.NEGATIVE_INFINITY) { c[i] = a[i] - b[i]; } } } public static double[] normalizeLog(double[] vector) { double normFactor = MathUtils.logsumexp(vector); if (normFactor == Double.NEGATIVE_INFINITY) { throw new IllegalArgumentException("Cannot normalize a zero-Vector!"); } for (int i = 0; i < vector.length; i++) { vector[i] -= normFactor; } return vector; } private static double logsumexp(double[] vector) { double max = absMax(vector); double sum = 0; for (double d : vector) { sum += Math.exp(d - max); } sum = max + Math.log(sum); return sum; } /** * @return the value that differs most from zero */ private static double absMax(double[] vector) { double result = 0; for (double d : vector) { if (d != Double.NEGATIVE_INFINITY && Math.abs(d) > Math.abs(result)) { result = d; } } return result; } public static int product(int[] vector) { return productOfRange(vector, 0, vector.length); } /** * product of the values in the array, from index start (inclusive) to end (exclusive) * * @throws ArrayIndexOutOfBoundsException * if end >= vector.length */ public static int productOfRange(int[] vector, int start, int end) { int result = 1; for (int i = start; i < end; i++) { result *= vector[i]; } return result; } public static int scalarProduct(int[] v1, int[] v2) { if (v1.length != v2.length) { throw new IllegalArgumentException("vectors differ in length"); } int result = 0; for (int i = 0; i < v1.length; i++) { result += v1[i] * v2[i]; } return result; } }