public class GeneralizedBitProcessing extends AbstractArrayProcessorWithContextSwitching
Universal converter of bitwise operation (an algorithm processing BitArray
)
to operation over any primitive type (an algorithm processing PArray
).
This class implements the following common idea. Let we have some algorithm,
that transforms the source bit array (BitArray
) b to another bit array ƒ(b).
(Here is an interface GeneralizedBitProcessing.SliceOperation
representing such algorithm.)
Let we want to generalize this algorithm for a case of any element types — byte, int,
double, etc.; in other words, for the common case of PArray
.
This class allows to do this.
Namely, let we have the source array (PArray
) a,
and let a_{min}..a_{max} be some numeric range,
a_{min}≤a_{max}
usually (but not necessarily) from the minimal to the maximal value, stored in the source array
(Arrays.rangeOf(a)
).
This class can work in two modes, called rounding modes
(and represented by GeneralizedBitProcessing.RoundingMode
enum):
the first mode is called rounddown mode, and the second is called roundup mode.
Below is the specification of the behaviour in both modes.
Rounddown mode  Roundup mode 
In both modes, we consider n+1 (n≥0) numeric thresholds
t_{0} = a_{min}, 

(In the degenerated case n=0, we consider t_{0} = t_{n} = a_{min}.)  (In the degenerated case n=0, we consider t_{0} = t_{n} = a_{max}.) 
Then we define the bit slice b_{i}, i=0,1,...,n,
as a bit array a≥t_{i}, i.e. b_{i}[k] = a[k]≥t_{i} ? 1 : 0 
Then we define the bit slice b_{i}, i=0,1,...,n,
as a bit array a>t_{i}, i.e. b_{i}[k] = a[k]>t_{i} ? 1 : 0 
The described transformation of the numeric array a to a set of n+1 "slices" (bit arrays) b_{i} is called splitting to slices. Then we consider the backward conversion of the set of bit slices b_{i} to a numeric array a', called joining the slices:  
a'[k] = t_{max i: bi[k] = 1}, or a'[k] = a_{min} if all b_{i}[k] = 0 
a'[k] = t_{min i: bi[k] = 0}, or a'[k] = a_{max} if all b_{i}[k] = 1 
It's obvious that if all a elements are inside a_{min}..a_{max}
range and if n is large enough, then a' is almost equal to a.
In particular, if a is a byte array (ByteArray
), a_{min}=0,
a_{max}=255 and n=255, then a' is strictly equal to a
(in both rounding modes).
The main task, solved by this class, is converting any bitwise operation ƒ(b) to a new operation g(a), defining for any primitivetype array a, according to the following rule:
Rounddown mode  Roundup mode 
g(a)[k] = t_{max i: ƒ(bi)[k] = 1}, or g(a)[k] = a_{min} if all ƒ(b_{i})[k] = 0 
g(a)[k] = t_{min i: ƒ(bi)[k] = 0}, or g(a)[k] = a_{max} if all ƒ(b_{i})[k] = 0 
In other words, the source array is split into bit slices, the bitwise operation is applied to all slices, and then we perform the backward conversion (joining) of slices set to a numeric array g(a). 
The conversion of the source array a to the target array c=g(a)
is performed by the main
method of this class: process(UpdatablePArray c, PArray a, Range range, long numberOfSlices)
.
The a_{min}..a_{max} range and the number of slices
numberOfSlices=n+1 are specified as arguments of this method.
The original bitwise algorithm should be specified while creating an instance of this class by
getInstance
method.
Note that the described operation does not require to calculate ƒ(b_{0})
in the rounddown mode or ƒ(b_{n}) in the roundup mode:
the result does not depend on it. Also note that the case n=0 is degenerated:
in this case always
Additional useful note: for some kinds of bitwise algorithms, you can improve the precision of the results
by replacing (after calling process
method)
the resulting array c=g(a)
with elementwise maximum, in case of rounddown mode, or elementwise minimum, in case of roundup mode,
of c and the source array a: Arrays.applyFunc(ArrayContext, net.algart.math.functions.Func, UpdatablePArray, PArray...)
method
with Func.MAX
or Func.MIN
argument.
This class allocates, in process
method, some temporary
bit arrays
. Arrays are allocated with help of the memory model,
returned by context.getMemoryModel()
method
of the context, specified while creating an instance of this class.
If the context is null, or if necessary amount of memory is less than
Arrays.SystemSettings.maxTempJavaMemory()
, then SimpleMemoryModel
is used
for allocating temporary arrays. There is a special case when
process
method
is called for bit arrays (element type is boolean); in this case, no AlgART arrays
are allocated.
When this class allocates temporary AlgART arrays, it also checks whether the passed (source and destination)
arrays are tiled, i.e. they are underlying arrays of some matrices, created by
Matrix.tile(long...)
or Matrix.tile()
method.
Only the case, when these methods are implemented in this package, is recognized.
In this case, if the src array, passed to process
method, is tiled, then the temporary AlgART arrays are tiled with the same tile structure.
This class uses multithreading (alike Arrays.copy(ArrayContext, UpdatableArray, Array)
and similar methods) to optimize calculations on multiprocessor or multicore computers.
Namely, the process
method
processes different bit slices in several parallel threads.
However, it is not useful if the bitwise processing method GeneralizedBitProcessing.SliceOperation.processBits(ArrayContext, UpdatableBitArray, BitArray, long, int, int)
already use multithreading optimization. In this case, please create an instance of this class via
getSingleThreadInstance
method.
This class is not threadsafe, but is threadcompatible and can be synchronized manually, if multithread access is necessary. However, usually there are no reasons to use the same instance of this class in different threads: usually there is much better idea to create a separate instance for every thread.
Modifier and Type  Class and Description 

