From b0373d91906a5659e4e78ecec922a155d36db750 Mon Sep 17 00:00:00 2001 From: Etienne Kneuss <ekneuss@gmail.com> Date: Mon, 11 May 2015 17:55:10 +0200 Subject: [PATCH] New benchmarks with strings, justifications, etc.. --- .../purescala/invalid/AsciiToPos.scala | 47 ++++++++++++ .../purescala/valid/TextJustifyNoPost.scala | 75 +++++++++++++++++++ .../verification/editor/AsciiToPos.scala | 47 ++++++++++++ .../editor/TextJustifyNoPost.scala | 75 +++++++++++++++++++ 4 files changed, 244 insertions(+) create mode 100644 src/test/resources/regression/verification/purescala/invalid/AsciiToPos.scala create mode 100644 src/test/resources/regression/verification/purescala/valid/TextJustifyNoPost.scala create mode 100644 testcases/verification/editor/AsciiToPos.scala create mode 100644 testcases/verification/editor/TextJustifyNoPost.scala diff --git a/src/test/resources/regression/verification/purescala/invalid/AsciiToPos.scala b/src/test/resources/regression/verification/purescala/invalid/AsciiToPos.scala new file mode 100644 index 000000000..4ec536ce7 --- /dev/null +++ b/src/test/resources/regression/verification/purescala/invalid/AsciiToPos.scala @@ -0,0 +1,47 @@ +import leon.lang._ +import leon.lang.synthesis._ +import leon.lang.string._ +import leon.collection._ + +object Justify { + def tokenize(ascii: List[Char]): List[String] = tokenize0(ascii, "") + def tokenize0(ascii: List[Char], wordAcc: String): List[String] = ascii match { + case Nil() => Nil() + case Cons(h, t) => if (h == ' ') { + if (wordAcc.length == 0) { + tokenize0(t, wordAcc) + } else { + Cons(wordAcc, tokenize0(t, "")) + } + } else { + tokenize0(t, String(List(h)) + wordAcc) + } + } + + def asciiToPos(in: List[Char], index: Int): List[Int] = in match { + case Nil() => Nil() + case Cons(head, tail) => if(head == ' ') Cons(index, asciiToPos(tail, index+1)) else asciiToPos(tail, index+1) + } + + def posToAscii(positions: List[Int], originalText: List[Char], currentPos: Int): List[Char] = positions match { + case Cons(start, rest) => + if(start > currentPos) { + Cons(' ', posToAscii(rest, originalText, currentPos+1)) + } else { + originalText match { + case Cons(l, ls) => + if(l == ' ') { + Cons(' ', posToAscii(rest, ls, currentPos+1)) + } else { + Cons(l, posToAscii(positions, ls, currentPos+1)) + } + case Nil() => Nil() + } + } + case Nil() => Nil() + } + + def posToAsciiKeepTokens(ascii: List[Char]) = { + posToAscii(asciiToPos(ascii, 0), ascii, 0) + } ensuring(res => tokenize(res) == tokenize(ascii)) +} diff --git a/src/test/resources/regression/verification/purescala/valid/TextJustifyNoPost.scala b/src/test/resources/regression/verification/purescala/valid/TextJustifyNoPost.scala new file mode 100644 index 000000000..e5b06bc94 --- /dev/null +++ b/src/test/resources/regression/verification/purescala/valid/TextJustifyNoPost.scala @@ -0,0 +1,75 @@ +import leon.lang._ +import leon.lang.synthesis._ +import leon.collection._ + +object Justify { + /* + * The Science of Programming from David Gries Section 20.1 + + * The goal is to justify a text. We are given a list of indices corresponding + * to the columns of the starting point of each word. Each words are already + * separated by one space. The parameter s is the additional number of spaces + * at the end of the line that we will need to add between words. We + * want the number of space on the same line to differ by at most one. + * + * If we denote by p and q the two number of spaces between words (p and q differ + * only by 1), then we want to only switch once the number of space between words + * on the line. This means that we first separate words using p, then we do it using + * q until the end of the line. + * + * z is the line number, the rule is for odd line number to have more spaces on the right (q=p+1) + * and for even line number to have more spaces on the left (p=q+1). We do not want trailing + * spaces. + * + * n is the number of words on the line. + * + * If we apply this justify to each line of a text separately, this should lead to a good looking + * justified text. + + * Here is an example: + * + * justifying lines by + * inserting extra blanks is + * one task of a text editor. + * + * results in: + * + * justifying lines by + * inserting extra blanks is + * one task of a text editor. + */ + + def addSpaces(words: List[BigInt], p: BigInt, q: BigInt, t: BigInt, n: BigInt, i: BigInt): List[BigInt] = words match { + case Nil() => Nil() + case Cons(head, tail) => + if(i <= t) Cons(head + p*(i-1), addSpaces(tail, p, q, t, n, i+1)) + else if(i > t && i <= n) Cons(head + p*(t-1) + q*(i-t), addSpaces(tail, p, q, t, n, i+1)) + else Nil() //this should never happen + } + + //this version implements the computation of parameters + def justifyParamsImpl(n: BigInt, z: BigInt, s: BigInt): (BigInt, BigInt, BigInt) = { + require(n >= 2 && s >= 0 && z >= 1) + val (q, t, p) = if(z % 2 == 0) { + val tmp = s / (n-1) + (tmp, 1 + (s % (n - 1)), tmp + 1) + } else { + val tmp = s / (n-1) + (tmp + 1, n - (s % (n - 1)), tmp) + } + (q, t, p) + } + + def justifyImpl(n: BigInt, z: BigInt, s: BigInt, words: List[BigInt]): (BigInt, BigInt, BigInt, List[BigInt]) = { + require(n >= 2 && s >= 0 && z >= 1) + val (q, t, p) = if(z % 2 == 0) { + val tmp = s / (n-1) + (tmp, 1 + (s % (n - 1)), tmp + 1) + } else { + val tmp = s / (n-1) + (tmp + 1, n - (s % (n - 1)), tmp) + } + (q, t, p, addSpaces(words, p, q, t, n, 0)) + } + +} diff --git a/testcases/verification/editor/AsciiToPos.scala b/testcases/verification/editor/AsciiToPos.scala new file mode 100644 index 000000000..4ec536ce7 --- /dev/null +++ b/testcases/verification/editor/AsciiToPos.scala @@ -0,0 +1,47 @@ +import leon.lang._ +import leon.lang.synthesis._ +import leon.lang.string._ +import leon.collection._ + +object Justify { + def tokenize(ascii: List[Char]): List[String] = tokenize0(ascii, "") + def tokenize0(ascii: List[Char], wordAcc: String): List[String] = ascii match { + case Nil() => Nil() + case Cons(h, t) => if (h == ' ') { + if (wordAcc.length == 0) { + tokenize0(t, wordAcc) + } else { + Cons(wordAcc, tokenize0(t, "")) + } + } else { + tokenize0(t, String(List(h)) + wordAcc) + } + } + + def asciiToPos(in: List[Char], index: Int): List[Int] = in match { + case Nil() => Nil() + case Cons(head, tail) => if(head == ' ') Cons(index, asciiToPos(tail, index+1)) else asciiToPos(tail, index+1) + } + + def posToAscii(positions: List[Int], originalText: List[Char], currentPos: Int): List[Char] = positions match { + case Cons(start, rest) => + if(start > currentPos) { + Cons(' ', posToAscii(rest, originalText, currentPos+1)) + } else { + originalText match { + case Cons(l, ls) => + if(l == ' ') { + Cons(' ', posToAscii(rest, ls, currentPos+1)) + } else { + Cons(l, posToAscii(positions, ls, currentPos+1)) + } + case Nil() => Nil() + } + } + case Nil() => Nil() + } + + def posToAsciiKeepTokens(ascii: List[Char]) = { + posToAscii(asciiToPos(ascii, 0), ascii, 0) + } ensuring(res => tokenize(res) == tokenize(ascii)) +} diff --git a/testcases/verification/editor/TextJustifyNoPost.scala b/testcases/verification/editor/TextJustifyNoPost.scala new file mode 100644 index 000000000..e5b06bc94 --- /dev/null +++ b/testcases/verification/editor/TextJustifyNoPost.scala @@ -0,0 +1,75 @@ +import leon.lang._ +import leon.lang.synthesis._ +import leon.collection._ + +object Justify { + /* + * The Science of Programming from David Gries Section 20.1 + + * The goal is to justify a text. We are given a list of indices corresponding + * to the columns of the starting point of each word. Each words are already + * separated by one space. The parameter s is the additional number of spaces + * at the end of the line that we will need to add between words. We + * want the number of space on the same line to differ by at most one. + * + * If we denote by p and q the two number of spaces between words (p and q differ + * only by 1), then we want to only switch once the number of space between words + * on the line. This means that we first separate words using p, then we do it using + * q until the end of the line. + * + * z is the line number, the rule is for odd line number to have more spaces on the right (q=p+1) + * and for even line number to have more spaces on the left (p=q+1). We do not want trailing + * spaces. + * + * n is the number of words on the line. + * + * If we apply this justify to each line of a text separately, this should lead to a good looking + * justified text. + + * Here is an example: + * + * justifying lines by + * inserting extra blanks is + * one task of a text editor. + * + * results in: + * + * justifying lines by + * inserting extra blanks is + * one task of a text editor. + */ + + def addSpaces(words: List[BigInt], p: BigInt, q: BigInt, t: BigInt, n: BigInt, i: BigInt): List[BigInt] = words match { + case Nil() => Nil() + case Cons(head, tail) => + if(i <= t) Cons(head + p*(i-1), addSpaces(tail, p, q, t, n, i+1)) + else if(i > t && i <= n) Cons(head + p*(t-1) + q*(i-t), addSpaces(tail, p, q, t, n, i+1)) + else Nil() //this should never happen + } + + //this version implements the computation of parameters + def justifyParamsImpl(n: BigInt, z: BigInt, s: BigInt): (BigInt, BigInt, BigInt) = { + require(n >= 2 && s >= 0 && z >= 1) + val (q, t, p) = if(z % 2 == 0) { + val tmp = s / (n-1) + (tmp, 1 + (s % (n - 1)), tmp + 1) + } else { + val tmp = s / (n-1) + (tmp + 1, n - (s % (n - 1)), tmp) + } + (q, t, p) + } + + def justifyImpl(n: BigInt, z: BigInt, s: BigInt, words: List[BigInt]): (BigInt, BigInt, BigInt, List[BigInt]) = { + require(n >= 2 && s >= 0 && z >= 1) + val (q, t, p) = if(z % 2 == 0) { + val tmp = s / (n-1) + (tmp, 1 + (s % (n - 1)), tmp + 1) + } else { + val tmp = s / (n-1) + (tmp + 1, n - (s % (n - 1)), tmp) + } + (q, t, p, addSpaces(words, p, q, t, n, 0)) + } + +} -- GitLab