Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
15 changes: 10 additions & 5 deletions src/main/scala/io/github/acl4s/String.scala
Original file line number Diff line number Diff line change
@@ -1,5 +1,7 @@
package io.github.acl4s

import scala.annotation.targetName

import io.github.acl4s.internal.foreach

def suffixArray(s: Array[Int], upper: Int): Array[Int] = {
Expand All @@ -8,7 +10,8 @@ def suffixArray(s: Array[Int], upper: Int): Array[Int] = {
internal.saIs(s.clone(), upper)
}

def suffixArrayArbitrary[T](s: Array[T])(using Ordering[T]): Array[Int] = {
@targetName("suffixArrayArbitrary")
def suffixArray[T](s: Array[T])(using Ordering[T]): Array[Int] = {
import scala.math.Ordered.orderingToOrdered

val n = s.length
Expand Down Expand Up @@ -37,7 +40,8 @@ def suffixArray(s: String): Array[Int] = {
* T. Kasai, G. Lee, H. Arimura, S. Arikawa, and K. Park,
* Linear-Time Longest-Common-Prefix Computation in Suffix Arrays and Its Applications
*/
def lcpArrayArbitrary[T](s: Array[T], sa: Array[Int]): Array[Int] = {
@targetName("lcpArrayArbitrary")
def lcpArray[T](s: Array[T], sa: Array[Int]): Array[Int] = {
require(s.length == sa.length)
val n = s.length
require(n >= 1)
Expand Down Expand Up @@ -65,7 +69,7 @@ def lcpArrayArbitrary[T](s: Array[T], sa: Array[Int]): Array[Int] = {
}

def lcpArray(s: String, sa: Array[Int]): Array[Int] = {
lcpArrayArbitrary(s.toCharArray.map(_.toInt), sa)
lcpArray(s.toCharArray.map(_.toInt), sa)
}

/**
Expand All @@ -74,7 +78,8 @@ def lcpArray(s: String, sa: Array[Int]): Array[Int] = {
* Algorithms on Strings, Trees, and Sequences: Computer Science and
* Computational Biology
*/
private def zAlgorithmImpl[T](s: Array[T]): Array[Int] = {
@targetName("zAlgorithmArbitrary")
def zAlgorithm[T](s: Array[T]): Array[Int] = {
val n = s.length
if (n == 0) {
return Array.empty
Expand All @@ -98,4 +103,4 @@ private def zAlgorithmImpl[T](s: Array[T]): Array[Int] = {
z
}

def zAlgorithm(s: String): Array[Int] = zAlgorithmImpl(s.toCharArray)
def zAlgorithm(s: String): Array[Int] = zAlgorithm(s.toCharArray)
48 changes: 24 additions & 24 deletions src/test/scala/io/github/acl4s/StringSuite.scala
Original file line number Diff line number Diff line change
Expand Up @@ -82,16 +82,16 @@ class StringSuite extends munit.FunSuite {

test("suffixArray empty") {
assertEquals(suffixArray("").toSeq, Seq.empty[Int])
assertEquals(suffixArrayArbitrary(Array.empty[Int]).toSeq, Seq.empty[Int])
assertEquals(suffixArrayArbitrary(Array.empty[Long]).toSeq, Seq.empty[Int])
assertEquals(suffixArray(Array.empty[Int]).toSeq, Seq.empty[Int])
assertEquals(suffixArray(Array.empty[Long]).toSeq, Seq.empty[Int])
}

test("suffixArray single") {
assertEquals(suffixArrayArbitrary(Array(0)).toSeq, Seq(0))
assertEquals(suffixArrayArbitrary(Array(-1)).toSeq, Seq(0))
assertEquals(suffixArrayArbitrary(Array(1)).toSeq, Seq(0))
assertEquals(suffixArrayArbitrary(Array(Int.MinValue)).toSeq, Seq(0))
assertEquals(suffixArrayArbitrary(Array(Int.MaxValue)).toSeq, Seq(0))
assertEquals(suffixArray(Array(0)).toSeq, Seq(0))
assertEquals(suffixArray(Array(-1)).toSeq, Seq(0))
assertEquals(suffixArray(Array(1)).toSeq, Seq(0))
assertEquals(suffixArray(Array(Int.MinValue)).toSeq, Seq(0))
assertEquals(suffixArray(Array(Int.MaxValue)).toSeq, Seq(0))
}

test("suffixArray SALCP naive") {
Expand All @@ -112,9 +112,9 @@ class StringSuite extends munit.FunSuite {

val sa = suffixArrayNaive(s)

assertEquals(suffixArrayArbitrary(s).toSeq, sa.toSeq)
assertEquals(suffixArray(s).toSeq, sa.toSeq)
assertEquals(suffixArray(s, maxC).toSeq, sa.toSeq)
assertEquals(lcpArrayArbitrary(s, sa).toSeq, lcpArrayNaive(s, sa).toSeq)
assertEquals(lcpArray(s, sa).toSeq, lcpArrayNaive(s, sa).toSeq)
}
}
for (n <- 1 to 10) {
Expand All @@ -134,17 +134,17 @@ class StringSuite extends munit.FunSuite {

val sa = suffixArrayNaive(s)

assertEquals(suffixArrayArbitrary(s).toSeq, sa.toSeq)
assertEquals(suffixArray(s).toSeq, sa.toSeq)
assertEquals(suffixArray(s, maxC).toSeq, sa.toSeq)
assertEquals(lcpArrayArbitrary(s, sa).toSeq, lcpArrayNaive(s, sa).toSeq)
assertEquals(lcpArray(s, sa).toSeq, lcpArrayNaive(s, sa).toSeq)
}
}
}

test("suffixArray all A test") {
for (n <- 1 to 100) {
val s = Array.fill(n)(10)
assertEquals(suffixArrayArbitrary(s).toSeq, suffixArrayNaive(s).toSeq)
assertEquals(suffixArray(s).toSeq, suffixArrayNaive(s).toSeq)
assertEquals(suffixArray(s, 10).toSeq, suffixArrayNaive(s).toSeq)
assertEquals(suffixArray(s, 12).toSeq, suffixArrayNaive(s).toSeq)
}
Expand All @@ -153,12 +153,12 @@ class StringSuite extends munit.FunSuite {
test("suffixArray all AB test") {
for (n <- 1 to 100) {
val s = Array.tabulate(n)(_ % 2)
assertEquals(suffixArrayArbitrary(s).toSeq, suffixArrayNaive(s).toSeq)
assertEquals(suffixArray(s).toSeq, suffixArrayNaive(s).toSeq)
assertEquals(suffixArray(s, 3).toSeq, suffixArrayNaive(s).toSeq)
}
for (n <- 1 to 100) {
val s = Array.tabulate(n)(i => 1 - (i % 2))
assertEquals(suffixArrayArbitrary(s).toSeq, suffixArrayNaive(s).toSeq)
assertEquals(suffixArray(s).toSeq, suffixArrayNaive(s).toSeq)
assertEquals(suffixArray(s, 3).toSeq, suffixArrayNaive(s).toSeq)
}
}
Expand Down Expand Up @@ -198,11 +198,11 @@ class StringSuite extends munit.FunSuite {
val lcp = lcpArray(s, sa).toSeq
assertEquals(lcp, Seq(1, 0))

assertEquals(lcpArrayArbitrary(Array(0, 0, 1), sa).toSeq, lcp)
assertEquals(lcpArrayArbitrary(Array(-100, -100, 100), sa).toSeq, lcp)
assertEquals(lcpArrayArbitrary(Array(Byte.MinValue, Byte.MinValue, Byte.MaxValue), sa).toSeq, lcp)
assertEquals(lcpArrayArbitrary(Array(Int.MinValue, Int.MinValue, Int.MaxValue), sa).toSeq, lcp)
assertEquals(lcpArrayArbitrary(Array(Long.MinValue, Long.MinValue, Long.MaxValue), sa).toSeq, lcp)
assertEquals(lcpArray(Array(0, 0, 1), sa).toSeq, lcp)
assertEquals(lcpArray(Array(-100, -100, 100), sa).toSeq, lcp)
assertEquals(lcpArray(Array(Byte.MinValue, Byte.MinValue, Byte.MaxValue), sa).toSeq, lcp)
assertEquals(lcpArray(Array(Int.MinValue, Int.MinValue, Int.MaxValue), sa).toSeq, lcp)
assertEquals(lcpArray(Array(Long.MinValue, Long.MinValue, Long.MaxValue), sa).toSeq, lcp)
}

private def zAlgorithmNaive[T](s: Array[T]): Array[Int] = {
Expand All @@ -218,7 +218,7 @@ class StringSuite extends munit.FunSuite {

test("zAlgorithm empty") {
assertEquals(zAlgorithm("").toSeq, Seq.empty[Int])
assertEquals(zAlgorithmImpl(Array.empty[Int]).toSeq, Seq.empty[Int])
assertEquals(zAlgorithm(Array.empty[Int]).toSeq, Seq.empty[Int])
}

test("zAlgorithm simple") {
Expand All @@ -241,8 +241,8 @@ class StringSuite extends munit.FunSuite {
assertEquals(lcp.toSeq, Seq(9, 0, 7, 0, 5, 0, 3, 0, 1))
}

assertEquals(zAlgorithmImpl(Array(1, 10, 1, 10)).toSeq, Seq(4, 0, 2, 0))
assertEquals(zAlgorithmImpl(Array(0, 0, 0, 0, 0, 0, 0)).toSeq, zAlgorithmNaive(Array(0, 0, 0, 0, 0, 0, 0)).toSeq)
assertEquals(zAlgorithm(Array(1, 10, 1, 10)).toSeq, Seq(4, 0, 2, 0))
assertEquals(zAlgorithm(Array(0, 0, 0, 0, 0, 0, 0)).toSeq, zAlgorithmNaive(Array(0, 0, 0, 0, 0, 0, 0)).toSeq)
}

test("zAlgorithm naive") {
Expand All @@ -255,7 +255,7 @@ class StringSuite extends munit.FunSuite {
s(i) = g % 4
g /= 4
}
assertEquals(zAlgorithmImpl(s).toSeq, zAlgorithmNaive(s).toSeq)
assertEquals(zAlgorithm(s).toSeq, zAlgorithmNaive(s).toSeq)
}
}
for (n <- 1 to 10) {
Expand All @@ -267,7 +267,7 @@ class StringSuite extends munit.FunSuite {
s(i) = g % 2
g /= 2
}
assertEquals(zAlgorithmImpl(s).toSeq, zAlgorithmNaive(s).toSeq)
assertEquals(zAlgorithm(s).toSeq, zAlgorithmNaive(s).toSeq)
}
}
}
Expand Down