Run-length encoding of a Repa array - arrays

I have a one-dimensional Repa array that consists of 0's and 1's and I want to calculate its run-length encoding.
E.g.: Turn [0,0,1,1,1,0,0,0,1,0,1,1] into [2,3,3,1,1,2] or something similar. (I'm using a list representation because of readability)
Ideally, I would like the run-length of the 1's and ignore the 0's.
So [0,0,1,1,1,0,0,0,1,0,1,1] becomes [3,1,2].
I would like the result to be a (Repa) array as well.
How can I do this using Repa? I can't use map or traverse since they only give me one element at a time. I could try to fold with some special kind of accumulator but that doesn't seem to be ideal and I don't know it it's even possible (due to monad laws).

I'm currently just iterating over the array and returning a list without using any Repa function. I'm working on Booleans instead of 1's and 0's but the algorithm is the same. I'm converting this list to a Repa Array afterwards.
runLength :: Array U DIM1 Bool -> [Length]
runLength arr = go ([], 0, False) 0 arr
where
Z :. n = extent arr
go :: Accumulator -> Int -> Array U DIM1 Bool -> [Length]
go !acc#(xs, c, b) !i !arr | i == n = if c > 0 then c:xs else xs
| otherwise =
if unsafeIndex arr (Z :. i)
then if b
then go (xs, c+1, b) (i+1) arr
else go (xs, 1, True) (i+1) arr
else if b
then go (c:xs, 0, False) (i+1) arr
else go (xs, 0, False) (i+1) arr

Related

OCaml matching in a sorting algorithm 0(n^2)

I have tried several things. Can I simply not match with less than?
The exception is redundant, to enable the matching loop. I can imagine all sorts of things are wrong and this bit of code. It would be nice if the vague less-than-you-less-than-me concept worked.
I admit I am frustrated. Why do I get an error at j < k every time, no matter where I improve or edit? Is that simply against the rules?
I was just looking at Array Length > Array Length as my while condition, that will have to change. Also, none of the Array Sorting methods seem to me to work in the smallest upwards routine as I understand the 0(n^2).
Can this code implement Array.for_all as a sorting algorithm?
UPDATE
let i = Array.length arr in
let sort (arr : array) (j : int) (k : int) =
Array.make n x = unsorted(arr : array) (n : int) (x : int)
while i > 0
match j < k with
| true -> a.(n) <- j
| false -> failwith (Printf.sprintf "Exception Found (%d)" i)
i - 1
;;
That was a lot of questions.
Thank you.
UPDATE:
I appreciate the help very much.
I know I need two arrays, not one. The finished code should read an array, and then give an array back. So, when k points to a smallest j the purpose of the algorithm is to kick j out of the first array, from wherever it it is, put it into the second array, and append every j after that one into the second array. The job is done when the first array is empty.
I see plenty of information about lists out there but not much about arrays. How can I remove the j_n-th element of an array?
This is a nice looking example of recursion used to search and delete an element from a list, can that work in an array?
Thank you again
The match in OCaml is restricted (in essence) to matching a value (an expression) against a set of structured constants that are known at compile time. If you want to test something like whether j < k you should just use an if expression, even if it's not as exotic and powerful seeming.
There are many other problems with your code, but this seems to answer your main question.
You can use an expression in a when clause to further constrain when a pattern matches. Simple example:
let f x =
match x with
| _ when x < 5 -> true
| _ -> false
In this trivial case, an if is of course better, but it can be useful in more complicated pattern matching with lots of options.
You'll have a lot of problems with your code but to answer your question, there are 3 ways I can see to do what you want to do:
match j < k with
| true -> a.(n) <- j
| false -> failwith (Printf.sprintf "Exception Found (%d)" i)
match j with
| _ when j < k -> a.(n) <- j
| _ -> failwith (Printf.sprintf "Exception Found (%d)" i)
if j < k
then a.(n) <- j
else failwith (Printf.sprintf "Exception Found (%d)" i)
The latter being the better. The only thing you need to remember is that pattern matching is done on patterns, it looks at what the values are, not their relations to other values. You can match an int with 1, 3 or 127 but not match this int with another one or compare it with another one.
On a side note, here are some problems in your code and some answers to your questions:
sort takes an array, a j, a k and a i but then
You use Array.make by checking if it's equal to unsorted (x = f is a boolean comparison unless you write let x = f in ...). It looks like you're trying to define an internal function but it's unclear how you're making it
if you want to define a randomly sorted array, you could just write Array.init 100 (fun _ -> Random.int 100)
you're clearly trying to sort your array between i and n (while a.(i) > a.(n) do ... done but then you're checking on j that is a parameter of your function and that never changes
Array.for_all checks that a predicate is true for every value in the array. If you want to apply a function with a different return type to your array you can either use Array.map:
map f a applies function f to all the elements of a, and builds an array with the results returned by f: [| f a.(0); f a.(1); ...; f a.(length a - 1) |].
or Array.fold_{left|right}:
fold_left f init a computes f (... (f (f init a.(0)) a.(1)) ...) a.(n-1), where n is the length of the array a.
fold_right f a init computes f a.(0) (f a.(1) ( ... (f a.(n-1) init) ...)), where n is the length of the array a.
As for the sorting functions, what makes you think they won't run in O(n^2)? You can look at the way they're implemented here

How to change for loop with an array module function?

This is a school assignment. I'm trying to make a function which takes an array A and makes a new array B, which is telling how many repeated numbers there are in an array. For example A is this:
A = [|2;9;9;2;2;4|]
The B would be:
B = [|3;2;2;3;3;1|]
Ny code is right now like this and working perfectly:
let A = [|2;9;9;2;2;4|]
let n = A.Length - 1
let B = Array.create A.Length 0
for i = 0 to n do
Array.iter (fun j -> if i <> j && A.[i]=j then B.[i] <- (B.[i] + 1)) A
printfn "%A" B
My question is, how much would asymptotic time be? I know the first for loop is O(n), but what about Array.iter? And is there any way to switch the first for loop with an array function?
Array.iter is linear in the array length, so your for loop is essentially O(n²) in time complexity. Replacing the loop with another Array.iter is possible but would not change the time complexity.
If you can solve the problem whichever way you want, I suggest using a Map to aggregate the numbers and their frequencies, then mapping the original array into one showing these frequencies. Since this is a school assignment, you should probably wait until after your submission deadline before you look at the following code:
let numFrequency (a : _ []) =
let m =
(Map.empty, a)
||> Array.fold (fun m n ->
Map.tryFind n m
|> Option.defaultValue 0
|> fun x -> Map.add n (x + 1) m)
Array.map (fun n -> Map.find n m) a
let A = [|2; 9; 9; 2; 2; 4|]
let B = numFrequency A
printf "%A\n%A\n" A B

F# why arrays are not scrambled in a different way when mapping a function to scramble each array in an array

I wrote a function to scramble an array and map an array of arrays to scramble each one different but they are scrambled the same way
let rand = System.Random()
let shuffle (rand : System.Random)(array :int[] ) = let rng = new Random()
let mutable n = array.Length
while (n > 1) do
let k = rng.Next(n)
n <- n - 1
let temp = array.[n]
array.[n] <- array.[k]
array.[k] <- temp
array
let playsarray = shuffle rand
let scrambledarray = Array.map (fun x -> playsarray x )
let playsarra = fun (array : int[]) -> array |> playsarray
let smallarray = [1..10].ToArray()
let megaarray = Array.create 10 smallarray
let megarrayscrambled = megaarray |> scrambledarray
megarrayscrambled |> Seq.iter (fun y -> printfn "Ar: %A" y)
after running the code all the 10 arrays have the same order in the data ej
Ar: [|5; 1; 7; 2; 8; 10; 6; 3; 9; 4|]
Ar: [|5; 1; 7; 2; 8; 10; 6; 3; 9; 4|] and so on ...
There are two problems with your code.
First, your shuffle function takes a rand parameter but isn't actually using it: inside the function you create a new System.Random instance and use it instead of using the one passed in. The docs for the System.Random constructor mention (in the examples) that the default constructor uses the current time as a seed, so if two Random objects are created in quick succession, they would have the same seed and thus produce the same values. To fix this problem, you just need to stop creating a new Random instance in your shuffle function and instead use the one passed in (I renamed it from rand to rng so that the rest of your code wouldn't need changing). Here's your shuffle function with that change made (and with much easier-to-read indentation: you don't have to start the first line of the function on the same line as the = sign; you can put it on the next line and just indent one indentation level, four spaces):
let shuffle (rng : System.Random) (array : int[]) =
let mutable n = array.Length // The number of items left to shuffle (loop invariant).
while (n > 1) do
let k = rng.Next(n) // 0 <= k < n.
n <- n - 1 // n is now the last pertinent index;
let temp = array.[n] // swap array[n] with array[k] (does nothing if k == n).
array.[n] <- array.[k]
array.[k] <- temp
array
BUT that won't solve your issues just yet, because you've also misunderstood how Array.create works. It creates an array of a given size, where each item in the array contains the value you passed in. I.e., every entry in your megarrayscrambled array contains a reference to the same smallarray. If you did megarrayscrambled.[0].[0] <- 999 you'd see that this changed every one of the ten entries in megarrayscrambled, because they're the same array.
What you actually wanted was to use Array.init, not Array.create. Array.init takes a function and runs that function once per item it's creating in the array you're building. This means that if that function returns [1..10].ToArray(), then each time it's called it will return a different array, and you'll therefore get the results you expect. (By the way, you can create an array more simply by doing [|1..10|], and that's what I'll use in the sample code below).
So just change your let megaarray line to:
let megaarray = Array.init 10 (fun _ -> [|1..10|])
and then you should see the results you were expecting.
BTW, one more little detail: in one line you have Array.map (fun x -> playsarray x), but that is just equivalent to Array.map playsarray, which is a little simpler to read.

