How to "invert" an array in linear time functionally rather than procedurally? - arrays

Say I have an array of integers A such that A[i] = j, and I want to "invert it"; that is, to create another array of integers B such that B[j] = i.
This is trivial to do procedurally in linear time in any language; here's a Python example:
def invert_procedurally(A):
B = [None] * (max(A) + 1)
for i, j in enumerate(A):
B[j] = i
return B
However, is there any way to do this functionally (as in functional programming, using map, reduce, or functions like those) in linear time?
The code might look something like this:
def invert_functionally(A):
# We can't modify variables in FP; we can only return a value
return map(???, A) # What goes here?
If this is not possible, what is the best (most efficient) alternative when doing functional programming?

In this context are arrays mutable or immutable? Generally I'd expect the mutable case to be about as straightforward as your Python implementation, perhaps aside from a few wrinkles with types. I'll assume you're more interested in the immutable scenario.
This operation inverts the indices and elements, so it's also important to know something about what constitutes valid array indices and impose those same constraints on the elements. Haskell has a class for index constraints called Ix. Any Ix type is ordered and has a range implementation to make an ordered list of indices ranging from one specified index to another. I think this Haskell implementation does what you want.
import Data.Array.IArray
invertArray :: (Ix x) => Array x x -> Array x x
invertArray arr = listArray (low,high) newElems
where oldElems = elems arr
newElems = indices arr
low = minimum oldElems
high = maximum oldElems
Under the hood listArray uses zipWith and range to associate indices in the specified range to the listed elements. That part ought to be linear time, and so is the one-time operation of extracting elements and indices from an array.
Whenever the sets of the input arrays indices and elements differ some elements will be undefined, which for better or worse blow up faster than Python's None. I believe you could overcome the undefined issue by implementing new Ix a instances over the Maybe monad, for instance.
Quick side-note: check out the invPerm example in the Haskell 98 Library Report. It does something similar to invertArray, but assumes up front that input array's elements are a permutation of its indices.

A solution needing mapand 3 operations:
toTuples views an the array as a list of tuples (i,e) where i is the index and e the element in the array at that index.
fromTuples creates and loads an array from a list of tuples.
swap which takes a tuple (a,b) and returns (b,a)
Hence the solution would be (in Haskellish notation):
invert = fromTuples . map swap . toTuples

Related

Parallel vectorized reduction of subarrays in array without explicit iteration

I have a linear array arr which is is the combination of the elements of a number of smaller sub-arrays. The position of each sub-array in the large array is given by an offsets array.
For example
If arr = [1,2,4,3,6,4,8,9,12,3] and offsets = [0,2,4,9], then the sub-arrays are [1,2,4], [3,6] and [4,8,9,12,3].
Now, given the array arr and offsets, I would like to perform a parallel reduction on each subarray. Let's assume that we want to find the max() of each subarray. So, the result, in our example case, will be [4,6,12]. The important constraint in the case is that the operations should be strictly vectorized, and no explicit iteration in loops is allowed. For instance, in python, something like this isn't allowed:
import numpy
arr = numpy.array([1,2,4,3,6,4,8,9,12,3])
offsets = numpy.array([0,2,4,9])
max_array = numpy.empty(num_sub_arrays)
for i in range(num_sub_arrays): # Eliminate this loop!
max_array[i] = numpy.max(arr[offsets[i]:offsets[i+1]])
How can I go about achieving this? Also, please note that the code should be as general as possible, as I plan on implementing it across multiple hardware (CUDA, AVX etc).
Any implementable hints regarding it will be highly helpful!

What is the time complexity of declaring a 2d array

