# HG changeset patch # User Christian Urban # Date 1580120293 0 # Node ID 8a34b2ebc8cc721ddbb0de88c05af51cde376e40 # Parent 0e591f806290d90f966ea0ba69b338eb2d0d180d updated diff -r 0e591f806290 -r 8a34b2ebc8cc IDEAS --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/IDEAS Mon Jan 27 10:18:13 2020 +0000 @@ -0,0 +1,8 @@ +flight data + +https://blog.jonlu.ca/posts/aa-tracker?ref=rprog + +============== +knight + +if one field is reachable from another in three moves \ No newline at end of file diff -r 0e591f806290 -r 8a34b2ebc8cc README --- a/README Tue Dec 03 11:07:09 2019 +0000 +++ b/README Mon Jan 27 10:18:13 2020 +0000 @@ -3,7 +3,8 @@ java -jar procyon-decompiler-0.5.36.jar -jar templates1/drumb.jar -o out - +------------------------- +~/pep-material/moss/mossnet -l java -b ../base.java *.java ------------------------- diff -r 0e591f806290 -r 8a34b2ebc8cc cws/cw02.tex --- a/cws/cw02.tex Tue Dec 03 11:07:09 2019 +0000 +++ b/cws/cw02.tex Mon Jan 27 10:18:13 2020 +0000 @@ -7,6 +7,8 @@ \begin{document} +%% should ask to lower case the words. + \section*{Part 7 (Scala)} \mbox{}\hfill\textit{``What one programmer can do in one month,}\\ diff -r 0e591f806290 -r 8a34b2ebc8cc cws/cw03.pdf Binary file cws/cw03.pdf has changed diff -r 0e591f806290 -r 8a34b2ebc8cc cws/cw03.tex --- a/cws/cw03.tex Tue Dec 03 11:07:09 2019 +0000 +++ b/cws/cw03.tex Mon Jan 27 10:18:13 2020 +0000 @@ -348,8 +348,8 @@ \noindent As you should have seen in the earlier parts, a naive search for tours beyond $8 \times 8$ boards and also searching for closed tours even on small -boards takes too much time. There is a heuristic, called \emph{Warnsdorf's -Rule} that can speed up finding a tour. This heuristic states that a +boards takes too much time. There is a heuristics, called \emph{Warnsdorf's +Rule} that can speed up finding a tour. This heuristics states that a knight is moved so that it always proceeds to the field from which the knight will have the \underline{fewest} onward moves. For example for a knight on field $(1, 3)$, the field $(0, 1)$ has the fewest possible @@ -386,7 +386,7 @@ Warnsdorf’s Rule. That means moves with the fewest legal onward moves should come first (in order to be tried out first). \hfill[1 Mark] -\item[(7)] Implement a \texttt{first\_closed\_tour\_heuristic} +\item[(7)] Implement a \texttt{first\_closed\_tour\_heuristics} function that searches for a single \textbf{closed} tour on a $6\times 6$ board. It should try out onward moves according to @@ -394,13 +394,13 @@ a solution when started in the middle of the board (that is position $(dimension / 2, dimension / 2)$). \hfill[1 Mark] -\item[(8)] Implement a \texttt{first\_tour\_heuristic} function +\item[(8)] Implement a \texttt{first\_tour\_heuristics} function for boards up to $30\times 30$. It is the same function as in (7) but searches for tours (not just closed tours). It might be called with any field on the board as starting field.\\ %You have to be careful to write a - %tail-recursive function of the \texttt{first\_tour\_heuristic} function + %tail-recursive function of the \texttt{first\_tour\_heuristics} function %otherwise you will get problems with stack-overflows.\\ \mbox{}\hfill[1 Mark] \end{itemize} diff -r 0e591f806290 -r 8a34b2ebc8cc handouts/pep-ho.pdf Binary file handouts/pep-ho.pdf has changed diff -r 0e591f806290 -r 8a34b2ebc8cc handouts/pep-ho.tex --- a/handouts/pep-ho.tex Tue Dec 03 11:07:09 2019 +0000 +++ b/handouts/pep-ho.tex Mon Jan 27 10:18:13 2020 +0000 @@ -42,6 +42,44 @@ % https://www.matthewgerstman.com/map-filter-reduce/ +% Timing +% +% xs.map(x => (x, xs.count(_==x))) +% +% vs xs.groupBy(identity) +% +% first is quadratic, while second is linear. + +% contrast map with a for loop in imperative languages +% +% Let’s use a simple example of calculating sales tax on an array of +% prices. +% +% const prices = [19.99, 4.95, 25, 3.50]; +% let new_prices = []; +% +% for(let i=0; i < prices.length; i++) { +% new_prices.push(prices[i] * 1.06); +% } +% +% We can achieve the same results using .map(): +% +% const prices = [19.99, 4.95, 25, 3.50]; +% let new_prices = prices.map(price => price * 1.06); +% +% The syntax above is condensed so let’s walk through it a bit. The +% .map() method takes a callback, which can be thought of as a function. +% That’s what is between the parentheses. The variable price is the name +% that will be used to identify each value. Since there’s only one +% input, we can omit the usual parentheses around the parameters. + +% potentially a worked example? Tetris in scala.js +% +% https://medium.com/@michael.karen/learning-modern-javascript-with-tetris-92d532bcd057 +% +% Scala videos +% https://www.youtube.com/user/DrMarkCLewis + \begin{document} \fnote{\copyright{} Christian Urban, King's College London, 2017, 2018, 2019} @@ -1009,6 +1047,16 @@ all aggregate functions are pre-defined and often you have to write your own recursive function for this. +\subsection*{Always Produce a Result! No Exceptions!} +% +%Function should always produce a value. Exception is not thrown. +%Whenever there is a possibility of non-value result (exception, void, +%undefined, null, etc.), it should be incorporated in the result type. +%Such types include but not limited to +% +%Option[T] + + \subsection*{Higher-Order Functions} Functions obviously play a central role in functional programming. Two simple diff -r 0e591f806290 -r 8a34b2ebc8cc marking4/mk-advanced --- a/marking4/mk-advanced Tue Dec 03 11:07:09 2019 +0000 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,24 +0,0 @@ -#!/bin/sh -###set -e - -trap "exit" INT - -files=${1:-assignment20189-*} - -for sd in $files; do - cd $sd - echo $sd - touch . - cp ../../../marking4/postfix_test.sh . - cp ../../../marking4/postfix_test7.scala . - cp ../../../marking4/postfix_test8.scala . - cp ../../../marking4/postfix_test9.scala . - ./postfix_test.sh output - rm postfix_test.sh - rm postfix_test7.scala - rm postfix_test8.scala - rm postfix_test9.scala - cd .. -done - - diff -r 0e591f806290 -r 8a34b2ebc8cc marking4/mk-postfix --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/marking4/mk-postfix Mon Jan 27 10:18:13 2020 +0000 @@ -0,0 +1,25 @@ +#!/bin/sh +###set -e + +trap "exit" INT + +files=${1:-assignment2019-*/Part8/*} + +for sd in $files; do + cd $sd + echo $sd + touch . + cp ../../../../../marking4/postfix_test.sh . + cp ../../../../../marking4/postfix_test7.scala . + cp ../../../../../marking4/postfix_test8.scala . + cp ../../../../../marking4/postfix_test9.scala . + ./postfix_test.sh output + rm postfix_test.sh + rm postfix_test7.scala + rm postfix_test8.scala + rm postfix_test9.scala + cd .. + cd .. +done + + diff -r 0e591f806290 -r 8a34b2ebc8cc marking4/postfix_test.sh --- a/marking4/postfix_test.sh Tue Dec 03 11:07:09 2019 +0000 +++ b/marking4/postfix_test.sh Mon Jan 27 10:18:13 2020 +0000 @@ -8,12 +8,12 @@ echo -e "Below is the feedback and provisional marks for your submission" >> $out -echo -e "the preliminary part for assignment 9. Please note all marks are provisional until" >> $out +echo -e "of Preliminar 9. Please note all marks are provisional until" >> $out echo -e "ratified by the assessment board -- this is not an official" >> $out echo -e "results transcript." >> $out -echo -e "" > $out +echo -e "" >> $out -# marks for CW9 part 2 +# marks for CW9 preliminary marks=$(( 0 )) @@ -26,23 +26,25 @@ # functional tests function scala_assert { - (ulimit -t 30; JAVA_OPTS="-Xmx1g" scala -i "$1" -- "$2") #2> /dev/null 1> /dev/null) + (ulimit -t 30; JAVA_OPTS="-Xmx1g" scala -i "$1" -- "$2" 2> /dev/null 1> /dev/null) } # purity test function scala_vars { - (egrep '\bvar\b|\breturn\b|\.par|ListBuffer|mutable|new Array' "$1" 2> /dev/null 1> /dev/null) +# (egrep '\bvar\b|\breturn\b|\.par|ListBuffer|mutable|new Array' "$1" 2> /dev/null 1> /dev/null) + (egrep '\bvar\b|\breturn\b|ListBuffer|mutable|new Array' "$1" 2> /dev/null 1> /dev/null) } + # var, return, ListBuffer test # echo -e "postfix.scala does not contain vars, returns, Arrays, ListBuffers etc?" | tee -a $out if (scala_vars postfix.scala) then - echo -e " --> FAIL (make triple-sure your program conforms to the required format)\n" | tee -a $out + echo -e " --> FAIL\n" | tee -a $out tsts0=$(( 1 )) else echo -e " --> success" | tee -a $out @@ -101,7 +103,7 @@ echo -e " --> success" | tee -a $out marks=$(( marks + 1 )) else - echo " --> ONE OF THE TESTS FAILED\n" | tee -a $out + echo -e " --> ONE OF THE TESTS FAILED\n" | tee -a $out fi fi @@ -115,7 +117,7 @@ if (scala_vars postfix2.scala) then - echo -e " --> FAIL (make triple-sure your program conforms to the required format)\n" | tee -a $out + echo -e " --> FAIL\n" | tee -a $out tsts0=$(( 1 )) else echo -e " --> success" | tee -a $out @@ -125,7 +127,6 @@ # compilation test -# compilation test if [ $tsts0 -eq 0 ] then echo -e "postfix2.scala runs?" | tee -a $out @@ -151,7 +152,18 @@ echo -e " syard(split(\"5 * 7 / 2\")) == List(\"5\", \"7\", \"*\", \"2\", \"/\")" | tee -a $out echo -e " syard(split(\"3 + 4 * 8 / ( 5 - 1 ) ^ 2 ^ 3\")) == " | tee -a $out echo -e " List(\"3\", \"4\", \"8\", \"*\", \"5\", \"1\", \"-\", \"2\", \"3\", \"^\", \"^\", \"/\", \"+\")" | tee -a $out - echo -e " " | tee -a $out + + if (scala_assert "postfix2.scala" "postfix_test9.scala") + then + echo -e " --> success" | tee -a $out + marks=$(( marks + 1 )) + else + echo -e " --> ONE OF THE TESTS FAILED\n" | tee -a $out + fi +fi + +if [ $tsts1 -eq 0 ] +then echo -e " compute(syard(split(\"3 + 4 * ( 2 - 1 )\"))) == 7" | tee -a $out echo -e " compute(syard(split(\"10 + 12 * 33\"))) == 406" | tee -a $out echo -e " compute(syard(split(\"( 5 + 7 ) * 2\"))) == 24" | tee -a $out @@ -163,10 +175,10 @@ echo -e " compute(syard(split(\"( 4 ^ 3 ) ^ 2\"))) == 4096" | tee -a $out echo -e " compute(syard(split(\"( 3 + 1 ) ^ 2 ^ 3\"))) == 65536" | tee -a $out - if (scala_assert "postfix2.scala" "postfix_test9.scala") + if (scala_assert "postfix2.scala" "postfix_test10.scala") then echo -e " --> success" | tee -a $out - marks=$(( marks + 2 )) + marks=$(( marks + 1 )) else echo -e " --> ONE OF THE TESTS FAILED\n" | tee -a $out fi diff -r 0e591f806290 -r 8a34b2ebc8cc marking4/postfix_test10.scala --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/marking4/postfix_test10.scala Mon Jan 27 10:18:13 2020 +0000 @@ -0,0 +1,13 @@ +import CW9b._ + + +assert(compute(syard(split("3 + 4 * ( 2 - 1 )"))) == 7) +assert(compute(syard(split("10 + 12 * 33"))) == 406) +assert(compute(syard(split("( 5 + 7 ) * 2"))) == 24) +assert(compute(syard(split("5 + 7 / 2"))) == 8) +assert(compute(syard(split("5 * 7 / 2"))) == 17) +assert(compute(syard(split("9 + 24 / ( 7 - 3 )"))) == 15) +assert(compute(syard(split("4 ^ 3 ^ 2"))) == 262144) +assert(compute(syard(split("4 ^ ( 3 ^ 2 )"))) == 262144) +assert(compute(syard(split("( 4 ^ 3 ) ^ 2"))) == 4096) +assert(compute(syard(split("( 3 + 1 ) ^ 2 ^ 3"))) == 65536) diff -r 0e591f806290 -r 8a34b2ebc8cc marking4/postfix_test9.scala --- a/marking4/postfix_test9.scala Tue Dec 03 11:07:09 2019 +0000 +++ b/marking4/postfix_test9.scala Mon Jan 27 10:18:13 2020 +0000 @@ -7,15 +7,3 @@ assert(syard(split("5 * 7 / 2")) == List("5", "7", "*", "2", "/")) assert(syard(split("3 + 4 * 8 / ( 5 - 1 ) ^ 2 ^ 3")) == List("3", "4", "8", "*", "5", "1", "-", "2", "3", "^", "^", "/", "+")) - - -assert(compute(syard(split("3 + 4 * ( 2 - 1 )"))) == 7) -assert(compute(syard(split("10 + 12 * 33"))) == 406) -assert(compute(syard(split("( 5 + 7 ) * 2"))) == 24) -assert(compute(syard(split("5 + 7 / 2"))) == 8) -assert(compute(syard(split("5 * 7 / 2"))) == 17) -assert(compute(syard(split("9 + 24 / ( 7 - 3 )"))) == 15) -assert(compute(syard(split("4 ^ 3 ^ 2"))) == 262144) -assert(compute(syard(split("4 ^ ( 3 ^ 2 )"))) == 262144) -assert(compute(syard(split("( 4 ^ 3 ) ^ 2"))) == 4096) -assert(compute(syard(split("( 3 + 1 ) ^ 2 ^ 3"))) == 65536) diff -r 0e591f806290 -r 8a34b2ebc8cc misc/decompile --- a/misc/decompile Tue Dec 03 11:07:09 2019 +0000 +++ b/misc/decompile Mon Jan 27 10:18:13 2020 +0000 @@ -9,20 +9,37 @@ (ulimit -t 30; JAVA_OPTS="-Xmx1g" scala "$1" 2>> /dev/null 1>> /dev/null) } + +#for sd in $files; do +# cd $sd/Part7 +# echo $sd +# if (scala_compile docdiff.scala) +# then +# scalac -g:notailcalls -d docdiff-decompiled.jar docdiff.scala +# java -jar ~/pep-material/procyon-decompiler-0.5.36.jar -ln -jar docdiff-decompiled.jar -o . +# rm CW7a.java +# mv CW7a$.java $sd-CW7a.java +# else +# echo -e " --> SCALA DID NOT RUN docdiff.scala" +# fi +# cd .. +# cd .. +#done + + + for sd in $files; do - cd $sd/Part7 + cd $sd/Part9 echo $sd - if (scala_compile docdiff.scala) + if (scala_compile postfix2.scala) then - scalac -g:notailcalls -d docdiff-decompiled.jar docdiff.scala + scalac -g:notailcalls -d docdiff-decompiled.jar postfix2.scala java -jar ~/pep-material/procyon-decompiler-0.5.36.jar -ln -jar docdiff-decompiled.jar -o . - rm CW7a.java - mv CW7a$.java $sd-CW7a.java + rm CW9b.java + mv CW9b$.java $sd-CW9b.java else echo -e " --> SCALA DID NOT RUN docdiff.scala" fi cd .. cd .. done - - diff -r 0e591f806290 -r 8a34b2ebc8cc progs/lecture1.scala --- a/progs/lecture1.scala Tue Dec 03 11:07:09 2019 +0000 +++ b/progs/lecture1.scala Mon Jan 27 10:18:13 2020 +0000 @@ -425,7 +425,17 @@ // - no vars, no ++i, no += // - no mutable data-structures (no Arrays, no ListBuffers) -// But what the heck.... +// But what the heck....lets try to count to 1 Mio in parallel + +var cnt = 0 + +for(i <- (1 to 1000000).par) cnt += 1 + +println(s"Should be 1 Mio: $cnt") + + + +// Or // Q: Count how many elements are in the intersections of // two sets? // A; IMPROPER WAY (mutable counter) diff -r 0e591f806290 -r 8a34b2ebc8cc progs/lecture2.scala --- a/progs/lecture2.scala Tue Dec 03 11:07:09 2019 +0000 +++ b/progs/lecture2.scala Mon Jan 27 10:18:13 2020 +0000 @@ -505,6 +505,14 @@ combs("abc".toList, 2) +// When writing recursive functions you have to +// think about three points +// +// - How to start with a recursive function +// - How to communicate between recursive calls +// - Exit conditions + + // A Recursive Web Crawler / Email Harvester //=========================================== diff -r 0e591f806290 -r 8a34b2ebc8cc progs/lecture5.scala --- a/progs/lecture5.scala Tue Dec 03 11:07:09 2019 +0000 +++ b/progs/lecture5.scala Mon Jan 27 10:18:13 2020 +0000 @@ -2,13 +2,12 @@ //================= - // Laziness with style //===================== // The concept of lazy evaluation doesn’t really // exist in non-functional languages. C-like languages -// are strict. To see the difference, consider +// are (sort of) strict. To see the difference, consider def square(x: Int) = x * x @@ -16,12 +15,12 @@ // This is called "strict evaluation". -// In contrast, say we have a pretty expensive operation: +// On the contrary, say we have a pretty expensive operation: def peop(n: BigInt): Boolean = peop(n + 1) val a = "foo" -val b = "bar" +val b = "foo" if (a == b || peop(0)) println("true") else println("false") @@ -48,7 +47,7 @@ val primes = generatePrimes(LazyList.from(2)) // the first 10 primes -primes.take(10).toList +primes.take(100).toList time_needed(1, primes.filter(_ > 100).take(3000).toList) time_needed(1, primes.filter(_ > 100).take(3000).toList) @@ -113,14 +112,7 @@ } -def depth(r: Rexp) : Int = r match { - case ZERO => 0 - case ONE => 0 - case CHAR(_) => 0 - case ALT(r1, r2) => Math.max(depth(r1), depth(r2)) + 1 - case SEQ(r1, r2) => Math.max(depth(r1), depth(r2)) + 1 - case STAR(r1) => depth(r1) + 1 -} + //example regular expressions val digit = "0" | "1" | "2" | "3" | "4" | "5" | "6" | "7" | "8" | "9" @@ -157,7 +149,17 @@ enum(LazyList(ZERO, ONE, CHAR('a'), CHAR('b'))).take(200).force -enum(LazyList(ZERO, ONE, CHAR('a'), CHAR('b'))).take(5_000_000) +enum(LazyList(ZERO, ONE, CHAR('a'), CHAR('b'))).take(5_000_000).force + + +def depth(r: Rexp) : Int = r match { + case ZERO => 0 + case ONE => 0 + case CHAR(_) => 0 + case ALT(r1, r2) => Math.max(depth(r1), depth(r2)) + 1 + case SEQ(r1, r2) => Math.max(depth(r1), depth(r2)) + 1 + case STAR(r1) => depth(r1) + 1 +} val is = @@ -176,7 +178,7 @@ def length_string_list(lst: List[String]): Int = lst match { case Nil => 0 - case x::xs => 1 + length_string_list(xs) + case _::xs => 1 + length_string_list(xs) } def length_int_list(lst: List[Int]): Int = lst match { @@ -185,7 +187,7 @@ } length_string_list(List("1", "2", "3", "4")) -length_int_list(List(1, 2, 3, 4)) +length_string_list(List(1, 2, 3, 4)) // you can make the function parametric in type(s) @@ -193,7 +195,7 @@ case Nil => 0 case x::xs => 1 + length(xs) } -length(List("1", "2", "3", "4")) +length[String](List("1", "2", "3", "4")) length(List(1, 2, 3, 4)) @@ -220,7 +222,7 @@ case Nil => Nil case x::xs => { val res = f(x) - if (acc.contains(res)) distinctBy(xs, f, acc) + if (acc.contains(res) distinctBy(xs, f, acc) else x::distinctBy(xs, f, res::acc) } } @@ -242,7 +244,7 @@ val y = id("hey") // String val z = id(Set(1,2,3,4)) // Set[Int] - +id[+A, -B] // The type variable concept in Scala can get really complicated. // @@ -266,13 +268,13 @@ arr(0) = "Hello World" - // (Immutable) // Object Oriented Programming in Scala // // ===================================== -abstract class Animal + +abstract class Animal case class Bird(name: String) extends Animal { override def toString = name } @@ -393,8 +395,6 @@ (1 / 2) + third - - // DFAs in Scala //=============== import scala.util.Try @@ -548,11 +548,14 @@ two - one == one eight - six == two - +eight - six +// problems about equality and type-errors -List(1, 2, 3).contains("your cup") +List(1, 2, 3).contains("your cup") // should not compile, but retruns false + +List(1, 2, 3) == Vector(1, 2, 3) // again should not compile, but returns true // I like best about Scala that it lets me often write @@ -562,9 +565,9 @@ // Puzzlers -val MONTH = 12 -val DAY = 24 -val (HOUR, MINUTE, SECOND) = (12, 0, 0) +val month = 12 +val day = 24 +val (hour, min, sec) = (12, 0, 0) // use lowercase names for variable @@ -573,14 +576,14 @@ val oneTwo = Seq(1, 2, 3).permutations if (oneTwo.length > 0) { - println("Permutations of 1 and 2:") + println("Permutations of 1,2 and 3:") oneTwo.foreach(println) } val threeFour = Seq(3, 4, 5).permutations if (!threeFour.isEmpty) { - println("Permutations of 3 and 4:") + println("Permutations of 3, 4 and 5:") threeFour.foreach(println) } @@ -610,4 +613,4 @@ //================ // does not work anymore in 2.13.0 -val numbers = List("1", "2").toSet() + "3" \ No newline at end of file +val numbers = List("1", "2").toSet + "3" diff -r 0e591f806290 -r 8a34b2ebc8cc progs/mandelbrot.scala --- a/progs/mandelbrot.scala Tue Dec 03 11:07:09 2019 +0000 +++ b/progs/mandelbrot.scala Mon Jan 27 10:18:13 2020 +0000 @@ -104,8 +104,8 @@ val d_x = (end.re - start.re) / W val d_y = (end.im - start.im) / H - for (y <- (0 until H)) { - for (x <- (0 until W)) { + for (y <- (0 until H).par) { + for (x <- (0 until W).par) { val c = start + (x * d_x + y * d_y * i) diff -r 0e591f806290 -r 8a34b2ebc8cc progs/sudoku.scala --- a/progs/sudoku.scala Tue Dec 03 11:07:09 2019 +0000 +++ b/progs/sudoku.scala Mon Jan 27 10:18:13 2020 +0000 @@ -64,6 +64,10 @@ } } +def pretty(game: String): String = + "\n" + (game.sliding(maxValue, maxValue).mkString(",\n")) + + // a list of hard games according to Andrew Coles and Peter Norvig val hard_games = @@ -180,6 +184,9 @@ "....14....3....2...7..........9...3.6.1.............8.2.....1.4....5.6.....7.8...", "4.....8.5.3..........7......2.....6.....8.4......1.......6.3.7.5..2.....1.4......") +println("108:\n" ++ pretty(hard_games(108).replaceAll("\\.", " ")) ++ "\n") +println("109:\n" ++ pretty(hard_games(109).replaceAll("\\.", " ")) ++ "\n") + // for measuring time def time_needed[T](i: Int, code: => T) = { diff -r 0e591f806290 -r 8a34b2ebc8cc solutions5/bf.jar Binary file solutions5/bf.jar has changed diff -r 0e591f806290 -r 8a34b2ebc8cc solutions5/bf.scala --- a/solutions5/bf.scala Tue Dec 03 11:07:09 2019 +0000 +++ b/solutions5/bf.scala Mon Jan 27 10:18:13 2020 +0000 @@ -1,13 +1,15 @@ // Part 1 about an Interpreter for the Brainf*** language //======================================================== + object CW10a { -type Mem = Map[Int, Int] +import io.Source +import scala.util._ -import io.Source -import scala.util._ +type Mem = Map[Int, Int] + // (1) Write a function that takes a file name as argument and // and requests the corresponding file from disk. It returns the @@ -92,6 +94,7 @@ case '-' => (pc + 1, mp, write(mem, mp, sread(mem, mp) - 1)) case '.' => { print(sread(mem, mp).toChar); (pc + 1, mp, mem) } case ',' => (pc + 1, mp, write(mem, mp, Console.in.read().toByte)) + //case ',' => (pc + 1, mp, write(mem, mp, scala.io.StdIn.readByte())) case '[' => if (sread(mem, mp) == 0) (jumpRight(prog, pc + 1, 0), mp, mem) else (pc + 1, mp, mem) case ']' => @@ -173,6 +176,7 @@ >>>+[[-]++++++>>>]<<<[[<++++++++<++>>-]+<.<[>----<-]<] <<[>>>>>[>>>[-]+++++++++<[>-<-]+++++++++>[-[<->-]+[<<<]]<[>+<-]>]<<-]<<-]""") + //collatz numbers (needs a number to be typed in) run(""">,[[----------[ >>>[>>>>]+[[-]+<[->>>>++>>>>+[>>>>]++[->+<<<<<]]<<<] @@ -244,3 +248,4 @@ */ } + diff -r 0e591f806290 -r 8a34b2ebc8cc testing1/collatz_test.sh --- a/testing1/collatz_test.sh Tue Dec 03 11:07:09 2019 +0000 +++ b/testing1/collatz_test.sh Mon Jan 27 10:18:13 2020 +0000 @@ -27,7 +27,7 @@ # purity test function scala_vars { - (egrep '\bvar\b|\breturn\b|\.par|ListBuffer|mutable|new Array' "$1" 2> /dev/null 1> /dev/null) + (egrep '\bvar\b|\breturn\b|\.par|ListBuffer|collection.mutable|util.control|new Array' "$1" 2> /dev/null 1> /dev/null) } diff -r 0e591f806290 -r 8a34b2ebc8cc testing1/drumb.scala --- a/testing1/drumb.scala Tue Dec 03 11:07:09 2019 +0000 +++ b/testing1/drumb.scala Mon Jan 27 10:18:13 2020 +0000 @@ -1,7 +1,12 @@ -// Main Part about a really dumb investment strategy -//====================================================== +// Core Part 6 about a really dumb investment strategy +//===================================================== + -object CW6b { +// generate jar with +// > scala -d drumb.jar drumb.scala + + +object CW6b { //two test portfolios diff -r 0e591f806290 -r 8a34b2ebc8cc testing2/danube.scala --- a/testing2/danube.scala Tue Dec 03 11:07:09 2019 +0000 +++ b/testing2/danube.scala Mon Jan 27 10:18:13 2020 +0000 @@ -2,118 +2,114 @@ // at Danube.co.uk //=========================================== -object CW7b { - import io.Source import scala.util._ +object CW7b { // for purposes of generating a jar + // (1) Implement the function get_csv_url which takes an url-string // as argument and requests the corresponding file. The two urls // of interest are ratings_url and movies_url, which correspond // to CSV-files. -// -// The function should ReTurn the CSV-file appropriately broken +// The function should ReTurn the CSV file appropriately broken // up into lines, and the first line should be dropped (that is without -// the header of the CSV-file). The result is a list of strings (lines +// the header of the CSV file). The result is a list of strings (lines // in the file). def get_csv_url(url: String) : List[String] = { - Try(Source.fromURL(url)("UTF-8").mkString.split("\n").toList.tail).getOrElse(List()) + val csv = Source.fromURL(url)("ISO-8859-1") + csv.mkString.split("\n").toList.drop(1) } - val ratings_url = """https://nms.kcl.ac.uk/christian.urban/ratings.csv""" val movies_url = """https://nms.kcl.ac.uk/christian.urban/movies.csv""" -// testcases -//----------- -// val ratings = get_csv_url(ratings_url) -// val movies = get_csv_url(movies_url) +// test cases + +//val ratings = get_csv_url(ratings_url) +//val movies = get_csv_url(movies_url) //ratings.length // 87313 //movies.length // 9742 - - -// (2) Implement two functions that process the CSV-files from (1). The ratings +// (2) Implement two functions that process the CSV files. The ratings // function filters out all ratings below 4 and ReTurns a list of // (userID, movieID) pairs. The movies function just ReTurns a list -// of (movieID, title) pairs. +// of (movieId, title) pairs. def process_ratings(lines: List[String]) : List[(String, String)] = { - val filteredLines = lines.filter(line => line.split(",")(2).toInt >= 4) - filteredLines.map(line => (line.split(",")(0), line.split(",")(1))) + for (cols <- lines.map(_.split(",").toList); + if (cols(2).toFloat >= 4)) yield (cols(0), cols(1)) } def process_movies(lines: List[String]) : List[(String, String)] = { - lines.map(line => (line.split(",")(0), line.split(",")(1))) + for (cols <- lines.map(_.split(",").toList)) yield (cols(0), cols(1)) } +// test cases -// testcases -//----------- -// val good_ratings = process_ratings(ratings) -// val movie_names = process_movies(movies) +//val good_ratings = process_ratings(ratings) +//val movie_names = process_movies(movies) //good_ratings.length //48580 //movie_names.length // 9742 +//============================================== +// Do not change anything below, unless you want +// to submit the file for the advanced part 3! +//============================================== + + +// (3) Implement a grouping function that calulates a map +// containing the userIds and all the corresponding recommendations +// (list of movieIds). This should be implemented in a tail +// recursive fashion, using a map m as accumulator. This map +// is set to Map() at the beginning of the claculation. + +def groupById(ratings: List[(String, String)], + m: Map[String, List[String]]) : Map[String, List[String]] = ratings match { + case Nil => m + case (id, mov) :: rest => { + val old_ratings = m.getOrElse (id, Nil) + val new_ratings = m + (id -> (mov :: old_ratings)) + groupById(rest, new_ratings) + } +} + +// +//val ls = List(("1", "a"), ("2", "a"), ("1", "c"), ("2", "a"), ("1", "c")) +// +//val m = groupById(ls, Map()) +// +//m.getOrElse("1", Nil).count(_ == "c") // => 2 +//m.getOrElse("1", Nil).count(_ == "a") // => 1 + +// test cases +//val ratings_map = groupById(good_ratings, Map()) +//groupById(good_ratings, Map()).get("214") +//groupById(good_ratings, Map()).toList.minBy(_._2.length) +//val movies_map = movie_names.toMap + +//ratings_map.get("414").get.map(movies_map.get(_)) // most prolific recommender with 1227 positive ratings +//ratings_map.get("474").get.map(movies_map.get(_)) // second-most prolific recommender with 787 positive ratings +//ratings_map.get("214").get.map(movies_map.get(_)) // least prolific recommender with only 1 positive rating -// (3) Implement a grouping function that calculates a Map -// containing the userIDs and all the corresponding recommendations -// (list of movieIDs). This should be implemented in a tail -// recursive fashion, using a Map m as accumulator. This Map m -// is set to Map() at the beginning of the calculation. +//(4) Implement a function that takes a ratings map and a movie_name as argument. +// The function calculates all suggestions containing +// the movie mov in its recommendations. It ReTurns a list of all these +// recommendations (each of them is a list and needs to have mov deleted, +// otherwise it might happen we recommend the same movie). -def groupById(ratings: List[(String, String)], - m: Map[String, List[String]]) : Map[String, List[String]] = { - if (ratings.length == 0) m - else { - val firstUser = ratings(0)._1 - val userRatings = ratings.filter(r => r._1 == firstUser) - val movieIds = userRatings.map(r => r._2) - val newMap = m + (firstUser -> movieIds) - groupById(ratings.filter(r => r._1 != firstUser), newMap) - } -} - - -// testcases -//----------- -//val ratings_map = groupById(good_ratings, Map()) -//val movies_map = movie_names.toMap - -//ratings_map.get("414").get.map(movies_map.get(_)) -// => most prolific recommender with 1227 positive ratings - -//ratings_map.get("474").get.map(movies_map.get(_)) -// => second-most prolific recommender with 787 positive ratings - -//ratings_map.get("214").get.map(movies_map.get(_)) -// => least prolific recommender with only 1 positive rating +def favourites(m: Map[String, List[String]], mov: String) : List[List[String]] = + (for (id <- m.keys.toList; + if m(id).contains(mov)) yield m(id).filter(_ != mov)) -// (4) Implement a function that takes a ratings map and a movie_name as argument. -// The function calculates all suggestions containing -// the movie in its recommendations. It ReTurns a list of all these -// recommendations (each of them is a list and needs to have the movie deleted, -// otherwise it might happen we recommend the same movie). - - -def favourites(m: Map[String, List[String]], mov: String) : List[List[String]] = { - val movieLists = m.map(r => r._2).toList.filter(_.contains(mov)) - for (movieList <- movieLists) yield { - movieList.filter(_!=mov) - } -} - - -// testcases -//----------- +// test cases // movie ID "912" -> Casablanca (1942) // "858" -> Godfather // "260" -> Star Wars: Episode IV - A New Hope (1977) @@ -125,53 +121,45 @@ // 52 a good rating to movies 260, 318, 593. +// (5) Implement a suggestions function which takes a rating +// map and a movie_name as arguments. It calculates all the recommended +// movies sorted according to the most frequently suggested movie(s) first. -// (5) Implement a suggestions function which takes a rating -// map and a movie_name as arguments. It calculates all the recommended -// movies sorted according to the most frequently suggested movie(s) first. - +// needed in Scala 2.13. + +def mapValues[S, T, R](m: Map[S, T], f: T => R) = + m.map { case (x, y) => (x, f(y)) } def suggestions(recs: Map[String, List[String]], - mov_name: String) : List[String] = { - val favs = favourites(recs, mov_name).flatten - favs.map(x => (x, favs.count(_==x))) - .sortBy(_._1) - .reverse - .sortBy(_._2) - .reverse - .distinct - .map(_._1) + mov_name: String) : List[String] = { + val favs = favourites(recs, mov_name).flatten + val favs_counted = mapValues(favs.groupBy(identity), (v:List[String]) => v.size).toList + val favs_sorted = favs_counted.sortBy(_._2).reverse + favs_sorted.map(_._1) } +// check +// groupMap is equivalent to groupBy(key).mapValues(_.map(f)) -// testcases -//----------- +// test cases //suggestions(ratings_map, "912") //suggestions(ratings_map, "912").length // => 4110 suggestions with List(858, 260, 318, 593, ...) // being the most frequently suggested movies - - -// (6) Implement a recommendations function which generates at most -// *two* of the most frequently suggested movies. It ReTurns the -// actual movie names, not the movieIDs. - +// (6) Implement recommendations functions which generates at most +// *two* of the most frequently suggested movies. It Returns the +// actual movie names, not the movieIDs. def recommendations(recs: Map[String, List[String]], - movs: Map[String, String], - mov_name: String) : List[String] = { - val sug = suggestions(recs, mov_name) - val toptwo = sug.take(2) - if (toptwo.length == 0) Nil - else toptwo.map(movs(_)) -} - + movs: Map[String, String], + mov_name: String) : List[String] = + suggestions(recs, mov_name).take(2).map(movs.get(_).get) // testcases -//----------- + // recommendations(ratings_map, movies_map, "912") // => List(Godfather, Star Wars: Episode IV - A NewHope (1977)) @@ -189,11 +177,11 @@ // => List(Shawshank Redemption, Forrest Gump (1994)) // recommendations(ratings_map, movies_map, "4") -// => Nil (there are three ratings for this movie in ratings.csv but they are not positive) +// => Nil (there are three ratings fro this movie in ratings.csv but they are not positive) -// If you want to calculate the recommendations for all movies, -// then use this code (it will take a few seconds calculation time). +// If you want to calculate the recomendations for all movies. +// Will take a few seconds calculation time. //val all = for (name <- movie_names.map(_._1)) yield { // recommendations(ratings_map, movies_map, name) @@ -205,32 +193,4 @@ //List(1,2).take(2) //List(1,2,3).take(2) - - } - -// val ratings_url = """https://nms.kcl.ac.uk/christian.urban/ratings.csv""" -// val movies_url = """https://nms.kcl.ac.uk/christian.urban/movies.csv""" - -// val ratings = CW7b.get_csv_url(ratings_url) -// val movies = CW7b.get_csv_url(movies_url) - -// println(movies.length) -// val good_ratings = CW7b.process_ratings(ratings) -// val movie_names = CW7b.process_movies(movies) - -// val ratings_map = CW7b.groupById(good_ratings, Map()) -// val movies_map = movie_names.toMap - - - -//println(CW7b.recommendations(ratings_map, movies_map, "912")) -/* -val ratings_url = """https://nms.kcl.ac.uk/christian.urban/ratings.csv""" - -val ratings = CW7b.get_csv_url(ratings_url) - -val good_ratings = CW7b.process_ratings(ratings) -val ratings_map = CW7b.groupById(good_ratings, Map()) - -println(CW7b.suggestions(ratings_map, "912").length)*/ diff -r 0e591f806290 -r 8a34b2ebc8cc testing3/knight_test.sh --- a/testing3/knight_test.sh Tue Dec 03 11:07:09 2019 +0000 +++ b/testing3/knight_test.sh Mon Jan 27 10:18:13 2020 +0000 @@ -230,7 +230,7 @@ if [ $tsts1 -eq 0 ] then echo -e "For testing needs to take 10 seconds or less to execute: " >> $out - echo -e " first_closed_tour_heuristic(6, List((3,3))) found and correct?" >> $out + echo -e " first_closed_tour_heuristics(6, List((3,3))) found and correct?" >> $out if (scala_assert_quick "knight2.scala" "knight_test7.scala") then @@ -245,8 +245,8 @@ if [ $tsts1 -eq 0 ] then echo -e "For testing needs to take 10 seconds or less to execute: " >> $out - echo -e " first_tour_heuristic(8, List((0,0))) found and correct?" >> $out - echo -e " first_tour_heuristic(30, List((0,0))) found and correct?" >> $out + echo -e " first_tour_heuristics(8, List((0,0))) found and correct?" >> $out + echo -e " first_tour_heuristics(30, List((0,0))) found and correct?" >> $out if (scala_assert_quick "knight2.scala" "knight_test8.scala") then @@ -298,7 +298,7 @@ echo -e "For testing needs to take 10 seconds or less to execute: " >> $out echo -e " tour_on_mega_board(70, List((0,0))) found and correct?" >> $out - if (scala_assert_quick "knight3.scala" "knight_test9.scala") + if (scala_assert_slow "knight3.scala" "knight_test9.scala") then echo -e " --> success" >> $out else diff -r 0e591f806290 -r 8a34b2ebc8cc testing3/knight_test7.scala --- a/testing3/knight_test7.scala Tue Dec 03 11:07:09 2019 +0000 +++ b/testing3/knight_test7.scala Mon Jan 27 10:18:13 2020 +0000 @@ -27,6 +27,6 @@ correct_urban(6)(p) && moves_urban(p.head).contains(p.last) -val tsc = first_closed_tour_heuristic(6, List((3, 3))).get +val tsc = first_closed_tour_heuristics(6, List((3, 3))).get assert(correct_closed_urban(6)(tsc) == true) diff -r 0e591f806290 -r 8a34b2ebc8cc testing3/knight_test8.scala --- a/testing3/knight_test8.scala Tue Dec 03 11:07:09 2019 +0000 +++ b/testing3/knight_test8.scala Mon Jan 27 10:18:13 2020 +0000 @@ -25,9 +25,9 @@ } -val ts8 = first_tour_heuristic(8, List((0,0))).get +val ts8 = first_tour_heuristics(8, List((0,0))).get assert(correct_urban(8)(ts8) == true) -val ts30 = first_tour_heuristic(30, List((0,0))).get +val ts30 = first_tour_heuristics(30, List((0,0))).get assert(correct_urban(30)(ts30) == true) diff -r 0e591f806290 -r 8a34b2ebc8cc testing4/re.scala --- a/testing4/re.scala Tue Dec 03 11:07:09 2019 +0000 +++ b/testing4/re.scala Mon Jan 27 10:18:13 2020 +0000 @@ -8,16 +8,16 @@ case object ZERO extends Rexp case object ONE extends Rexp case class CHAR(c: Char) extends Rexp -case class ALT(r1: Rexp, r2: Rexp) extends Rexp -case class SEQ(r1: Rexp, r2: Rexp) extends Rexp -case class STAR(r: Rexp) extends Rexp +case class ALT(r1: Rexp, r2: Rexp) extends Rexp // alternative +case class SEQ(r1: Rexp, r2: Rexp) extends Rexp // sequence +case class STAR(r: Rexp) extends Rexp // star -// some convenience for typing in regular expressions + +// some convenience for typing regular expressions import scala.language.implicitConversions import scala.language.reflectiveCalls - def charlist2rexp(s: List[Char]): Rexp = s match { case Nil => ONE case c::Nil => CHAR(c) @@ -39,117 +39,137 @@ def ~ (r: String) = SEQ(s, r) } -// (1) Complete the function nullable according to +// (5) Complete the function nullable according to // the definition given in the coursework; this // function checks whether a regular expression // can match the empty string and Returns a boolean // accordingly. -def nullable (r: Rexp) : Boolean = r match { - case ZERO => false - case ONE => true - case CHAR(_) => false - case ALT(r1, r2) => nullable(r1) || nullable(r2) - case SEQ(r1, r2) => nullable(r1) && nullable(r2) - case STAR(_) => true +def nullable (r: Rexp) : Boolean = { + r match { + case ZERO => false + case ONE => true + case CHAR(c) => false + case ALT(r1, r2) => (nullable(r1) || nullable(r2)) + case SEQ(r1, r2) => (nullable(r1) && nullable(r2)) + case STAR(r) => true + } } -// (2) Complete the function der according to +// (6) Complete the function der according to // the definition given in the coursework; this // function calculates the derivative of a // regular expression w.r.t. a character. -def der (c: Char, r: Rexp) : Rexp = r match { - case ZERO => ZERO - case ONE => ZERO - case CHAR(d) => if (c == d) ONE else ZERO - case ALT(r1, r2) => ALT(der(c, r1), der(c, r2)) - case SEQ(r1, r2) => - if (nullable(r1)) ALT(SEQ(der(c, r1), r2), der(c, r2)) - else SEQ(der(c, r1), r2) - case STAR(r1) => SEQ(der(c, r1), STAR(r1)) +def der (c: Char, r: Rexp) : Rexp = { + r match { + case ZERO => ZERO + case ONE => ZERO + case CHAR(d) => if(d == c) ONE else ZERO + case ALT(r1, r2) => ALT(der(c, r1), der(c, r2)) + case SEQ(r1, r2) => if(nullable(r1)) { + (ALT(SEQ(der(c, r1), r2), der(c, r2))) + } else { + SEQ(der(c, r1), r2) + } + case STAR(r) => SEQ(der(c, r), STAR(r)) + } } -// (3) Complete the simp function according to + +// (7) Complete the simp function according to // the specification given in the coursework; this // function simplifies a regular expression from // the inside out, like you would simplify arithmetic // expressions; however it does not simplify inside // STAR-regular expressions. -def simp(r: Rexp) : Rexp = r match { - case ALT(r1, r2) => (simp(r1), simp(r2)) match { - case (ZERO, r2s) => r2s - case (r1s, ZERO) => r1s - case (r1s, r2s) => if (r1s == r2s) r1s else ALT (r1s, r2s) - } - case SEQ(r1, r2) => (simp(r1), simp(r2)) match { - case (ZERO, _) => ZERO - case (_, ZERO) => ZERO - case (ONE, r2s) => r2s - case (r1s, ONE) => r1s - case (r1s, r2s) => SEQ(r1s, r2s) - } - case r => r +def simp(r: Rexp) : Rexp = { + r match { + case STAR(r) => STAR(r) // does not process r star + case SEQ(r1, r2) => { + val x = (simp(r1), simp(r2)) + if(x._1 == ZERO) ZERO else + if(x._2 == ZERO) ZERO else + if(x._1 == ONE) simp(x._2) else + if(x._2 == ONE) simp(x._1) else + if(x._1 == x._2) simp(x._2) else + SEQ(simp(x._1), simp(x._2)) + } + case ALT(r1, r2) => { + val x = (simp(r1), simp(r2)) + if(x._1 == ZERO) simp(x._2) else + if(x._2 == ZERO) simp(x._1) else + if(x._1 == x._2) simp(x._2) else + ALT(simp(x._1), simp(x._2)) + } + case r => r // if single regex, return it + } } -// (4) Complete the two functions below; the first +// (8) Complete the two functions below; the first // calculates the derivative w.r.t. a string; the second // is the regular expression matcher taking a regular // expression and a string and checks whether the -// string matches the regular expression. +// string matches the regular expression -def ders (s: List[Char], r: Rexp) : Rexp = s match { - case Nil => r - case c::s => ders(s, simp(der(c, r))) +def ders (s: List[Char], r: Rexp) : Rexp = { + s match { + case Nil => r + case c :: cs => ders(cs, simp(der(c,r))) + } } -// main matcher function -def matcher(r: Rexp, s: String) = nullable(ders(s.toList, r)) +def matcher(r: Rexp, s: String): Boolean = { + val listOfCharacters = s.toList + val result = ders(listOfCharacters, r) + nullable(result) +} -// (5) Complete the size function for regular + +// (9) Complete the size function for regular // expressions according to the specification // given in the coursework. - -def size(r: Rexp): Int = r match { - case ZERO => 1 - case ONE => 1 - case CHAR(_) => 1 - case ALT(r1, r2) => 1 + size(r1) + size (r2) - case SEQ(r1, r2) => 1 + size(r1) + size (r2) - case STAR(r1) => 1 + size(r1) +def size(r: Rexp): Int = { + r match { + case ZERO => 1 + case ONE => 1 + case CHAR(c) => 1 + case ALT(r1, r2) => 1 + size(r1) + size(r2) + case SEQ(r1, r2) => 1 + size(r1) + size(r2) + case STAR(r) => 1 + size(r) + } } - - // some testing data -//matcher(("a" ~ "b") ~ "c", "abc") // => true -//matcher(("a" ~ "b") ~ "c", "ab") // => false +/* +matcher(("a" ~ "b") ~ "c", "abc") // => true +matcher(("a" ~ "b") ~ "c", "ab") // => false // the supposedly 'evil' regular expression (a*)* b -val EVIL = SEQ(STAR(STAR(CHAR('a'))), CHAR('b')) +// val EVIL = SEQ(STAR(STAR(CHAR('a'))), CHAR('b')) -//matcher(EVIL, "a" * 1000 ++ "b") // => true -//matcher(EVIL, "a" * 1000) // => false +matcher(EVIL, "a" * 1000 ++ "b") // => true +matcher(EVIL, "a" * 1000) // => false // size without simplifications -//size(der('a', der('a', EVIL))) // => 28 -//size(der('a', der('a', der('a', EVIL)))) // => 58 +size(der('a', der('a', EVIL))) // => 28 +size(der('a', der('a', der('a', EVIL)))) // => 58 // size with simplification -//size(simp(der('a', der('a', EVIL)))) // => 8 -//size(simp(der('a', der('a', der('a', EVIL))))) // => 8 +size(simp(der('a', der('a', EVIL)))) // => 8 +size(simp(der('a', der('a', der('a', EVIL))))) // => 8 // Python needs around 30 seconds for matching 28 a's with EVIL. // Java 9 and later increase this to an "astonishing" 40000 a's in -// around 30 seconds. +// 30 seconds. // -// Lets see how long it takes to match strings with -// 5 Million a's...it should be in the range of a -// couple of seconds. +// Lets see how long it really takes to match strings with +// 5 Million a's...it should be in the range of a couple +// of seconds. def time_needed[T](i: Int, code: => T) = { val start = System.nanoTime() @@ -158,19 +178,19 @@ (end - start)/(i * 1.0e9) } -//for (i <- 0 to 5000000 by 500000) { -// println(i + " " + "%.5f".format(time_needed(2, matcher(EVIL, "a" * i))) + " secs.") -//} +for (i <- 0 to 5000000 by 500000) { + println(i + " " + "%.5f".format(time_needed(2, matcher(EVIL, "a" * i)))) +} // another "power" test case -//simp(Iterator.iterate(ONE:Rexp)(r => SEQ(r, ONE | ONE)).drop(100).next) == ONE +simp(Iterator.iterate(ONE:Rexp)(r => SEQ(r, ONE | ONE)).drop(50).next) == ONE // the Iterator produces the rexp // // SEQ(SEQ(SEQ(..., ONE | ONE) , ONE | ONE), ONE | ONE) // -// where SEQ is nested 100 times. - +// where SEQ is nested 50 times. +*/ } diff -r 0e591f806290 -r 8a34b2ebc8cc testing4/re_test.sh --- a/testing4/re_test.sh Tue Dec 03 11:07:09 2019 +0000 +++ b/testing4/re_test.sh Mon Jan 27 10:18:13 2020 +0000 @@ -107,9 +107,12 @@ echo -e " simp(ZERO | ONE) == ONE" >> $out echo -e " simp(STAR(ZERO | ONE)) == STAR(ZERO | ONE)" >> $out echo -e " simp(ONE ~ (ONE ~ (ONE ~ CHAR('a')))) == CHAR('a')" >> $out + echo -e " simp(((ONE ~ ONE) ~ ONE) ~ CHAR('a')) == CHAR('a'))" >> $out + echo -e " simp(((ONE | ONE) ~ ONE) ~ CHAR('a')) == CHAR('a'))" >> $out echo -e " simp(ONE ~ (ONE ~ (ONE ~ ZERO))) == ZERO" >> $out echo -e " simp(ALT(ONE ~ (ONE ~ (ONE ~ ZERO)), CHAR('a'))) == CHAR('a')" >> $out echo -e " simp(CHAR('a') | CHAR('a')) == CHAR('a')" >> $out + echo -e " simp(CHAR('a') ~ CHAR('a')) == CHAR('a') ~ CHAR('a')" >> $out echo -e " simp(ONE | CHAR('a')) == (ONE | CHAR('a'))" >> $out echo -e " simp(ALT((CHAR('a') | ZERO) ~ ONE," >> $out echo -e " ((ONE | CHAR('b')) | CHAR('c')) ~ (CHAR('d') ~ ZERO))) == CHAR('a')" >> $out diff -r 0e591f806290 -r 8a34b2ebc8cc testing5/bf_test4.scala --- a/testing5/bf_test4.scala Tue Dec 03 11:07:09 2019 +0000 +++ b/testing5/bf_test4.scala Mon Jan 27 10:18:13 2020 +0000 @@ -3,7 +3,7 @@ assert(run("[-]", Map(0 -> 100)) == Map(0 -> 0)) assert(run("[->+<]", Map(0 -> 10)) == Map(0 -> 0, 1 -> 10)) assert(run("[>>+>>+<<<<-]", Map(0 -> 42)) == Map(0 -> 0, 2 -> 42, 4 -> 42)) -val hw_urban = """+++++[->++++++++++<]>--<+++[->>++++++++++ - <<]>>++<<----------[+>.>.<+<]""" -assert(run(hw_urban) == Map(0 -> 0, 1 -> 58, 2 -> 32)) +//val hw_urban = """+++++[->++++++++++<]>--<+++[->>++++++++++ +// <<]>>++<<----------[+>.>.<+<]""" +//assert(run(hw_urban) == Map(0 -> 0, 1 -> 58, 2 -> 32))