What is the fastest way to initialize an immutable unboxed int array in Haskell?

Is this the fastest way to initialize an immutable array in Haskell with non-default (non-zero) values? In the following examples I am simply initializing the array with values from 0 to (size-1).
Fastest so far (twice the speed of Code.ST below). Thanks to leftaroundabout:
...
import qualified Data.Vector.Unboxed as V
stArray :: Int -> V.Vector Int
stArray size =
V.generate size id
...
My original fastest:
module Code.ST where
import Data.Array.MArray
import Data.Array.ST
import Data.Array.Unboxed
stArray :: Int -> UArray Int Int
stArray size =
runSTUArray $ newArray (0,size-1) 0 >>= f 0
where
f i a
| i >= size = return a
| otherwise = writeArray a i i >> f (i + 1) a
stMain :: IO ()
stMain = do
let size = 340000000
let a = stArray size
putStrLn $ "Size: " ++ show size ++ " Min: " ++ show (a ! 0) ++ " Max: " ++ show (a ! (size - 1))
I have tried the simpler immutable ways of doing it and it is 2 to 3 times slower on my PC (YMMV). I also tried Repa but it falls over even with smaller than 340000000 size arrays (lots of HD trashing - I gave up before it finished).
Have you tried listArray from Data.Array.Unboxed? You can use them like this:
-- listArray :: (Ix i, IArray a e) => (i, i) -> [e] -> a i e
listArray (0,3) "abcdefgh" :: UArray Int Char
This will create
array (0,3) [(0,'a'),(1,'b'),(2,'c'),(3,'d')]
If you need a bit more flexibility you can use array from the same module.
-- array :: (Ix i, IArray a e) => (i, i) -> [(i, e)] -> a i e
array (0,3) (zip [1,3,0,2] "abcd") :: UArray Int Char
Which will produce
array (0,3) [(0,'c'),(1,'a'),(2,'d'),(3,'b')]
I don't really know whether it is fast or not, but certainly it is more convenient to use than hand-written ST loops.