static class 
GeneralizedBitProcessing.RoundingMode
Rounding mode, in which
GeneralizedBitProcessing class works: see comments to that class. 
static interface 
GeneralizedBitProcessing.SliceOperation
Algorithm of processing bit arrays, that should be generalized for another element types via
GeneralizedBitProcessing class. 
Modifier and Type  Method and Description 

GeneralizedBitProcessing 
context(ArrayContext newContext)
Switches the context: returns an instance, identical to this one excepting
that it uses the specified newContext for all operations.

static GeneralizedBitProcessing 
getInstance(ArrayContext context,
GeneralizedBitProcessing.SliceOperation sliceOperation,
GeneralizedBitProcessing.RoundingMode roundingMode)
Returns new instance of this class.

static GeneralizedBitProcessing 
getSingleThreadInstance(ArrayContext context,
GeneralizedBitProcessing.SliceOperation sliceOperation,
GeneralizedBitProcessing.RoundingMode roundingMode)
Returns new instance of this class, that does not use multithreading optimization.

int 
numberOfTasks()
Returns the number of threads, that this class uses for multithreading optimization.

void 
process(UpdatablePArray dest,
PArray src,
Range range,
long numberOfSlices)
Performs processing of the source array src, with saving results in dest array,
on the base of the bit processing algorithm, specified for this instance.

GeneralizedBitProcessing.RoundingMode 
roundingMode()
Returns the rounding mode, used by this instance.

GeneralizedBitProcessing.SliceOperation 
sliceOperation()
Returns the bit processing algorithm, used by this instance.

context, contextPart, memoryModel
public static GeneralizedBitProcessing getInstance(ArrayContext context, GeneralizedBitProcessing.SliceOperation sliceOperation, GeneralizedBitProcessing.RoundingMode roundingMode)
context
 the context
that will be used by this object;
may be null, then it will be ignored, and all temporary arrays
will be created by SimpleMemoryModel
.sliceOperation
 the bit processing operation that will be generalized by this instance.roundingMode
 the rounding mode, used by the created instance.java.lang.NullPointerException
 if sliceOperation or roundingMode argument is null.getSingleThreadInstance(ArrayContext, SliceOperation, net.algart.arrays.GeneralizedBitProcessing.RoundingMode)