What is the worst case running time of declaring a 2D array? The 2d array is not strictly square. I have seen answers that state it is O(n) and I have also seen answers that state its O(n²).
In my mind, when declaring an object array such as this:
Object[][] gridArray = new Object[i][j];
//The number of elements n = i*j
The time complexity when declaring the array should be O(n) as it will just scale linearly depending on how many elements there will be. Am I missing something?
It depends on what you mean by n.
Some may define n as your i and see the j depended to that, for example a square n * n, for that definition you get O(n^2), O(i * i) or O(i * j) if j in O(i).
However you defined it as n = i * j. So yes, it is O(n) for your definition of n but that notation hides O(i * j) which may be more appropriate.
However note that it depends on whether your language actually initializes all those array entries at creation. Some languages don't do that!
I guess your code is Java, this language actually sets every entry to an initial value. In your case this would be null, thus it indeed creates i * j elements and sets them to null, yielding O(i * j).
Also take a look at Syntax for creating a two-dimensional array, which explains in detail how your code works.

Comparing Arrays of Arrays

So I have two arrays, a and b of varying size containing child arrays of the same length and both are of the same type as are the child arrays (float for example).
I want find all the matches for the child arrays in b within the child arrays of array a.
Now I'm looking for a faster or better way to do this (perhaps CUDA or SIMD coding).
At the moment I have something like (F#):
let mutable result = 0.0
for a in arrayA do:
for b in arrayB do:
if a = b then
result <- result + (a |> Array.sum)
My array a contains around 5 Million elements and array b contains around 3000. Hence my performance related issue.
You use bruteforce algorithm to solve the problem. Suppose that A and B have sizes N and M respecively, each small array you are checking for equality is K elements long. Your algorithm takes O(N M K) time in worst case and O(N M + Z K) in best case, given that number of matches is Z (which may attain N M).
Notice that each of your small arrays is essentially a string. You have two sets of strings, and you want to detect all equal pairs between them.
This problem can be solved with hash table. Create a hash table with O(M) cells. In this table, store strings of array B without duplication. After you have added all the strings from B, iterate over strings from A and check if they are present in the hash table. This solution can be implemented as randomized one with O((M + N) K) time complexity on average, which is linear of the input data size.
Also, you can solve the problem in non-randomized way. Put all the strings into a single array X and sort them. During sorting, put strings from A after all equal strings from B. Note that you should remember which strings of X came from which array. You can either use some fast comparison sort, or use radix sort. In the latter case sorting is done in linear time, i.e. in O((M + N) K).
Now all the common strings are stored in X contiguously. You can iterate over X, maintaining the set of strings from B equal to the currently processed string. If you see a string different from the previous one, clear the set. If the string is from B, add it to the set. If it is from A, record that it is equal to the set of elements from B. This is a single pass over X with O(K) time per string, so it takes O((M + N) K) time in total.
If length K of your strings is not tiny, you can add vectorization to string operations. In case of hash table approach, most time would be spent on computing string hash. If you choose polynomial hash modulo 2^32, then it is easy to vectorize it with SSE2. Also, you need fast string comparison, which can be done with memcmp function, which can be easily vectorized too. For the sorting solution, you need only string comparisons. Also, you might want to implement a radix sort, which is not possible to vectorize, I'm afraid.
Efficient parallelization of both approaches is not very simple. For the first algorithm, you need a concurrent hash table. Actually, there are even some lock-free hash tables out there. For the second approach, you can parallelize the first step (quicksort is easy to parallelize, radix sort is not). The second step can be parallelized too if there are not too many equal strings: you can split the array X into almost equal pieces, breaking it only between two different strings.
You may save some time comparing large arrays by splitting them into smaller arrays and doing the equality check in parallel.
This chunk function is taken directly from F# Snippets
let chunk chunkSize (arr : _ array) =
query {
for idx in 0..(arr.Length - 1) do
groupBy (idx / chunkSize) into g
select (g |> Seq.map (fun idx -> arr.[idx]))
}
Then going something like this to compare arrays. I have chosen to split each array into 4 smaller chunks:
let fastArrayCompare a1 a2 = async {
let! a =
Seq.zip (chunk 4 a1) (chunk 4 a2)
|> Seq.map (fun (a1',a2') -> async {return a1' = a2'})
|> Async.Parallel
return Array.TrueForAll (a,(fun t -> t))}
Obviously you now adding some extra time with the array splitting but with lots of very large array comparisons you should make up this time and then some.

Array in Haskell

How is an array created in haskell using the constructor array? I mean, does it create the first element and so on? In that case how does it read the associated list?
For example if we consider the following two programs:-
ar :: Int->(Array Int Int)
ar n = array (0,(n-1)) (((n-1),1):[(i,((ar n)!(i+1))) | i<-[0..(n-2)]])
ar :: Int->(Array Int Int)
ar n = array (0,(n-1)) ((0,1):[(i,((ar n)!(i-1))) | i<-[1..(n-1)]])
Will these two have different time complexity?
That depends on the implementation, but in a reasonable implementation, both have the same complexity (linear in the array size).
In GHC's array implementation, if we look at the code
array (l,u) ies
= let n = safeRangeSize (l,u)
in unsafeArray' (l,u) n
[(safeIndex (l,u) n i, e) | (i, e) <- ies]
{-# INLINE unsafeArray' #-}
unsafeArray' :: Ix i => (i,i) -> Int -> [(Int, e)] -> Array i e
unsafeArray' (l,u) n#(I# n#) ies = runST (ST $ \s1# ->
case newArray# n# arrEleBottom s1# of
(# s2#, marr# #) ->
foldr (fill marr#) (done l u n marr#) ies s2#)
{-# INLINE fill #-}
fill :: MutableArray# s e -> (Int, e) -> STRep s a -> STRep s a
-- NB: put the \s after the "=" so that 'fill'
-- inlines when applied to three args
fill marr# (I# i#, e) next
= \s1# -> case writeArray# marr# i# e s1# of
s2# -> next s2#
we can see that first a new chunk of memory is allocated for the array, that is then sequentially filled with arrEleBottom (which is an error call with message "undefined array element"), and then the elements supplied in the list are written to the respective indices in the order they appear in the list.
In general, since it is a boxed array, what is written to the array on construction is a thunk that specifies how to compute the value when it is needed (explicitly specified values, like the literal 1 in your examples, will result in a direct pointer to that value written to the array).
When the evaluation of such a thunk is forced, it may force also the evaluation of further thunks in the array - if the thunk refers to other array elements, like here. In the specific examples here, forcing any thunk results in forcing all thunks later resp. earlier in the array until the end with the entry that doesn't refer to another array element is reached. In the first example, if the first array element that is forced is the one at index 0, that builds a thunk of size proportional to the array length that is then reduced, so forcing the first array element then has complexity O(n), then all further elements are already evaluated, and forcing them is O(1). In the second example, the situation is symmetric, there forcing the last element first incurs the total evaluation cost. If the elements are demanded in a different order, the cost of evaluating all thunks is spread across the requests for different elements, but the total cost is the same. The cost of evaluating any not-yet-evaluated thunk is proportional to its distance from the next already evaluated thunk, and includes evaluating all thunks in between.
Since array access is constant time (except for cache effects, but those should not make a difference if you fill the array either forward or backward, they could make a big difference if the indices were in random order, but that still wouldn't affect time complexity), both have the same complexity.
Note however, that your using ar n to define the array elements carries the risk of multiple arrays being allocated (if compiled without optimisations, GHC does that - just tested: even with optimisations that can happen). To make sure that only one is constructed, make it
ar n = result
where
result = array (0,n-1) (... result!index ...)

Compare two integer arrays with same length

[Description] Given two integer arrays with the same length. Design an algorithm which can judge whether they're the same. The definition of "same" is that, if these two arrays were in sorted order, the elements in corresponding position should be the same.
[Example]
<1 2 3 4> = <3 1 2 4>
<1 2 3 4> != <3 4 1 1>
[Limitation] The algorithm should require constant extra space, and O(n) running time.
(Probably too complex for an interview question.)
(You can use O(N) time to check the min, max, sum, sumsq, etc. are equal first.)
Use no-extra-space radix sort to sort the two arrays in-place. O(N) time complexity, O(1) space.
Then compare them using the usual algorithm. O(N) time complexity, O(1) space.
(Provided (max − min) of the arrays is of O(Nk) with a finite k.)
You can try a probabilistic approach - convert the arrays into a number in some huge base B and mod by some prime P, for example sum B^a_i for all i mod some big-ish P. If they both come out to the same number, try again for as many primes as you want. If it's false at any attempts, then they are not correct. If they pass enough challenges, then they are equal, with high probability.
There's a trivial proof for B > N, P > biggest number. So there must be a challenge that cannot be met. This is actually the deterministic approach, though the complexity analysis might be more difficult, depending on how people view the complexity in terms of the size of the input (as opposed to just the number of elements).
I claim that: Unless the range of input is specified, then it is IMPOSSIBLE to solve in onstant extra space, and O(n) running time.
I will be happy to be proven wrong, so that I can learn something new.
Insert all elements from the first array into a hashtable
Try to insert all elements from the second array into the same hashtable - for each insert to element should already be there
Ok, this is not with constant extra space, but the best I could come up at the moment:-). Are there any other constraints imposed on the question, like for example to biggest integer that may be included in the array?
A few answers are basically correct, even though they don't look like it. The hash table approach (for one example) has an upper limit based on the range of the type involved rather than the number of elements in the arrays. At least by by most definitions, that makes the (upper limit on) the space a constant, although the constant may be quite large.
In theory, you could change that from an upper limit to a true constant amount of space. Just for example, if you were working in C or C++, and it was an array of char, you could use something like:
size_t counts[UCHAR_MAX];
Since UCHAR_MAX is a constant, the amount of space used by the array is also a constant.
Edit: I'd note for the record that a bound on the ranges/sizes of items involved is implicit in nearly all descriptions of algorithmic complexity. Just for example, we all "know" that Quicksort is an O(N log N) algorithm. That's only true, however, if we assume that comparing and swapping the items being sorted takes constant time, which can only be true if we bound the range. If the range of items involved is large enough that we can no longer treat a comparison or a swap as taking constant time, then its complexity would become something like O(N log N log R), were R is the range, so log R approximates the number of bits necessary to represent an item.
Is this a trick question? If the authors assumed integers to be within a given range (2^32 etc.) then "extra constant space" might simply be an array of size 2^32 in which you count the occurrences in both lists.
If the integers are unranged, it cannot be done.
You could add each element into a hashmap<Integer, Integer>, with the following rules: Array A is the adder, array B is the remover. When inserting from Array A, if the key does not exist, insert it with a value of 1. If the key exists, increment the value (keep a count). When removing, if the key exists and is greater than 1, reduce it by 1. If the key exists and is 1, remove the element.
Run through array A followed by array B using the rules above. If at any time during the removal phase array B does not find an element, you can immediately return false. If after both the adder and remover are finished the hashmap is empty, the arrays are equivalent.
Edit: The size of the hashtable will be equal to the number of distinct values in the array does this fit the definition of constant space?
I imagine the solution will require some sort of transformation that is both associative and commutative and guarantees a unique result for a unique set of inputs. However I'm not sure if that even exists.
public static boolean match(int[] array1, int[] array2) {
int x, y = 0;
for(x = 0; x < array1.length; x++) {
y = x;
while(array1[x] != array2[y]) {
if (y + 1 == array1.length)
return false;
y++;
}
int swap = array2[x];
array2[x] = array2[y];
array2[y] = swap;
}
return true;
}
For each array, Use Counting sort technique to build the count of number of elements less than or equal to a particular element . Then compare the two built auxillary arrays at every index, if they r equal arrays r equal else they r not . COunting sort requires O(n) and array comparison at every index is again O(n) so totally its O(n) and the space required is equal to the size of two arrays . Here is a link to counting sort http://en.wikipedia.org/wiki/Counting_sort.
given int are in the range -n..+n a simple way to check for equity may be the following (pseudo code):
// a & b are the array
accumulator = 0
arraysize = size(a)
for(i=0 ; i < arraysize; ++i) {
accumulator = accumulator + a[i] - b[i]
if abs(accumulator) > ((arraysize - i) * n) { return FALSE }
}
return (accumulator == 0)
accumulator must be able to store integer with range = +- arraysize * n
How 'bout this - XOR all the numbers in both the arrays. If the result is 0, you got a match.

Resources