# Lecture 004 - Array Sequence

## Array Implementation of Sequence

$\langle a_0, ..., a_{n-1}\rangle$ represented as $[a_0, ..., a_{n-1}], n, (l, r)$ Where it stores a 'a list, the length of array, and left, right index of subsequence.

By design, the sequence is immutable, since we want pure functions. The only way to get something new is to construct a new sequence.

nth A i = A[i]

• work/span: $O(1)$

length A = |A|

• work/span: $O(1)$

append (A, B)

• work: $O(|A|+|B|)$

• span: $O(1)$

tabulate f n = <f(i) : 0 <= i <= n>: construct a new sequence

subseq A (start, length) = <A[i] : start <= i < start + length>: implemented as array slice

• the observed behavior is the same as tabulate (\lambda j, nth A (left + i)) length

flatten:

• Naive: the observed behavior is mapReduce empty append (fn x => x) A

• Work: $\sum_{i = 0}^{\log |A|} (\log |A| + \|A\|)$ // TODO: send email
• Good: actual implementation is first figure out index where each old sequence start in the new array and batch copy them into new sequence

• we define $\|A\|$ as the number of total 'a element in sequence
• we define $|A|$ as the number of 'a seq in master sequence
• Work: $O(|A| + \|A\|)$ since we want to compute starting index position (prefix sum) and copy down.
• Span: $O(\log |A|)$
• We can use scan (which is $O(\log n)$) to calculate all prefix sums
• Copy down array is $O(1)$

filter predicate A:

• Good: using map and flatten, we map 'a that satisfy predicate into singleton sequence else empty. Then flatten it.

• filter p A = flatten (map (fn x => if p x then (singleton x) else empty))

• filter p A = <(if p x then <x> else <>) : x \in A)>

inject: since each modification requires copy of a new array, we want to modify multiple indice at once.

• if we don't have duplicates in the injected sequence, then

• Work: $O(|A|)$ where $|A|$ is the length of original sequence
• Span: $O(1)$
• if we have duplicates

• and we don't care about the order
• Work: $O(|A| + |B|)$ where $|B|$ is the length of injected sequence
• Span: $O(1)$ if we don't care about race condition, cost $O(\log d(u))$ if we do. (where $d(u)$ is the maximum number of updates that target the same index.) // QUESTION: why is it the cost
• we make sure left duplicated is the right one // QUESTION: what is work/span
• we make sure right duplicated is the right one

## Side Note About Compairson Function

The function Seq.merge require a compairson function that satisfy the following properties:

• for any x, cmp (x, x) = EQUAL

• for any x,y, if cmp (x, y) = EQUAL, then cmp (y, x) = EQUAL

• for any x,y, if cmp (x, y) = LESS, then cmp (y, x) = GREATER

• for any x,y, if cmp (x, y) = GREATER, then cmp (y, x) = LESS

A invalid compairson function might be: sml fun cmp (x, y) = if x < y then LESS else GREATER

If the requirement is not satisfied, some compiler will generate infinite loop when using Seq.merge.

Therefore, you should use Int.compare whenever possible.

Table of Content