Calling a function on an array multiple times

Still trying to grasp around the basics of Matlab.
I have a function f, that takes as arguments a matrix A, and two numbers (max and delta).
I also have a function g that takes a matrix A and one number threshold and returns a matrix B, if the value of an element in A is bigger than or equal to threshold, the corresponding value in B should be 1, if it is smaller than or equal to -threshold, it should be -1, otherwise 0. The original matrix should not be changed in neither function f nor g.
I want function f to try different values for threshold in the call for g, and I want the results from each call to line up horizontally in a new matrix.
I'm not sure how to do this function f, I'm guessing the easiest way would be to create an array:
t1= [-threshold:delta:threshold];
but how do I call g for each value of the elements in the array and line them up in a new array?
function B = f(A, threshold, delta)
t1= [-threshold:delta:threshold];
%What to write here?
end
function B = g(A, threshold)
B=(A>=threshold)-(A<=-threshold);
end
If
A=[[-3:-1]' [1:3]']
Then
f(A, 2, 1)
should return the same matrix as the command [[-1 -1 0]' [0 1 1]' [-1 -1 0]' [0 1 1]']
What you want is a loop statement, a for loop would do well here.
As for lining the arrays side by side, simply create an array of the right size:
h = size(A,1);
w = size(A,2);
result = zeros( h , w*floor(2*threshold/delta) );
Then in each iteration index the correct section:
result(:,((i*w):((i+1)*w)+1) = g(A, -threshold+delta*i);
Although, I must say, it's somewhat of an odd way to store data, would be better to use a cell array, or a 3D matrix, something like this:
result = zeros( h , w , floor(2*threshold/delta) );
and
result(:,:,i+1) = g(A, -threshold+delta*i);

Resources