//
// 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;
}
}
}