// // Math.NET Numerics, part of the Math.NET Project // http://numerics.mathdotnet.com // http://github.com/mathnet/mathnet-numerics // http://mathnetnumerics.codeplex.com // // Copyright (c) 2009-2010 Math.NET // // Permission is hereby granted, free of charge, to any person // obtaining a copy of this software and associated documentation // files (the "Software"), to deal in the Software without // restriction, including without limitation the rights to use, // copy, modify, merge, publish, distribute, sublicense, and/or sell // copies of the Software, and to permit persons to whom the // Software is furnished to do so, subject to the following // conditions: // // The above copyright notice and this permission notice shall be // included in all copies or substantial portions of the Software. // // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, // EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES // OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND // NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT // HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, // WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING // FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR // OTHER DEALINGS IN THE SOFTWARE. // namespace MathNet.Numerics.Threading { using System; using System.Numerics; #if !SILVERLIGHT using System.Collections.Concurrent; using System.Threading.Tasks; #endif /// /// Used to simplify parallel code, particularly between the .NET 4.0 and Silverlight Code. /// internal static class CommonParallel { /// /// Executes a for loop in which iterations may run in parallel. /// /// The start index, inclusive. /// The end index, exclusive. /// The body to be invoked for each iteration. /// The argument is null. /// At least one invocation of the body threw an exception. public static void For(int fromInclusive, int toExclusive, Action body) { #if SILVERLIGHT Parallel.For(fromInclusive, toExclusive, body); #else if (Control.DisableParallelization || Control.NumberOfParallelWorkerThreads < 2) { for (var index = fromInclusive; index < toExclusive; index++) { body(index); } } else { Parallel.ForEach( Partitioner.Create(fromInclusive, toExclusive), new ParallelOptions { MaxDegreeOfParallelism = Control.NumberOfParallelWorkerThreads }, (range, loopState) => { for (var i = range.Item1; i < range.Item2; i++) { body(i); } }); } #endif } /// /// Aggregates a function over a loop. /// /// Starting index of the loop. /// Ending index of the loop /// The function to aggregate. /// The sum of the function over the loop. public static double Aggregate(int fromInclusive, int toExclusive, Func body) { var sync = new object(); var sum = 0.0; #if SILVERLIGHT Parallel.For( fromInclusive, toExclusive, () => 0.0, (i, localData) => localData += body(i), localResult => { lock (sync) { sum += localResult; } }); #else if (Control.DisableParallelization || Control.NumberOfParallelWorkerThreads < 2) { for (var index = fromInclusive; index < toExclusive; index++) { sum += body(index); } } else { Parallel.ForEach( Partitioner.Create(fromInclusive, toExclusive), new ParallelOptions { MaxDegreeOfParallelism = Control.NumberOfParallelWorkerThreads }, () => 0.0, (range, loopState, localData) => { for (var i = range.Item1; i < range.Item2; i++) { localData += body(i); } return localData; }, localResult => { lock (sync) { sum += localResult; } }); } #endif return sum; } /// /// Aggregates a function over a loop for Complex data type. /// /// Starting index of the loop. /// Ending index of the loop /// The function to aggregate. /// The sum of the function over the loop. public static Complex Aggregate(int fromInclusive, int toExclusive, Func body) { var sync = new object(); var sum = Complex.Zero; #if SILVERLIGHT Parallel.For( fromInclusive, toExclusive, () => Complex.Zero, (i, localData) => localData += body(i), localResult => { lock (sync) { sum += localResult; } }); #else if (Control.DisableParallelization || Control.NumberOfParallelWorkerThreads < 2) { for (var index = fromInclusive; index < toExclusive; index++) { sum += body(index); } } else { Parallel.ForEach( Partitioner.Create(fromInclusive, toExclusive), new ParallelOptions { MaxDegreeOfParallelism = Control.NumberOfParallelWorkerThreads }, () => Complex.Zero, (range, loopState, localData) => { for (var i = range.Item1; i < range.Item2; i++) { localData += body(i); } return localData; }, localResult => { lock (sync) { sum += localResult; } }); } #endif return sum; } /// /// Executes each of the provided actions inside a discrete, asynchronous task. /// /// An array of actions to execute. /// The actions array contains a null element. /// An action threw an exception. public static void Invoke(params Action[] actions) { Parallel.Invoke(actions); } /// /// Selects an item (such as Max or Min). /// /// Starting index of the loop. /// Ending index of the loop /// The function to select items over a subset. /// The function to select the item of selection from the subsets. /// The selected value. public static double Select(int fromInclusive, int toExclusive, Func body, Func localFinally) { double ret = 0; var syncLock = new object(); #if SILVERLIGHT Parallel.For( fromInclusive, toExclusive, () => 0.0, (i, localData) => localData += body(i, localData), localResult => { lock (syncLock) { ret = localFinally(ret, localResult); } }); #else Parallel.ForEach( Partitioner.Create(fromInclusive, toExclusive), new ParallelOptions { MaxDegreeOfParallelism = Control.NumberOfParallelWorkerThreads }, () => 0.0, (range, loop, localData) => { for (var i = range.Item1; i < range.Item2; i++) { localData = body(i, localData); } return localData; }, localResult => { lock (syncLock) { ret = localFinally(ret, localResult); } }); #endif return ret; } } }