Repository: commons-math Updated Branches: refs/heads/MATH_3_X 49b4bbd41 -> 1c4ebd5bd
MATH-1250 Methods to estimate concurrency performance. Project: http://git-wip-us.apache.org/repos/asf/commons-math/repo Commit: http://git-wip-us.apache.org/repos/asf/commons-math/commit/895f50e6 Tree: http://git-wip-us.apache.org/repos/asf/commons-math/tree/895f50e6 Diff: http://git-wip-us.apache.org/repos/asf/commons-math/diff/895f50e6 Branch: refs/heads/MATH_3_X Commit: 895f50e696f07942e6694f145f1d8e3d83c5ef84 Parents: 49b4bbd Author: Gilles <er...@apache.org> Authored: Sun Jul 19 00:02:45 2015 +0200 Committer: Gilles <er...@apache.org> Committed: Sun Jul 19 20:37:27 2015 +0200 ---------------------------------------------------------------------- src/changes/changes.xml | 7 +++ .../commons/math3/ml/neuralnet/Neuron.java | 44 ++++++++++++++- .../neuralnet/sofm/KohonenTrainingTaskTest.java | 21 ++++++- .../sofm/TravellingSalesmanSolver.java | 58 ++++++++++++++++---- 4 files changed, 113 insertions(+), 17 deletions(-) ---------------------------------------------------------------------- http://git-wip-us.apache.org/repos/asf/commons-math/blob/895f50e6/src/changes/changes.xml ---------------------------------------------------------------------- diff --git a/src/changes/changes.xml b/src/changes/changes.xml index c5cdb11..3e6d4be 100644 --- a/src/changes/changes.xml +++ b/src/changes/changes.xml @@ -51,6 +51,13 @@ If the output is not quite correct, check for invisible trailing spaces! </properties> <body> <release version="3.6" date="XXXX-XX-XX" description=""> + <action dev="erans" type="add" issue="MATH-1250"> + "Neuron" class (package "o.a.c.m.ml.neuralnet"): added methods that can be used + to assess concurrency performance. + </action> + <action dev="erans" type="fix" issue="MATH-1248" due-to="Chris Popp"> + Removed unnecessary allocations in "BigFraction" (package "o.a.c.m.fraction"). + </action> <action dev="psteitz" type="fix" issue="MATH-1245"> Fixed error in computing discrete distribution of D statistics for small-sample 2-sample Kolmogorov-Smirnov tests. Error was causing incorrect p-values returned http://git-wip-us.apache.org/repos/asf/commons-math/blob/895f50e6/src/main/java/org/apache/commons/math3/ml/neuralnet/Neuron.java ---------------------------------------------------------------------- diff --git a/src/main/java/org/apache/commons/math3/ml/neuralnet/Neuron.java b/src/main/java/org/apache/commons/math3/ml/neuralnet/Neuron.java index 51c533f..3fd0c0a 100644 --- a/src/main/java/org/apache/commons/math3/ml/neuralnet/Neuron.java +++ b/src/main/java/org/apache/commons/math3/ml/neuralnet/Neuron.java @@ -20,8 +20,10 @@ package org.apache.commons.math3.ml.neuralnet; import java.io.Serializable; import java.io.ObjectInputStream; import java.util.concurrent.atomic.AtomicReference; -import org.apache.commons.math3.util.Precision; +import java.util.concurrent.atomic.AtomicLong; + import org.apache.commons.math3.exception.DimensionMismatchException; +import org.apache.commons.math3.util.Precision; /** @@ -40,6 +42,10 @@ public class Neuron implements Serializable { private final int size; /** Neuron data. */ private final AtomicReference<double[]> features; + /** Number of attempts to update a neuron. */ + private final AtomicLong numberOfAttemptedUpdates = new AtomicLong(0); + /** Number of successful updates of a neuron. */ + private final AtomicLong numberOfSuccessfulUpdates = new AtomicLong(0); /** * Creates a neuron. @@ -129,16 +135,48 @@ public class Neuron implements Serializable { return false; } + // Increment attempt counter. + numberOfAttemptedUpdates.incrementAndGet(); + if (features.compareAndSet(current, update.clone())) { - // The current thread could atomically update the state. + // The current thread could atomically update the state (attempt succeeded). + numberOfSuccessfulUpdates.incrementAndGet(); return true; } else { - // Some other thread came first. + // Some other thread came first (attempt failed). return false; } } /** + * Retrieves the number of calls to the + * {@link #compareAndSetFeatures(double[],double[]) compareAndSetFeatures} + * method. + * Note that if the caller wants to use this method in combination with + * {@link #getNumberOfSuccessfulUpdates()}, additional synchronization + * may be required to ensure consistency. + * + * @return the number of update attempts. + */ + public long getNumberOfAttemptedUpdates() { + return numberOfAttemptedUpdates.get(); + } + + /** + * Retrieves the number of successful calls to the + * {@link #compareAndSetFeatures(double[],double[]) compareAndSetFeatures} + * method. + * Note that if the caller wants to use this method in combination with + * {@link #getNumberOfAttemptedUpdates()}, additional synchronization + * may be required to ensure consistency. + * + * @return the number of successful updates. + */ + public long getNumberOfSuccessfulUpdates() { + return numberOfSuccessfulUpdates.get(); + } + + /** * Checks whether the contents of both arrays is the same. * * @param current Current values. http://git-wip-us.apache.org/repos/asf/commons-math/blob/895f50e6/src/test/java/org/apache/commons/math3/ml/neuralnet/sofm/KohonenTrainingTaskTest.java ---------------------------------------------------------------------- diff --git a/src/test/java/org/apache/commons/math3/ml/neuralnet/sofm/KohonenTrainingTaskTest.java b/src/test/java/org/apache/commons/math3/ml/neuralnet/sofm/KohonenTrainingTaskTest.java index d3f5628..218a709 100644 --- a/src/test/java/org/apache/commons/math3/ml/neuralnet/sofm/KohonenTrainingTaskTest.java +++ b/src/test/java/org/apache/commons/math3/ml/neuralnet/sofm/KohonenTrainingTaskTest.java @@ -30,6 +30,7 @@ import java.util.concurrent.Future; import org.apache.commons.math3.Retry; import org.apache.commons.math3.RetryRunner; +import org.apache.commons.math3.ml.neuralnet.sofm.KohonenTrainingTask; import org.apache.commons.math3.util.FastMath; import org.junit.Assert; import org.junit.Test; @@ -65,7 +66,12 @@ public class KohonenTrainingTaskTest { final TravellingSalesmanSolver solver = new TravellingSalesmanSolver(squareOfCities, 2, seed); // printSummary("before.travel.seq.dat", solver); - solver.createSequentialTask(15000).run(); + final Runnable task = solver.createSequentialTask(15000); + task.run(); + + // All update attempts must be successful in the absence of concurrency. + Assert.assertEquals(solver.getUpdateRatio(), 1, 0d); + // printSummary("after.travel.seq.dat", solver); final City[] result = solver.getCityList(); Assert.assertEquals(squareOfCities.length, @@ -96,12 +102,16 @@ public class KohonenTrainingTaskTest { new City("i0", 1, 1), }; - final TravellingSalesmanSolver solver = new TravellingSalesmanSolver(squareOfCities, 2); + // Seed that allows the unit test to always succeed. + final long seed = 534712311L; + + final TravellingSalesmanSolver solver = new TravellingSalesmanSolver(squareOfCities, 2, seed); // printSummary("before.travel.par.dat", solver); // Parallel execution. final ExecutorService service = Executors.newCachedThreadPool(); - final Runnable[] tasks = solver.createParallelTasks(3, 5000); + final int numProcs = Runtime.getRuntime().availableProcessors(); + final Runnable[] tasks = solver.createParallelTasks(numProcs, 5000); final List<Future<?>> execOutput = new ArrayList<Future<?>>(); // Run tasks. for (Runnable r : tasks) { @@ -116,6 +126,11 @@ public class KohonenTrainingTaskTest { // Terminate all threads. service.shutdown(); + if (numProcs > 1) { + // We expect that some update attempts will be concurrent. + Assert.assertTrue(solver.getUpdateRatio() < 1); + } + // printSummary("after.travel.par.dat", solver); final City[] result = solver.getCityList(); Assert.assertEquals(squareOfCities.length, http://git-wip-us.apache.org/repos/asf/commons-math/blob/895f50e6/src/test/java/org/apache/commons/math3/ml/neuralnet/sofm/TravellingSalesmanSolver.java ---------------------------------------------------------------------- diff --git a/src/test/java/org/apache/commons/math3/ml/neuralnet/sofm/TravellingSalesmanSolver.java b/src/test/java/org/apache/commons/math3/ml/neuralnet/sofm/TravellingSalesmanSolver.java index 369ea33..026d8bd 100644 --- a/src/test/java/org/apache/commons/math3/ml/neuralnet/sofm/TravellingSalesmanSolver.java +++ b/src/test/java/org/apache/commons/math3/ml/neuralnet/sofm/TravellingSalesmanSolver.java @@ -23,23 +23,30 @@ import java.util.Set; import java.util.HashSet; import java.util.Collection; import java.util.Iterator; -import org.apache.commons.math3.ml.neuralnet.Neuron; -import org.apache.commons.math3.ml.neuralnet.Network; -import org.apache.commons.math3.ml.neuralnet.FeatureInitializer; -import org.apache.commons.math3.ml.neuralnet.FeatureInitializerFactory; + +import org.apache.commons.math3.analysis.FunctionUtils; +import org.apache.commons.math3.analysis.UnivariateFunction; +import org.apache.commons.math3.analysis.function.Constant; +import org.apache.commons.math3.analysis.function.HarmonicOscillator; +import org.apache.commons.math3.distribution.RealDistribution; +import org.apache.commons.math3.distribution.UniformRealDistribution; +import org.apache.commons.math3.exception.MathUnsupportedOperationException; import org.apache.commons.math3.ml.distance.DistanceMeasure; import org.apache.commons.math3.ml.distance.EuclideanDistance; +import org.apache.commons.math3.ml.neuralnet.FeatureInitializer; +import org.apache.commons.math3.ml.neuralnet.FeatureInitializerFactory; +import org.apache.commons.math3.ml.neuralnet.Network; +import org.apache.commons.math3.ml.neuralnet.Neuron; import org.apache.commons.math3.ml.neuralnet.oned.NeuronString; +import org.apache.commons.math3.ml.neuralnet.sofm.KohonenTrainingTask; +import org.apache.commons.math3.ml.neuralnet.sofm.KohonenUpdateAction; +import org.apache.commons.math3.ml.neuralnet.sofm.LearningFactorFunction; +import org.apache.commons.math3.ml.neuralnet.sofm.LearningFactorFunctionFactory; +import org.apache.commons.math3.ml.neuralnet.sofm.NeighbourhoodSizeFunction; +import org.apache.commons.math3.ml.neuralnet.sofm.NeighbourhoodSizeFunctionFactory; import org.apache.commons.math3.random.RandomGenerator; import org.apache.commons.math3.random.Well44497b; -import org.apache.commons.math3.exception.MathUnsupportedOperationException; import org.apache.commons.math3.util.FastMath; -import org.apache.commons.math3.analysis.UnivariateFunction; -import org.apache.commons.math3.analysis.FunctionUtils; -import org.apache.commons.math3.analysis.function.HarmonicOscillator; -import org.apache.commons.math3.analysis.function.Constant; -import org.apache.commons.math3.distribution.RealDistribution; -import org.apache.commons.math3.distribution.UniformRealDistribution; /** * Solves the "Travelling Salesman's Problem" (i.e. trying to find the @@ -133,6 +140,35 @@ public class TravellingSalesmanSolver { } /** + * Measures the network's concurrent update performance. + * + * @return the ratio between the number of succesful network updates + * and the number of update attempts. + */ + public double getUpdateRatio() { + return computeUpdateRatio(net); + } + + /** + * Measures the network's concurrent update performance. + * + * @param net Network to be trained with the SOFM algorithm. + * @return the ratio between the number of successful network updates + * and the number of update attempts. + */ + private static double computeUpdateRatio(Network net) { + long numAttempts = 0; + long numSuccesses = 0; + + for (Neuron n : net) { + numAttempts += n.getNumberOfAttemptedUpdates(); + numSuccesses += n.getNumberOfSuccessfulUpdates(); + } + + return (double) numSuccesses / (double) numAttempts; + } + + /** * Creates an iterator that will present a series of city's coordinates in * a random order. *