public static GeneralizedBitProcessing getSingleThreadInstance(ArrayContext context, GeneralizedBitProcessing.SliceOperation sliceOperation, GeneralizedBitProcessing.RoundingMode roundingMode)
context
 the context
that will be used by this object;
may be null, then it will be ignored, and all temporary arrays
will be created by SimpleMemoryModel
.sliceOperation
 the bit processing operation that will be generalized by this instance.roundingMode
 the rounding mode, used by the created instance.java.lang.NullPointerException
 if sliceOperation or roundingMode argument is null.getInstance(ArrayContext, SliceOperation, net.algart.arrays.GeneralizedBitProcessing.RoundingMode)
public GeneralizedBitProcessing context(ArrayContext newContext)
subtask
of the full task.context
in interface ArrayProcessorWithContextSwitching
context
in class AbstractArrayProcessorWithContextSwitching
newContext
 another context, used by the returned instance; may be null.public GeneralizedBitProcessing.SliceOperation sliceOperation()
getInstance
or getSingleThreadInstance
method.public GeneralizedBitProcessing.RoundingMode roundingMode()
getInstance
or getSingleThreadInstance
method.public int numberOfTasks()
getSingleThreadInstance
method orgetThreadPoolFactory()
.recommendedNumberOfTasks()
if it was created by getInstance
method.(As in Arrays.copy(ArrayContext, UpdatableArray, Array)
, if the context argument of
getInstance
DefaultThreadPoolFactory
is used.)
Note that the real number of parallel threads will be a minimum from this value and
n, where n+1 is the desired number of slices (the last argument of
process(UpdatablePArray, PArray, Range, long)
method).
public void process(UpdatablePArray dest, PArray src, Range range, long numberOfSlices)
GeneralizedBitProcessing.SliceOperation.processBits(ArrayContext, UpdatableBitArray, BitArray, long, int, int)
method of the sliceOperation()
object (representing the used bit processing algorithm),
and the processed slices are joined to the resulting array dest.
See the precise description of this generalization of a bit processing algorithm
in the comments to this class
.
The src and dest arrays must not be the same array or views of the same array; in other case, the results will be incorrect. These arrays must have the same element types and the same lengths; in other case, an exception will occur.
The range argument specifies the a_{min}..a_{max} range,
used for splitting to bit slices.
If you do not want to lose too little or too big values in the processed array, this range should
contain all possible values of src array.
The simplest way to provide this is using the result of Arrays.rangeOf(src)
.
The numberOfSlices argument is the number of bit slices, used for splitting the src array,
which is equal to n+1 in the comments to this class
.
Less values of this argument increases speed, larger values increases precision of the result
(only numberOfSlices different values are possible for dest elements).
If the element type is a fixedpoint type (src and dest are PFixedArray
instance),
this argument is automatically truncated to
size()
+1.0))
Please remember that numberOfSlices=1 (n=0) is a degenerated case: in this case,
the dest array is just filled by range.min()
(rounddown mode) or range.min() (roundup mode),
alike in UpdatablePArray.fill(double)
method.
If the element type is boolean (BitArray
), then a generalization of the bitwise algorithm
is not necessary. In this case, if numberOfSlices>1, this method just calls
sliceOperation()
.processBits
method for the passed dest and src arrays.
(However, according to the specification of GeneralizedBitProcessing.SliceOperation
, if its
isInPlaceProcessingAllowed()
method returns true, then src arrays is firstly copied into dest,
and then the dest arrays is passed as both srcBits and destBits arguments.)
Note: if the element type is boolean, then multithreading is never used:
processBits
method is called
in the current thread, and its threadIndex and numberOfThreads arguments are
0 and 1 correspondingly.
dest
 the result of processing.src
 the source AlgART array.range
 the a_{min}..a_{max} range,
used for splitting to bit slices.numberOfSlices
 the number of bit slices (i.e. n+1); must be positive.java.lang.NullPointerException
 if one of the arguments is null.java.lang.IllegalArgumentException
 if dest and src arrays have different lengths
or element types, or if numberOfSlices<=0.