├── .gitattributes ├── .gitignore ├── .merlin ├── 3110 Final Project Writeup.pdf ├── LICENSE.txt ├── Makefile ├── README.md ├── VERSION ├── _tags ├── comparison.ml ├── comparison.mli ├── dictionary.ml ├── dictionary.mli ├── language_files ├── c_info.json ├── cpp_info.json ├── java_info.json ├── ocaml_info.json ├── python_info.json └── txt_info.json ├── main.ml ├── main.mli ├── preprocessing.ml ├── preprocessing.mli ├── test.ml ├── test_comparison.ml ├── test_dictionary.ml ├── test_preprocessing.ml ├── test_winnow.ml ├── tests ├── MiniFactorialTests │ ├── Original.java │ ├── T1-Commented.java │ ├── T1-Copy.java │ ├── T1-Whitespaces.java │ ├── T2-Renamed.java │ ├── T2-VariableLong.java │ ├── T3-DummyMethod.java │ ├── T3-DummyMethodPlus.java │ ├── T3-EndlessLoop.java │ ├── T3-ForWhile.java │ ├── T3-Inlining.java │ ├── T3-JumpLabel.java │ ├── T3-LoopEndpoint.java │ ├── T3-LoopUnrolling.java │ ├── T3-OutputStream.java │ ├── T3-VariableBigInt.java │ ├── T4-AlgorithmChange.java │ ├── T4-Approximation.java │ ├── T4-ProGuardObfuscation.java │ └── T4-Recursive.java ├── SSID_demo │ ├── 01.java │ ├── 02.java │ ├── 03.java │ ├── 04.java │ ├── 05.java │ ├── 06.java │ ├── 07.java │ ├── 08.java │ ├── 09.java │ └── 10.java ├── test1 │ ├── intset.ml │ └── intset1.ml ├── test10 │ ├── add.ml │ ├── add_test.ml │ ├── btrees.ml │ ├── discussiongame.ml │ ├── hello.ml │ └── lab03_test.ml ├── test11 │ ├── Camel.txt │ ├── CamelMaybeCopy.txt │ ├── Camelcopy.txt │ ├── Camelcopy2.txt │ ├── Camelcopy3.txt │ └── Camels.txt ├── test12 │ ├── DumbAI.java │ └── DumbAI2.java ├── test13 │ ├── heaplib.c │ └── heaplib2.c ├── test14 │ ├── P2.py │ └── P2_2.py ├── test15 │ ├── all_subarray.cpp │ └── all_subarray_2.cpp ├── test2 │ ├── main.ml │ └── main1.ml ├── test3 │ ├── labsoln.ml │ └── labsoln1.ml ├── test4 │ ├── functions.ml │ └── functions1.ml ├── test5 │ ├── queens_lazy.ml │ └── queens_tail.ml ├── test6 │ ├── kmp.ml │ └── strpos.ml ├── test7 │ ├── strpos.ml │ └── strpos2.ml ├── test8 │ ├── lab03.ml │ ├── lab031.ml │ ├── lab032.ml │ ├── lab033.ml │ └── lab034.ml └── test9 │ ├── prelimpract.ml │ ├── prelimpract1.ml │ └── prelimpract2.ml ├── winnowing.ml └── winnowing.mli /.gitattributes: -------------------------------------------------------------------------------- 1 | tests/* linguist-generated 2 | language_files/* linguist-generated -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | .DS_Store 2 | tests/.DS_Store 3 | _build/ 4 | ocamoss -------------------------------------------------------------------------------- /.merlin: -------------------------------------------------------------------------------- 1 | PKG oUnit 2 | PKG yojson 3 | PKG ANSITerminal 4 | B _build -------------------------------------------------------------------------------- /3110 Final Project Writeup.pdf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/RobYang1024/OCaMOSS/5a78137bf717d2bb8248489f0619a01ebea9d1df/3110 Final Project Writeup.pdf -------------------------------------------------------------------------------- /LICENSE.txt: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2018 Aniroodh Ravikumar, Danny Yang, Robert Yang, Gauri Jain 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. -------------------------------------------------------------------------------- /Makefile: -------------------------------------------------------------------------------- 1 | build: 2 | ocamlbuild -use-ocamlfind main.native && mv main.native ocamoss 3 | 4 | test: 5 | ocamlbuild -use-ocamlfind test.native && ./test.native 6 | 7 | clean: 8 | ocamlbuild -clean 9 | 10 | run: 11 | ocamlbuild -use-ocamlfind main.native && mv main.native ocamoss && ./ocamoss -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | ## OCaMoss User's Guide 2 | 3 | Plagiarism detection software, inspired by MOSS and implemented in OCaml. 4 | Runs using a command-line interface. 5 | 6 | This is NOT an OCaml client for MOSS, this is a completely separate program. For more details about the system or how MOSS works in general, read the PDF report in this repository or [this blog post](https://yangdanny97.github.io/blog/2019/05/03/MOSS) I wrote. 7 | 8 | Note: this was originally written as the final project for a course - it has since been updated by me, so some aspects of the PDF report may not be accurate. In particular, the latest version of OCaMOSS no longer uses a 2-3 tree. 9 | 10 |
11 | 12 | - To build - `make` 13 | - To build & run the REPL - `make run` 14 | - To build & run unit tests -`make test` 15 | 16 | Required Dependencies: 17 | - Yojson 18 | - ANSITerminal 19 | - OUnit (for unit tests) 20 | 21 |
22 | 23 | ### Commands: 24 | (note - commands are case-sensitive) 25 | 26 | - `run [threshold]` - runs OCaMoss on the working directory. 27 | The threshold argument gives the program the percentage of the file to match with 28 | another for it to be flagged as plagiarised, and must be at least 0.4 and at most 1 29 | - `dir` - lists the working directory and the files that it contains 30 | - `setdir [dir]` - sets the relative directory to look for files and resets any 31 | results 32 | - `results` - lists the file names for which there are results 33 | - `results [filename]` - lists the detailed results of overlap for that file 34 | (Make sure to include the extension of the file) 35 | - `resultpairs` -- lists all the pairs of files for which there are positive results 36 | - `compare [fileA] [fileB]` - prints out specific overlaps of fileA and fileB 37 | (Make sure to include the extension of the files) 38 | - `quit` - exits the REPL 39 | - `help` - display the available commands 40 | 41 |
42 | 43 | ### Usage instructions/tutorial: 44 | 45 | 1. `setdir` to folder you want to test. requirements: file names have no spaces 46 | and all files have the same extension 47 | (example: `setdir tests/test1`) 48 | 2. `run` with desired params (example: `run 0.5` is the same as `run`) 49 | 3. `results` to view list of results, [results filename] to view list of 50 | results for specific file, and [`compare A B` to compare matching patterns for 51 | two files (example: `results Camel.txt`) 52 | 53 | Example for runnning test case 1 and inspecting results: 54 | 1. `setdir tests/test1` 55 | 2. `run` 56 | 3. `results/results intset.ml/compare intset1.ml intset.ml/resultpairs` 57 | 58 |
59 | 60 | ### Other information: 61 | 62 | #### Similarity score: 63 | - used as a measure of how likely file A plagiarized from file B 64 | - ratio of # matching hashes between A and B : # hashes in fingerprint for A 65 | - overall similarity score for A is the average of all similarity scores 66 | for file A that are > 0.5 67 | - threshold score for detecting possible plagiarism varies with the file type, but experimentally we determined it to be around 0.5 68 | 69 | #### Supported languages/file formats: 70 | - OCaml - .ml 71 | - Java - .java 72 | - C - .c 73 | - Python - .py 74 | - English - .txt (note: english comparison does NOT account for semantics) 75 | 76 |
77 | 78 | Self-generated test case descriptions (test case N is in directory tests/testN): 79 | 80 | NOTE: to replicate results, run using threshold = 0.4 81 | 82 | 1) exact duplicates - should return positive result 83 | 2) variable names changed - should return positive result 84 | 3) functions/comments reordered - should return positive result 85 | 4) functions1.ml is a copy of functions.ml but with large sections deleted - should return positive result for functions1 but not functions 86 | 5) different implementations of the same algorithm - should NOT return positive 87 | result 88 | 6) completely different files - should NOT return positive result 89 | 7) functions/comments reordered - should return positive result 90 | 8) more than 2 files - files changed respectively as follows: function/variable names changed; random spaces/new lines added; rec declarations/ match statement lines changed - should return positive result for all files except for lab034.ml which is a dummy. 91 | 9) more than 2 files - files changed respectively as follows: same comments but different code; comments deleted and same code with variable/function names changed - should NOT return positive result for first and should return positive result for second 92 | 10) large group of all different files - should NOT return positive result 93 | 11) txt files check - files are changed respectively as follows: exact wikipedia article; edited but very similar wikipedia article; sentences shifted around of original; exact same; a file that says “camel” five times; a more hazy edit of the original - should return positive result for all except last two: “Camels.txt” and “CamelMaybeCopy.txt” 94 | 12) Java check - test for a Java file, where one file has all comments removed 95 | 13) C check - test for a C file where one file has all comments removed 96 | 14) Python check - test for a Python file, where one files has comments removed and variable names changed. 97 | -------------------------------------------------------------------------------- /VERSION: -------------------------------------------------------------------------------- 1 | This is version 1, released 02/09/18. -------------------------------------------------------------------------------- /_tags: -------------------------------------------------------------------------------- 1 | true: package(unix), package(oUnit), package(yojson), package(ANSITerminal) 2 | -------------------------------------------------------------------------------- /comparison.ml: -------------------------------------------------------------------------------- 1 | open Dictionary 2 | 3 | module StringKey = struct 4 | type t = string 5 | let compare k1 k2 = Stdlib.compare k1 k2 6 | end 7 | 8 | module HashValue = struct 9 | type t = (int*int) list 10 | let format d = () 11 | end 12 | 13 | module FileDict = HashtblDict (StringKey)(HashValue) 14 | 15 | module DictValue = struct 16 | type t = FileDict.t 17 | let format d = () 18 | end 19 | 20 | module CompDict = HashtblDict (StringKey)(DictValue) 21 | 22 | let intersection v1 v2 = 23 | let rec intersection_helper lst1 lst2 common = 24 | match lst1 with 25 | | [] -> common 26 | | (h,p)::t -> 27 | let acc = if List.mem_assoc h lst2 then (h,p)::common 28 | else common in 29 | intersection_helper t lst2 acc 30 | 31 | in 32 | List.rev(intersection_helper v1 v2 []) 33 | 34 | let make_pair_comp k0 file_list = 35 | List.fold_left (fun x (k,v) -> 36 | FileDict.insert k (intersection (List.assoc k0 file_list) v) x) 37 | FileDict.empty file_list 38 | 39 | let compare d = 40 | let file_list = FileDict.to_list d in 41 | List.fold_left (fun x (k,v) -> 42 | CompDict.insert k (make_pair_comp k file_list) x) 43 | CompDict.empty file_list 44 | 45 | let cmp_tuple (k1,s1) (k2,s2) = 46 | if Stdlib.compare s1 s2 = 0 then Stdlib.compare k1 k2 47 | else -(Stdlib.compare s1 s2) 48 | 49 | let create_sim_list comp_dict t = 50 | let create_sim_list_helper comp_dict = 51 | List.fold_left (fun x (k,d) -> match FileDict.find k d with 52 | | None -> failwith "Unimplemented" 53 | | Some v -> let file_length = float_of_int (List.length v) in 54 | let file_ss = 55 | List.fold_left (fun (score,n) (k1,v1) -> 56 | if StringKey.compare k k1 = 0 then (score,n) 57 | else begin 58 | if file_length = 0.0 then (score,n) 59 | else 60 | let s = ((float_of_int (List.length v1))/.file_length) in 61 | if s >= t then (score+.s,n+.1.0) else (score,n) 62 | end) (0.0,0.0) (FileDict.to_list d) 63 | in 64 | let sim_score = if (snd file_ss) = 0.0 then 0.0 65 | else (fst file_ss)/.(snd file_ss) in 66 | if sim_score >= t then (k,sim_score)::x else x) 67 | [] (CompDict.to_list comp_dict) 68 | in 69 | List.sort (cmp_tuple) (create_sim_list_helper comp_dict) 70 | 71 | let create_pair_sim_list f_name f_dict_list = 72 | try 73 | if f_dict_list = [] then [] else 74 | let f_length = float_of_int (List.length (List.assoc f_name f_dict_list)) in 75 | List.fold_left (fun lst (k,v) -> 76 | if k = f_name then lst 77 | else if f_length = 0.0 then (k,0.0)::lst 78 | else begin 79 | (k,(float_of_int(List.length v))/.f_length)::lst 80 | end) [] f_dict_list 81 | with 82 | | Division_by_zero -> failwith "Invalid file dictionary" 83 | -------------------------------------------------------------------------------- /comparison.mli: -------------------------------------------------------------------------------- 1 | open Dictionary 2 | 3 | (* [StringKey] is a module that represents a key of a dictionary of type 4 | * string. *) 5 | module StringKey : Comparable with type t = string 6 | 7 | (* [HashValue] is a module that represents a value of a dictionary of type 8 | * int list. 9 | *) 10 | module HashValue : Formattable with type t = (int*int) list 11 | 12 | (* [FileDict] is a module that represents a dictionary with keys of type string 13 | * and values of type int list. 14 | *) 15 | module FileDict : Dictionary with type Key.t = string 16 | and type Value.t = (int*int) list 17 | 18 | (* [DictValue] is a module that represents a value of a dictionary of type 19 | * FileDict.t 20 | *) 21 | module DictValue : Formattable with type t = FileDict.t 22 | 23 | (* [CompDict] is a module that represents a dictionary with keys of type string 24 | * and values of type FileDict.t 25 | *) 26 | module CompDict: Dictionary with type Key.t = string 27 | and type Value.t = FileDict.t 28 | 29 | (* [intersection v1 v2] returns a list of elements present in both v1 and 30 | * v2. The elements are in the order that they appear in v1, and the positions 31 | * are as they are in the corresponding values in v1. 32 | *) 33 | val intersection : HashValue.t -> HashValue.t -> HashValue.t 34 | 35 | (* [make_pair_comp k0 file_list comp_dict] returns a file dictionary where the 36 | * keys are the keys from file_list, and each value is the intersection of 37 | * the values in file_list of the key mapped to that value, and the key k0. 38 | *) 39 | val make_pair_comp : string -> (StringKey.t * HashValue.t) list -> FileDict.t 40 | 41 | (* [compare d] returns a comparison dictionary whose keys are the keys 42 | * from d, and whose values are dictionaries representing pairwise comparisons 43 | * of that key with every other key in d. 44 | *) 45 | val compare : FileDict.t -> CompDict.t 46 | 47 | (* [create_sim_list threshold comp_dict] assigns a similarity score to each of 48 | * the keys in comp_dict, and returns a list of files whose similarity scores 49 | * are above threshold, and their overall similarity score. The similarity of 50 | * one file with another is calculated as the number of matching hashes between 51 | * the files divided by the number of hashes of the file itself, and hence the 52 | * similarity score of a file is the average of the similarities of that 53 | * file with every other file. The files are ordered in decreasing order of 54 | * similarity, and files that have the same similarity score are ordered by 55 | * increasing order of filename. 56 | *) 57 | val create_sim_list : CompDict.t -> float -> (StringKey.t * float) list 58 | 59 | (* [create_pair_sim_list f_name f_dict_list] returns a list of files and 60 | * their corresponding pair similarity scores when compared with f_name. 61 | * requires: The value in f_dict_list corresponding to f_name cannot be 62 | * an empty list, unless f_dict_list itself is an empty list. *) 63 | val create_pair_sim_list : StringKey.t -> (StringKey.t * HashValue.t) list -> 64 | (StringKey.t * float) list 65 | -------------------------------------------------------------------------------- /dictionary.ml: -------------------------------------------------------------------------------- 1 | open Hashtbl 2 | open Seq 3 | 4 | module type Comparable = sig 5 | type t 6 | val compare: t -> t -> int 7 | end 8 | 9 | module type Formattable = sig 10 | type t 11 | val format: t -> unit 12 | end 13 | 14 | module type Dictionary = sig 15 | module Key : Comparable 16 | module Value : Formattable 17 | type key = Key.t 18 | type value = Value.t 19 | type t 20 | val empty : t 21 | val size : t -> int 22 | val member : key -> t -> bool 23 | val find : key -> t -> value option 24 | val insert : key -> value -> t -> t 25 | val to_list : t -> (key * value) list 26 | end 27 | 28 | module type DictionaryMaker = 29 | functor (K : Comparable) (V : Formattable) 30 | -> Dictionary with module Key = K and module Value = V 31 | 32 | module HashtblDict (K : Comparable) (V : Formattable) = struct 33 | 34 | module Key = K 35 | 36 | module Value = V 37 | 38 | type key = Key.t 39 | 40 | type value = Value.t 41 | 42 | type t = Tbl of (key, value) Hashtbl.t 43 | 44 | let empty = Tbl(Hashtbl.create 10000) 45 | 46 | let size (Tbl d) = Hashtbl.length d 47 | 48 | let member k (Tbl d) = 49 | match Hashtbl.find_opt d k with 50 | |Some _ -> true 51 | |None -> false 52 | 53 | let find k (Tbl d) = Hashtbl.find_opt d k 54 | 55 | let insert k v (Tbl d) = 56 | let cpy = (Hashtbl.copy d) in 57 | Hashtbl.add cpy k v ; Tbl(cpy) 58 | 59 | let to_list (Tbl d) = 60 | Hashtbl.fold (fun k v acc -> (k, v) :: acc) d [] 61 | end 62 | -------------------------------------------------------------------------------- /dictionary.mli: -------------------------------------------------------------------------------- 1 | 2 | (* A [Comparable] is a value that can be compared. *) 3 | module type Comparable = sig 4 | 5 | (* Type t gives the type of the value that is stored in the comparable. *) 6 | type t 7 | 8 | (* [compare t1 t2] returns a positive number if t1 is greater than t2, 9 | * a negative number if it is less than t2 and 0 if they are equal. 10 | *) 11 | val compare: t -> t -> int 12 | 13 | end 14 | 15 | 16 | module type Formattable = sig 17 | 18 | type t 19 | 20 | val format: t -> unit 21 | 22 | end 23 | 24 | (* A [Dictionary] maps keys to values. The keys 25 | * must be comparable, but there are no restrictions 26 | * on the values. 27 | *) 28 | 29 | module type Dictionary = sig 30 | 31 | module Key : Comparable 32 | 33 | module Value : Formattable 34 | 35 | type key = Key.t 36 | 37 | type value = Value.t 38 | 39 | (* Type t represents how the dictionary itself is implemented and stored as. 40 | *) 41 | type t 42 | 43 | (* [empty] represents an empty dictionary. *) 44 | val empty : t 45 | 46 | (* [size d] represents the size of the dictionary d. *) 47 | val size : t -> int 48 | 49 | (* [member k dict] returns true if k is a binding in the dictionary d 50 | * and false if not. 51 | *) 52 | val member : key -> t -> bool 53 | 54 | (* [find k dict] returns None if k is not a binding in dict, and Some v 55 | * if v is the value bound to k in dict. 56 | *) 57 | val find : key -> t -> value option 58 | 59 | (* [insert k v dict] adds a new binding of k with value v to dict if k is not 60 | * in dict already, and binds k to a new value v if it is already 61 | * present in the dictionary, and returns the new dictionary. 62 | *) 63 | val insert : key -> value -> t -> t 64 | 65 | (* [to_list dict] returns an association list where each element of the list 66 | * is a tuple of a key and it's corresponding value in dict. *) 67 | val to_list : t -> (key * value) list 68 | 69 | end 70 | 71 | module type DictionaryMaker = 72 | functor (K : Comparable) 73 | -> functor (V : Formattable) 74 | -> Dictionary with module Key = K and module Value = V 75 | 76 | module HashtblDict : DictionaryMaker 77 | -------------------------------------------------------------------------------- /language_files/c_info.json: -------------------------------------------------------------------------------- 1 | { 2 | "keywords": ["auto", "double", "int", "struct", "break", "else", "long", "switch", 3 | "case", "enum", "register", "typedef", "char", "extern", "return", "union", 4 | "const","float", "short", "unsigned", "continue", "for", "signed", "void", 5 | "default", "goto", "sizeof", "volatile", "do", "if", "static", "while","ctype", 6 | "errno","h","limits","locale","math","setjmp","stdarg","stddef","stdio","stdlib","size_t", "wchar_t", 7 | "div_t", "ldiv_t", "assert", "isalnum","isalpha","iscntrl","isdigit", "toupper", 8 | "isgraph","islower","isprint","ispunct","isspace","isupper","isxdigit", "tolower", 9 | "CHAR_BIT","SCHAR_MIN","SCHAR_MAX","UCHAR_MAX","CHAR_MIN","CHAR_MAX","MB_LEN_MAX", 10 | "SHRT_MIN","SHRT_MAX","USHRT_MAX","INT_MIN","INT_MAX","UINT_MAX","LONG_MIN","LONG_MAX","ULONG_MAX", 11 | "acos","asin","atan","atan2","ceil","cos","cosh","exp","fabs","floor","fmod","frexp", 12 | "ldexp","log","log10","modf","pow","sin","sinh","sqrt","tanh","raise","signal","sig_atomic_t", 13 | "SIG_DFL","SIG_ERR","SIG_IGN","va_list","va_start","va_arg","va_end","NULL","offsetof", 14 | "ptrdiff_t","_IOLBF","_IOFBF","BUFSIZ","EOF","FILE","FILENAME_MAX","FOPEN_MAX","fpos_t", 15 | "L_tmpnam","TMP_MAX","_IONBF","SEEK_CUR","stderr","stdin","stdout","SEEK_END", 16 | "SEEK_SET","fgets","gets","fopen","freopen","tmpfile","fclose","feof", 17 | "ferror","fflush","fgetc","fgetpos","fprintf","fputc","fputs","fscanf","fseek", 18 | "fsetpos","getc","getchar","printf","putc","putchar","puts","remove","rename","scanf", 19 | "setvbuf","sprintf","sscanf","ungetc","vfprintf","vprintf","vsprintf","int","fread", 20 | "fwrite","clearerr","perror","rewind","setbuf","memchr","strcat","strchr","strcpy","strerror", 21 | "strncat","strncpy","strpbrk","strrchr","strstr","strtok","memcmp","strcmp","strcoll", 22 | "strncmp","strcspn","strlen","strspn","strxfrm","memcpy","memmove","memset","clock_t","time_t", 23 | "asctime","ctime","clock","difftime","strftime","tm","mktime","time", "EXIT_FAILURE", 24 | "EXIT_SUCCESS", "RAND_MAX","MB_CUR_MAX","atof","getenv","div","strtod","abs","atexit","atoi", 25 | "mblen","mbtowc","rand","wctomb","ldiv","mbstowcs","wcstombs","system", 26 | "bsearch","calloc","malloc","realloc","abort","exit","free","qsort","srand","include"], 27 | "special characters": ["(", ")", "[", "]", "{", "}", "*", ",", ":", "=", ";", 28 | ".", "#", "-", "~", "!", "&", "+", "-", "/", "&", "<", ">", "|" , "%" , "^"], 29 | "comment-start" : "/*", 30 | "comment-end" : "*/", 31 | "comment" : "//", 32 | "comments-nest": false, 33 | "strings":true 34 | } -------------------------------------------------------------------------------- /language_files/cpp_info.json: -------------------------------------------------------------------------------- 1 | { 2 | "keywords": ["BUFSIZ", "CHAR_BIT", "CHAR_MAX", "CHAR_MIN", "EOF", "EXIT_FAILURE", "EXIT_SUCCESS", 3 | "FALSE", "FILE", "FILENAME_MAX", "FOPEN_MAX", "INT_MAX", "INT_MIN", "LONG_MAX", "LONG_MIN", 4 | "L_tmpnam", "MB_CUR_MAX", "MB_LEN_MAX", "NULL", "RAND_MAX", "SCHAR_MAX", "SCHAR_MIN", "SEEK_CUR", 5 | "SEEK_END", "SEEK_SET", "SHRT_MAX", "SHRT_MIN", "SIG_DFL", "SIG_ERR", "SIG_IGN", "TMP_MAX", 6 | "TRUE", "UCHAR_MAX", "UINT_MAX", "ULONG_MAX", "USHRT_MAX", "_IOFBF", "_IOLBF", "_IONBF", 7 | "abort", "abs", "acos", "alignas", "alignof", "and", "and_eq", "asctime", "asin", "asm", 8 | "assert", "atan", "atan2", "atexit", "atof", "atoi", "atomic_cancel", "atomic_commit", 9 | "atomic_noexcept", "auto", "bitand", "bitor", "bool", "break", "bsearch", "calloc", "case", 10 | "catch", "ceil", "char", "char16_t", "char32_t", "class", "clearerr", "clock", "clock_t", 11 | "co_await", "co_return", "co_yield", "compl", "concept", "const", "const_cast", "constexpr", 12 | "continue", "cos", "cosh", "ctime", "ctype", "decltype", "default", "delete", "difftime", "div", 13 | "div_t", "do", "double", "dynamic_cast", "else", "enum", "errno", "exit", "exp", "explicit", 14 | "export", "extern", "fabs", "fclose", "feof", "ferror", "fflush", "fgetc", "fgetpos", "fgets", 15 | "float", "floor", "fmod", "fopen", "for", "fpos_t", "fprintf", "fputc", "fputs", "fread", 16 | "free", "freopen", "frexp", "friend", "fscanf", "fseek", "fsetpos", "fwrite", "getc", "getchar", 17 | "getenv", "gets", "goto", "h", "if", "import", "include", "inline", "int", "isalnum", "isalpha", 18 | "iscntrl", "isdigit", "isgraph", "islower", "isprint", "ispunct", "isspace", "isupper", "isxdigit", 19 | "ldexp", "ldiv", "ldiv_t", "limits", "locale", "log", "log10", "long", "malloc", "math", "mblen", 20 | "mbstowcs", "mbtowc", "memchr", "memcmp", "memcpy", "memmove", "memset", "mktime", "modf", "module", 21 | "mutable", "namespace", "new", "noexcept", "not", "not_eq", "nullptr", "offsetof", "operator", 22 | "or", "or_eq", "perror", "pow", "printf", "private", "protected", "ptrdiff_t", "public", "putc", 23 | "putchar", "puts", "qsort", "raise", "rand", "realloc", "register", "reinterpret_cast", "remove", 24 | "rename", "requires", "return", "rewind", "scanf", "setbuf", "setjmp", "setvbuf", "short", 25 | "sig_atomic_t", "signal", "signed", "sin", "sinh", "size_t", "sizeof", "sprintf", "sqrt", 26 | "srand", "sscanf", "static", "static_assert", "static_cast", "stdarg", "stddef", "stderr", 27 | "stdin", "stdio", "stdlib", "stdout", "strcat", "strchr", "strcmp", "strcoll", "strcpy", 28 | "strcspn", "strerror", "strftime", "strlen", "strncat", "strncmp", "strncpy", "strpbrk", 29 | "strrchr", "strspn", "strstr", "strtod", "strtok", "struct", "strxfrm", "switch", "synchronized", 30 | "system", "tanh", "template", "this", "thread_local", "throw", "time", "time_t", "tm", "tmpfile", 31 | "tolower", "toupper", "try", "typedef", "typeid", "typename", "ungetc", "union", "unsigned", 32 | "using", "va_arg", "va_end", "va_list", "va_start", "vfprintf", "virtual", "void", "volatile", 33 | "vprintf", "vsprintf", "wchar_t", "wcstombs", "wctomb", "while", "xor", "xor_eq"], 34 | "special characters": ["(", ")", "[", "]", "{", "}", "*", ",", ":", "=", ";", 35 | ".", "#", "-", "~", "!", "&", "+", "-", "/", "&", "<", ">", "|" , "%" , "^"], 36 | "comment-start" : "/*", 37 | "comment-end" : "*/", 38 | "comment" : "//", 39 | "comments-nest": false, 40 | "strings":true 41 | } -------------------------------------------------------------------------------- /language_files/java_info.json: -------------------------------------------------------------------------------- 1 | { 2 | "keywords": ["abstract", "continue", "for", "new", "switch", "assert", "default", "package", 3 | "synchronized", "boolean", "do", "if", "private", "this", "break", "double", "implements", 4 | "protected", "throw", "byte", "else", "import", "public", "throws", "case", "enum", 5 | "instanceof", "return", "transient", "catch", "extends", "int", "short", "try", "char", "final", 6 | "interface", "static", "void", "class", "finally", "long", "strictfp", "volatile", 7 | "float", "native", "super", "while", "Boolean", "Byte", "Character", "Class", "ClassLoader", 8 | "ClassValue", "Compiler", "Double", "Enum", "Float", "InheritableThreadLocal", "Integer ", 9 | "Long", "Math", "Number", "Object", "Package", "Process", "ProcessBuilder", "Runtime", 10 | "RuntimePermission", "SecurityManager", "Short", "StackTraceElement", "StrictMath", "String", 11 | "StringBuffer", "StringBuilder", "System", "Thread", "ThreadGroup", "ThreadLocal", 12 | "Throwable", "Void", "AbstractCollection", "AbstractList", "AbstractMap", "AbstractQueue", 13 | "AbstractSequentialList", "AbstractSet", "ArrayDeque", "ArrayList", "Arrays", "BitSet", 14 | "Calendar", "Collections", "Currency", "Date", "Dictionary", "EnumMap", "EnumSet", 15 | "EventListenerProxy", "EventObject", "FormattableFlags", "Formatter", "GregorianCalendar", 16 | "HashMap","HashSet", "Hashtable", "IdentityHashMap", "LinkedHashMap", "LinkedHashSet", "LinkedList", 17 | "ListResourceBundle", "Locale", "Objects", "Observable", "PriorityQueue", "Properties", 18 | "PropertyPermission", "PropertyResourceBundle", "Random", "ResourceBundle", 19 | "ResourceBundle.Control", "Scanner", "ServiceLoader", "SimpleTimeZone", "Stack", 20 | "StringTokenizer", "Timer", "TimerTask", "TimeZone", "TreeMap", "TreeSet", "UUID", 21 | "Vector", "WeakHashMap"], 22 | "special characters": ["!", "$", "%", "&", "*", "+", "-", ".", "/", ":", ";", 23 | "<", "=", ">", "?", "^", "|", "\"", "'", "(", ")", ",", "[", "]", 24 | "{", "}", "~", "@"], 25 | "comment-start" : "/*", 26 | "comment-end" : "*/", 27 | "comment": "//", 28 | "comments-nest": false, 29 | "strings":true 30 | } 31 | -------------------------------------------------------------------------------- /language_files/ocaml_info.json: -------------------------------------------------------------------------------- 1 | { 2 | "keywords": ["and", "as", "assert", "asr", "begin", "class", "constraint", 3 | "do", "done", "downto", "else", "end", "exception", "external", 4 | "false", "for", "fun", "function", "functor", "if", "in", "include", 5 | "inherit", "initializer", "land", "lazy", "let", "lor", "lsl", "lsr", 6 | "lxor", "match", "method", "mod", "module", "mutable", "new", "nonrec", 7 | "object", "of", "open", "or", "private", "rec", "sig", "struct", "then", 8 | "to", "true", "try", "type", "val", "virtual", "when", "while", "with", 9 | "Arg", "Array", "ArrayLabels", "Buffer", "Bytes", "BytesLabels", "Callback", 10 | "Char", "Complex", "Digest", "Ephemeron", "Filename", "Format", "Gc", 11 | "Genlex", "Hashtbl", "Int32", "Int64", "Lazy", "Lexing", "List", 12 | "ListLabels", "Map", "Marshal", "MoreLabels", "Nativeint", "Oo", "Parsing", 13 | "Printexc", "Printf", "Queue", "Random", "Scanf", "Set", "Sort", 14 | "Spacetime", "Stack", "StdLabels", "Stream", "String", "StringLabels", 15 | "Sys", "Uchar", "Weak", "failwith"], 16 | "special characters": ["!", "$", "%", "&", "*", "+", "-", ".", "/", ":", ";", 17 | "<", "=", ">", "?", "@", "^", "|", "~", "#", "\"", "(", ")", ",", "[", "]", 18 | "{", "}"], 19 | "comment-start": "(*", 20 | "comment-end": "*)", 21 | "comment": "", 22 | "comments-nest": true, 23 | "strings":true 24 | } 25 | -------------------------------------------------------------------------------- /language_files/python_info.json: -------------------------------------------------------------------------------- 1 | { 2 | "keywords": ["False", "None", "True", "and", "as", "assert", "break", "class", "continue", 3 | "def", "del", "elif", "else", "except", "finally", "for", "from", "global", "if", "import", 4 | "in", "is", "lambda", "nonlocal", "not", "or", "pass", "raise", "return", "try", 5 | "while", "with", "yield","__future__","__main__","abc","aifc","argparse","array","ast", 6 | "asynchat","asyncore","atexit","audioop","base64","bdb","binascii","binhex","bisect", 7 | "builtins","bz2","calendar","cgi","cgitb","chunk","cmath","cmd","code","codecs","codeop", 8 | "collections","colorsys","compileall","configparser","contextlib","copy","copyreg","crypt", 9 | "csv","ctypes","curses","datetime","dbm","decimal","difflib","dis","distutils","doctest", 10 | "email","errno","faulthandler","fcntl","filecmp","fileinput","fnmatch","formatter","fpectl", 11 | "fractions","ftplib","functools","gc","getopt","getpass","gettext","glob","grp","gzip", 12 | "hashlib","heapq","hmac","html","http","imaplib","imghdr","imp","importlib","inspect","io", 13 | "ipaddress","itertools","json","keyword","linecache","locale","logging","lzma","macpath", 14 | "mailbox","mailcap","marshal","math","mimetypes","mmap","modulefinder","msilib","msvcrt", 15 | "multiprocessing","netrc","nis","nntplib","numbers","operator","optparse","os","os.path", 16 | "ossaudiodev","parser","pdb","pickle","pickletools","pipes","pkgutil","platform","plistlib", 17 | "poplib","posix","pprint","pty","pwd","py_compile","pyclbr","pydoc","queue","quopri", 18 | "random","re","readline","reprlib","resource","rlcompleter","runpy","sched","select","shelve","shlex", 19 | "shutil","signal","site","smtpd","smtplib","sndhdr","socket","socketserver","spwd","sqlite3","ssl", 20 | "stat","string","stringprep","struct","subprocess","sunau","symbol","symtable","sys","sysconfig","syslog", 21 | "tabnanny","tarfile","telnetlib","tempfile","termios","test","test","textwrap","threading","time", 22 | "timeit","tkinter","token","tokenize","trace","traceback","tty","turtle","types","unicodedata", 23 | "unittest","urllib","uu","uuid","venv","warnings","wave","weakref","webbrowser","winreg", 24 | "winsound","wsgiref","xdrlib","xml","xmlrpc","zipfile","zipimport","zlib"], 25 | "special characters": ["!", "%", "&", "*", "+", "-", ".", "/", ":", ";", 26 | "<", "=", ">", "?", "^", "|", "~", "\"", "(", ")", ",", "[", "]", "{", "}", "'"], 27 | "comment-start": "'''", 28 | "comment-end": "'''", 29 | "comment": "#", 30 | "comments-nest": false, 31 | "strings":false 32 | } 33 | -------------------------------------------------------------------------------- /language_files/txt_info.json: -------------------------------------------------------------------------------- 1 | { 2 | "keywords": [], 3 | "special characters": [], 4 | "comment-start":"", 5 | "comment-end":"", 6 | "comment":"", 7 | "comments-nest": false, 8 | "strings":false 9 | } 10 | -------------------------------------------------------------------------------- /main.mli: -------------------------------------------------------------------------------- 1 | open Preprocessing 2 | open Comparison 3 | 4 | type color = RED | GREEN | CYAN | TEXT 5 | 6 | (* type representing the state of the interface *) 7 | type state = {display: (color * string) list; directory: string; results: 8 | CompDict.t option; result_files: (color * string) list; 9 | threshold: float} 10 | 11 | (* type for commands recognised by MOSS 12 | * RUN - runs MOSS on the current directory of the state, no arguments 13 | * HELP - lists the available commands, no arguments 14 | * SETDIR - sets the working directory where MOSS looks for files, takes 15 | * 1 argument, displays the working directory 16 | * DIR - displays the working directory and all the files it contains 17 | * RESULTS - displays results, takes 0 arguments 18 | * (lists files that are contained in results, and their similarity scores) 19 | * or 1 argument (lists similarity scores for that file vs other files) 20 | * COMPARE - compares two files, printing out the similar sections, takes 2 21 | * arguments 22 | *) 23 | type cmd = RUN of string | DIR | HELP | SETDIR of string 24 | | RESULTS of string | PAIR | COMPARE of (string*string)| ERROR 25 | 26 | (* this is printed every time the user enters the help command *) 27 | val help: string 28 | 29 | (* represents the initial state of OCaMoss when it starts: 30 | * displays a welcome message and a list of commands 31 | * default params of k=35 w=40 32 | * no results loaded and no working directory preset *) 33 | val newstate: state 34 | 35 | (* parses the string of a user into specific commands for MOSS *) 36 | val parse: string -> cmd 37 | 38 | (* [repl st] the REPL for entering commands to MOSS, 39 | * side effects: prints the string in the display field in [st] and 40 | * some progress indicators when running and displaying results 41 | * expected behavior for commands: 42 | * 43 | * [run] 44 | * - runs MOSS on the current directory of the state 45 | * - displays an error message if current directory is not set, 46 | * if files are invalid file type, or if not all files have same extn 47 | * - displays list of files that are likely to be plagiarized 48 | * - two optional params for w and k, with the following conditions: 49 | * w is in range [20,100], k is in range [15,40], k < w 50 | * - if only one param is provided, if params are invalid an error 51 | * message will be displayed 52 | * 53 | * [help] 54 | * - lists the available commands, takes no arguments 55 | * 56 | * [setdir] 57 | * - sets the working directory where MOSS looks for files, takes 58 | * 1 argument, the directory path relative to the folder main.ml is in 59 | * - displays the files in the new directory 60 | * - displays error message if directory is incorrect 61 | * 62 | * [dir] 63 | * - displays the working directory and all the files it contains 64 | * 65 | * [results] 66 | * if 0 arguments: 67 | * - displays all files that have results, and their overall similarity scores 68 | * if 1 argument (name of a file: 69 | * - if valid file name of a file with results, displays the similarity score 70 | * of that file compared to all other files in results 71 | * - if there are no results to display, an error message will be shown 72 | * 73 | * [compare] 74 | * - if results exist, and both arguments are valid file names with results, 75 | * a side by side printout of the matching patterns in the fingerprints of 76 | * files will be displayed 77 | * - otherwise, an error message will be displayed 78 | * 79 | * [quit] 80 | * - exits the repl 81 | * 82 | * invalid commands will display an error message 83 | *) 84 | val repl : state -> unit 85 | -------------------------------------------------------------------------------- /preprocessing.ml: -------------------------------------------------------------------------------- 1 | open Winnowing 2 | open Unix 3 | open Filename 4 | open Yojson.Basic.Util 5 | 6 | type comment_info = { 7 | single_comment: string; 8 | multi_comment_start: string; 9 | multi_comment_end: string; 10 | nest: bool; 11 | strings: bool; 12 | } 13 | 14 | type language_info = { 15 | keywords: string list; 16 | special_chars: char list; 17 | comment_info: comment_info; 18 | } 19 | 20 | let get_language_info language_file = 21 | let path_to_language_file = 22 | String.concat "/" ["language_files"; language_file] in 23 | let json = Yojson.Basic.from_file path_to_language_file in 24 | let keywords_list = json |> member "keywords" 25 | |> to_list |> List.map to_string in 26 | let special_chars = json |> member "special characters" 27 | |> to_list |> List.map to_string 28 | |> List.map (fun str -> String.get str 0) in 29 | let one_line_comm_st = json |> member "comment" |> to_string in 30 | let mult_line_comm_st = json |> member "comment-start" |> to_string in 31 | let mult_line_comm_end = json |> member "comment-end" |> to_string in 32 | let comments_nest = json |> member "comments-nest" |> to_bool in 33 | let rm_string = json |> member "strings" |> to_bool in 34 | let comment_info = { 35 | single_comment = one_line_comm_st; 36 | multi_comment_start = mult_line_comm_st; 37 | multi_comment_end = mult_line_comm_end; 38 | nest = comments_nest; 39 | strings = rm_string 40 | } in 41 | { 42 | keywords = keywords_list; 43 | special_chars = special_chars; 44 | comment_info = comment_info; 45 | } 46 | 47 | let keywords l = l.keywords 48 | let special_chars l = l.special_chars 49 | let comment_info l = l.comment_info 50 | 51 | (* [rem_white_space code_string] returns a string list representing the strings 52 | * in [code_string] separated by tabs, newlines, carriage returns, and spaces, 53 | * with empty strings filtered out of said list. 54 | * 55 | * example: [rem_white_space " Hello World " = ["Hello"; "World"]] 56 | *) 57 | let rem_white_space code_string = 58 | code_string |> 59 | String.split_on_char '\t' |> String.concat " " |> 60 | String.split_on_char '\n' |> String.concat " " |> 61 | String.split_on_char '\r' |> String.concat " " |> 62 | String.split_on_char ' ' |> 63 | List.filter (fun str -> str <> "") 64 | 65 | (* [split_and_keep_on_spec_chars spec_chars str] essentially does the same 66 | * thing as [String.split_on_char] for each character in [spec_char], except 67 | * each of the characters in [spec_char] are themselves an element in the 68 | * resulting list. 69 | * 70 | * example: 71 | * [split_and_keep_on_spec_chars [!;?] "Hello!World?" = 72 | * ["Hello"; "!"; "World"; "?"]] 73 | *) 74 | let split_and_keep_on_spec_chars spec_chars str = 75 | let rec str_to_chr_arr str = 76 | let tail_len = String.length str - 1 in 77 | match str with 78 | | "" -> [] 79 | | str -> (String.get str 0)::(str_to_chr_arr (String.sub str 1 tail_len)) 80 | in 81 | let char_array = str_to_chr_arr str in 82 | (List.fold_left 83 | (fun acc_arr chr -> 84 | let str_of_chr = String.make 1 chr in 85 | if List.mem chr spec_chars then 86 | List.cons "" (List.cons str_of_chr acc_arr) 87 | else 88 | match acc_arr with 89 | | h::t -> (String.concat "" [h;str_of_chr])::t 90 | | [] -> failwith "Array should never be empty") 91 | [""] 92 | char_array) |> List.filter (fun str -> str <> "") |> List.rev 93 | 94 | (* [split_on_str str_to_split_on acc_str_arr str_to_split] splits up 95 | * [str_to_split] on every instance of [str_to_split_on] when 96 | * [acc_str_arr] = []. [acc_str_arr] acts as an accumulator array that stores 97 | * the accumulating string array as splitting is being done. 98 | * 99 | * example: 100 | * [split_on_str "Hello" [] "HelloWorldHelloWorldHello" = 101 | * ["Hello"; "World"; "Hello"; "World"; "Hello"] 102 | *) 103 | let rec split_on_str str_to_split_on acc_str_arr str_to_split = 104 | let str_to_split_on_len = String.length str_to_split_on in 105 | let str_to_split_len = String.length str_to_split in 106 | let new_acc_arr_else_case acc_str_arr str_to_split_on str_to_add = 107 | match acc_str_arr with 108 | | [] -> [str_to_add] 109 | | h::t -> 110 | if h = str_to_split_on then str_to_add::acc_str_arr 111 | else 112 | let new_acc_arr_hd = String.concat "" [h; str_to_add] in 113 | new_acc_arr_hd::t 114 | in 115 | if String.length str_to_split = 0 then List.rev acc_str_arr 116 | else 117 | try 118 | if str_to_split_on = (String.sub str_to_split 0 str_to_split_on_len) then 119 | let head_str = str_to_split_on in 120 | let tail_len = str_to_split_len - str_to_split_on_len in 121 | let tail_str = String.sub str_to_split str_to_split_on_len tail_len in 122 | split_on_str str_to_split_on (head_str::acc_str_arr)tail_str 123 | else 124 | let head_str = String.sub str_to_split 0 1 in 125 | let tail_len = str_to_split_len - 1 in 126 | let tail_str = String.sub str_to_split 1 tail_len in 127 | let new_acc_arr = 128 | new_acc_arr_else_case acc_str_arr str_to_split_on head_str in 129 | split_on_str str_to_split_on new_acc_arr tail_str 130 | with Invalid_argument _ -> 131 | let new_acc_arr = 132 | new_acc_arr_else_case acc_str_arr str_to_split_on str_to_split in 133 | List.rev new_acc_arr 134 | 135 | (* [remove_strings code_str], when treating [code_str] as a block of code, 136 | * removes all instances of strings in code_str. 137 | * 138 | * example: [remove_strings "let str = \"Hello\"" = "let str = "] 139 | *) 140 | let remove_strings code_str = 141 | let code_str = String.split_on_char '\'' code_str |> String.concat "\"" in 142 | let filter_from_arr (acc_arr, start) str = 143 | if str = "\"" && start = false then 144 | (" "::acc_arr, true) 145 | else if str = "\"" then 146 | (" "::acc_arr, false) 147 | else 148 | if start then (" s "::acc_arr, start) 149 | else (" "::str::acc_arr, false) 150 | in 151 | let split_on_strings_arr = split_on_str "\"" [] code_str in 152 | let acc_tup = 153 | List.fold_left filter_from_arr ([], false) split_on_strings_arr in 154 | match acc_tup with 155 | | (acc_arr, _) -> List.rev acc_arr 156 | 157 | (* [remove_comments comment_start comment_end comments_nest code_str], where 158 | * - [comment_start] is a string that indicates the start of a comment. 159 | * - [comment_end] is a string that indicates the end of a comment. 160 | * - [comments_nest] is a bool that indicates whether or not comments nest in 161 | * the language that [code_str] is written in. 162 | * - and [code_str] is the string representation of code whose comments are to 163 | * be removed. 164 | * returns [code_str] but with all of its comments removed. 165 | *) 166 | let remove_comments 167 | comment_start comment_end comments_nest code_str = 168 | let do_filter_from_arr (acc_arr, nesting) str = 169 | if str = comment_start then 170 | if comments_nest then (" "::acc_arr, nesting + 1) 171 | else (" "::acc_arr, 1) 172 | else if str = comment_end then 173 | if comments_nest then (" "::acc_arr, nesting - 1) 174 | else (" "::acc_arr, 0) 175 | else 176 | if nesting > 0 then (acc_arr, nesting) 177 | else (" "::str::acc_arr, 0) 178 | in 179 | let split_on_comments_arr = 180 | split_on_str comment_start [] code_str |> 181 | List.map (split_on_str comment_end []) |> List.flatten 182 | in 183 | let acc_tup = 184 | List.fold_left do_filter_from_arr ([], 0) split_on_comments_arr in 185 | match acc_tup with 186 | | (acc_arr, _) -> List.rev acc_arr 187 | 188 | (* [replace_generics keywords spec_chars str_arr] goes through the list, and 189 | * replaces any string that 190 | * - isn't a keyword 191 | * - isn't the string representation of a special character 192 | * - isn't the string representation of an int 193 | * with the letter "v". All relevant keywords and special characters are found 194 | * in [keywords] and [spec_chars], respectively. 195 | * 196 | * example: [ 197 | * replace_generics 198 | * ["if"; "then"; "else"] 199 | * ['['; ']'] 200 | * ["if"; "some_bool"; "then"; "["; "]"; "else"; "["; "one_element"; "]"] = 201 | * ["if"; "v"; "then"; "["; "]"; "else"; "["; "v"; "]"] 202 | * ] 203 | *) 204 | let replace_generics keywords spec_chars str_arr = 205 | List.map 206 | (fun str -> 207 | if List.mem str keywords || 208 | ((String.length str = 1) && (List.mem (String.get str 0) spec_chars)) 209 | then str 210 | else 211 | try 212 | int_of_string str |> string_of_int 213 | with Failure _ -> "v" ) 214 | str_arr 215 | 216 | (* Refer to preprocessing.mli for this function's specifications *) 217 | let remove_noise comment_info code_string keywords spec_chars is_txt = 218 | if is_txt then code_string 219 | else 220 | let rm_one_line_comment s = 221 | if comment_info.single_comment = "" then s 222 | else 223 | remove_comments comment_info.single_comment "\n" false s 224 | |> String.concat "" 225 | in 226 | let rm_mult_line_comment s = 227 | if comment_info.multi_comment_start = "" then s 228 | else 229 | remove_comments comment_info.multi_comment_start comment_info.multi_comment_end comment_info.nest s 230 | |> String.concat "" 231 | in 232 | let rm_strings s = 233 | if comment_info.strings then remove_strings s |> String.concat "" 234 | else s 235 | in 236 | rm_strings code_string |> rm_mult_line_comment |> rm_one_line_comment |> 237 | split_and_keep_on_spec_chars spec_chars |> 238 | List.map rem_white_space |> List.flatten |> 239 | replace_generics keywords spec_chars |> 240 | String.concat "" 241 | 242 | (* Refer to preprocessing.mli for this function's specifications *) 243 | let k_grams s k = 244 | let rec k_grams_helper acc s n = 245 | try 246 | let n_sub_str = String.sub s 0 n in 247 | let tail_str = String.sub s 1 ((String.length s)-1) in 248 | k_grams_helper (n_sub_str::acc) tail_str n 249 | with Invalid_argument _ -> List.rev acc 250 | in 251 | k_grams_helper [] s k 252 | 253 | (* [determine_language_file f] returns the string that represents the name of 254 | * of the json file that contains all relevant information about the language 255 | * that the code in the file named [f] is written in. 256 | *) 257 | let determine_language_file f = 258 | if check_suffix f "txt" then "txt_info.json" 259 | else if check_suffix f "ml" then "ocaml_info.json" 260 | else if check_suffix f "mli" then "ocaml_info.json" 261 | else if check_suffix f "c" then "c_info.json" 262 | else if check_suffix f "cpp" then "cpp_info.json" 263 | else if check_suffix f "java" then "java_info.json" 264 | else if check_suffix f "py" then "python_info.json" 265 | else failwith "This file format is not supported" 266 | 267 | let get_ngrams f n = 268 | let rec hash_helper f_channel s = 269 | try 270 | let line = input_line f_channel in 271 | hash_helper f_channel (s^line^"\n") 272 | with 273 | | End_of_file -> s in 274 | let language_file = determine_language_file f in 275 | let language_info = get_language_info language_file in 276 | let keywords = language_info.keywords in 277 | let spec_chars = language_info.special_chars in 278 | let f_string = hash_helper (open_in f) language_file in 279 | let is_txt = check_suffix f "txt" in 280 | let com_info = language_info.comment_info in 281 | let noise_removed_str = 282 | remove_noise com_info f_string keywords spec_chars is_txt in 283 | k_grams noise_removed_str n 284 | 285 | (* Refer to preprocessing.mli for this function's specifications *) 286 | let hash_file f = 287 | let n_grams = get_ngrams f 35 in 288 | List.map (Hashtbl.hash) n_grams 289 | 290 | (* Refer to preprocessing.mli for this function's specifications *) 291 | let rec get_file_positions dir dir_name filename positions = 292 | try 293 | let f_name = Unix.readdir dir in 294 | if f_name <> filename then get_file_positions dir dir_name filename 295 | positions 296 | else begin 297 | let f = dir_name ^ Filename.dir_sep ^ f_name in 298 | let n_grams = get_ngrams f 35 in 299 | let results = List.map (fun x -> 300 | (string_of_int x, List.nth n_grams (x - 1)) 301 | ) positions in 302 | List.sort (fun a b -> 303 | Stdlib.compare (snd a |> Hashtbl.hash) (snd b |> Hashtbl.hash) 304 | ) results 305 | end 306 | with 307 | | _ -> [] 308 | -------------------------------------------------------------------------------- /preprocessing.mli: -------------------------------------------------------------------------------- 1 | open Winnowing 2 | open Unix 3 | 4 | type comment_info = { 5 | single_comment: string; 6 | multi_comment_start: string; 7 | multi_comment_end: string; 8 | nest: bool; 9 | strings: bool; 10 | } 11 | 12 | type language_info = { 13 | keywords: string list; 14 | special_chars: char list; 15 | comment_info: comment_info; 16 | } 17 | 18 | (* [get_language_info language_file] gets the language info from a particular language JSON file and returns it as a record 19 | * requires: language_file is well-formatted JSON with the necessary fields 20 | *) 21 | val get_language_info : string -> language_info 22 | 23 | (* [remove_noise c_i_q code_str keywords spec_chars comments_nest remove_strings], 24 | * where 25 | * - [c_i_q] represents a comment_info record 26 | * - [code_str] is the string representation of the code whose noise is to be 27 | * removed. 28 | * - [keywords] represents a list of keywords in the language that [code_str] is 29 | * written in that are to be kept upon noise removal, and not replaced by a 30 | * generic character. 31 | * - [spec_chars] represents a list of special characters in the language that 32 | * [code_str] is written in that are to be kept upon noise removal, and not 33 | * replaced by a generic character. 34 | * - [comments_nest] is a bool that indicates whether or not multi-line 35 | * comments nest in the language. 36 | * - and [remove_strings] is a bool that indicates whether or not strings are to 37 | * be removed from files of this language 38 | * is a function that takes outputs a "noise removed" version of [code_str], 39 | * where noise removal in this case indicates removing all instances of white 40 | * space, strings (if set to be removed), and comments, and replacing all 41 | * programmer defined variable/class/interface/module/type/function/method etc., 42 | * names with a generic character 'v'. 43 | *) 44 | val remove_noise : comment_info -> string -> string list -> char list -> bool -> string 45 | 46 | (* [k_grams str n] creates a list of strings of length n, starting at each 47 | * character in [str] up to and including ([str] length - [n])th character. 48 | * 49 | * example: 50 | * [k_grams "Hello World" 3 = 51 | * ["Hel"; "ell"; "llo"; "lo "; "o W"; " Wo"; "Wor"; "orl"; "rld"]] 52 | *) 53 | val k_grams : string -> int -> string list 54 | 55 | (* [hash_file f] returns a list of hashes for n-grams of a file f with default 56 | * n = 35, where the file has been preprocessed by removing whitespace, 57 | * removing comments, replacing all variable names and strings with a generic 58 | * tag, while making sure that keywords and module names remain intact. 59 | *) 60 | val hash_file : string -> int list 61 | 62 | (* [get_file_positions dir dir_name filename positions] rehashes file filename 63 | * from directory dir, preprocessing it similar to how it would be in hash_file, 64 | * and returns a list of parts of the files that start at the values in 65 | * positions once the files have been preprocessed. 66 | *) 67 | val get_file_positions : Unix.dir_handle -> 68 | string -> string -> int list -> (string * string) list 69 | -------------------------------------------------------------------------------- /test.ml: -------------------------------------------------------------------------------- 1 | open OUnit2 2 | 3 | let suite = "Final Project Test Suite" >::: 4 | Test_winnow.tests 5 | @ 6 | Test_comparison.tests 7 | @ 8 | Test_dictionary.tests 9 | @ 10 | Test_preprocessing.tests 11 | 12 | (* The following line must be the one and only place 13 | * in your entire source code that calls [OUnit2.run_test_tt_main]. *) 14 | let _ = run_test_tt_main suite 15 | -------------------------------------------------------------------------------- /test_comparison.ml: -------------------------------------------------------------------------------- 1 | open OUnit2 2 | open Dictionary 3 | open Comparison 4 | 5 | let assoc_compare l1 l2 = 6 | if List.length l1 <> List.length l2 then false 7 | else 8 | List.fold_left (fun acc (k,v) -> acc && List.assoc k l2 = v) true l1 9 | 10 | let unordered_list_compare l1 l2 = 11 | if List.length l1 <> List.length l2 then false 12 | else 13 | List.fold_left (fun acc x -> acc && List.mem x l2) true l1 14 | 15 | let filedict_equal d1 d2 = 16 | assert_equal ~cmp:assoc_compare (FileDict.to_list d1) (FileDict.to_list d2) 17 | 18 | let compdict_equal d1 d2 = 19 | assert_equal ~cmp:assoc_compare (CompDict.to_list d1) (CompDict.to_list d2) 20 | 21 | let emp_file = FileDict.empty 22 | 23 | let se_dict = FileDict.insert "a" [(1,0)] emp_file 24 | let de_dict = FileDict.(empty |> insert "a" [(1,0);(2,0)] 25 | |> insert "b" [(1,0);(3,0)]) 26 | let emp_e_dict = FileDict.(empty |> insert "a" [] |> insert "b" [(7,0);(4,0)] 27 | |> insert "c" [(4,0);(8,0);(13,0)]) 28 | 29 | let def_p_comp = FileDict.(empty |> insert "a" [(1,0);(2,0)] 30 | |> insert "b" [(1,0)]) 31 | let des_p_comp = FileDict.(empty |> insert "a" [(1,0)] 32 | |> insert "b" [(1,0);(3,0)]) 33 | let emp_e_f_p_comp = FileDict.(empty |> insert "a" [] |> insert "b" [] 34 | |> insert "c" []) 35 | let emp_e_s_p_comp = FileDict.(empty |> insert "a" [] 36 | |> insert "b" [(7,0);(4,0)] 37 | |> insert "c" [(4,0)]) 38 | let emp_e_t_p_comp = FileDict.(empty |> insert "a" [] |> insert "b" [(4,0)] 39 | |> insert "c" [(4,0);(8,0);(13,0)]) 40 | 41 | 42 | let emp_comp = CompDict.empty 43 | let se_comp = CompDict.(insert "a" se_dict empty) 44 | let def_comp = CompDict.(insert "a" def_p_comp empty) 45 | let de_comp = CompDict.insert "b" des_p_comp def_comp 46 | let emp_e_comp = CompDict.(empty |> insert "a" emp_e_f_p_comp 47 | |> insert "b" emp_e_s_p_comp 48 | |> insert "c" emp_e_t_p_comp) 49 | 50 | let get_files = List.map (fun (k,s) -> k) 51 | 52 | let tests = [ 53 | 54 | (* The test cases for intersection has cases that test what happens with 55 | * one or more empty lists, single element lists, 2 lists with the order 56 | * reversed, lists with elements of same hash but different position, 57 | * and lists with different number of elements, which are all the edge 58 | * cases, and then a couple of general cases. *) 59 | "empty lists" >:: (fun _ -> assert_equal ~cmp:assoc_compare [] (intersection [] [])); 60 | "one list empty" >:: (fun _ -> assert_equal ~cmp:assoc_compare [] 61 | ((intersection [(12,7);(9,13)] []))); 62 | "single lists uneq" >:: 63 | (fun _ -> assert_equal ~cmp:assoc_compare [] (intersection [(1,0)] [(2,0)])); 64 | "single lists eq" >:: 65 | (fun _ -> assert_equal ~cmp:assoc_compare [(1,0)] (intersection [(1,0)] [(1,0)])); 66 | "diff order" >:: (fun _ -> assert_equal ~cmp:assoc_compare [(1,0);(2,0)] 67 | ((intersection [(1,0);(2,0)] [(2,0);(1,0)]))); 68 | "second order" >:: (fun _ -> assert_equal ~cmp:assoc_compare [(2,0);(1,0)] 69 | ((intersection [(2,0);(1,0)] [(1,0);(2,0)] ))); 70 | "diff pos" >:: (fun _ -> assert_equal ~cmp:assoc_compare [(1,3);(2,1)] 71 | ((intersection [(1,3);(2,1)] [(2,2);(1,5)]))); 72 | "diff number of elems" >:: (fun _ -> assert_equal ~cmp:assoc_compare [(1,0);(2,1)] 73 | ((intersection [(1,0);(7,3);(2,1);(4,3)] 74 | [(2,2);(1,5)]))); 75 | "simp case" >:: 76 | (fun _ -> assert_equal ~cmp:assoc_compare [(1,0);(2,0)] 77 | ((intersection [(3,0);(1,0);(2,0)] [(2,0);(1,0)]))); 78 | "long case" >:: (fun _ -> assert_equal ~cmp:assoc_compare [(41,0);(20,0);(7,0);(53,0)] 79 | (intersection [(82,0);(23,0);(46,0);(93,0);(41,0);(20,0); 80 | (47,0);(7,0);(84,0);(53,0)] 81 | [(80,0);(42,0);(41,0);(53,0);(72,0);(7,0);(20,0);(100,0)])); 82 | 83 | 84 | (* The test cases for make_pair_comp test if the function works on an 85 | * empty file, on a single entry file dictionary, if it works correctly for 86 | * either part of a double entry file dictionary with the corresponding 87 | * changes, and if it works if one of the entries in a file dictionary 88 | * is empty, which are all the edge cases. *) 89 | "empty file" >:: (fun _ -> filedict_equal emp_file 90 | (make_pair_comp "" [])); 91 | "single entry" >:: (fun _ -> filedict_equal se_dict 92 | (make_pair_comp "a" [("a",[(1,0)])])); 93 | "double entry first" >:: (fun _ -> filedict_equal def_p_comp 94 | (make_pair_comp "a" (FileDict.to_list de_dict))); 95 | "double entry second" >:: (fun _ -> filedict_equal des_p_comp 96 | (make_pair_comp "b" (FileDict.to_list de_dict))); 97 | "empty entry in file" >:: (fun _ -> filedict_equal emp_e_f_p_comp 98 | (make_pair_comp "a" (FileDict.to_list emp_e_dict))); 99 | "empty entry second" >:: (fun _ -> filedict_equal emp_e_s_p_comp 100 | (make_pair_comp "b" (FileDict.to_list emp_e_dict))); 101 | "empty entry third" >:: (fun _ -> filedict_equal emp_e_t_p_comp 102 | (make_pair_comp "c" (FileDict.to_list emp_e_dict))); 103 | 104 | 105 | (* The test for compare test if it works on an empty file dictionary, 106 | * a single entry file dictionary, a double entry file dictionary, 107 | * and a file dictionary with an empty entry, which are all the edge 108 | * cases. *) 109 | "empty comp" >:: (fun _ -> compdict_equal emp_comp 110 | (compare emp_file)); 111 | "single entry comp" >:: (fun _ -> compdict_equal se_comp 112 | (compare se_dict)); 113 | "double entry comp" >:: (fun _ -> compdict_equal de_comp 114 | (compare de_dict)); 115 | "empty entry comp" >:: (fun _ -> compdict_equal emp_e_comp 116 | (compare emp_e_dict)); 117 | 118 | 119 | (* The test cases for create_sim_list test if the function works for 120 | * an empty comparison dictionary, one with a single entry, one with two 121 | * entries, and only with an empty entry, which are all the edge cases. *) 122 | "empty sim" >:: (fun _ -> assert_equal ~cmp:assoc_compare [] 123 | (create_sim_list emp_comp 0.5)); 124 | "single entry sim" >:: (fun _ -> assert_equal ~cmp:assoc_compare [] 125 | (create_sim_list se_comp 0.5)); 126 | "double entry sim" >:: (fun _ -> assert_equal ~cmp:unordered_list_compare ["a";"b"] 127 | (create_sim_list de_comp 0.5 |> get_files)); 128 | "empty entry sim" >:: (fun _ -> assert_equal ~cmp:unordered_list_compare ["b"] 129 | (create_sim_list emp_e_comp 0.5 |> get_files)); 130 | 131 | 132 | (* The tests for create_pair_sim_list test if it works on an empty file 133 | * dictionary list, a single entry list, a double entry list for both entries 134 | * and for a list with an empty entry with every other filename than that of 135 | * of the one with the empty entry, since a precondition is that that case 136 | * will not work, which are all of the edge cases. *) 137 | "empty pair" >:: (fun _ -> assert_equal ~cmp:assoc_compare [] 138 | (create_pair_sim_list "" [])); 139 | "single entry" >:: (fun _ -> assert_equal ~cmp:assoc_compare [] 140 | (create_pair_sim_list "a" (FileDict.to_list se_dict))); 141 | "double entry first" >:: (fun _ -> assert_equal ~cmp:assoc_compare [("b",0.5)] 142 | (create_pair_sim_list "a" (FileDict.to_list def_p_comp))); 143 | "double entry second" >:: (fun _ -> assert_equal ~cmp:assoc_compare [("a",0.5)] 144 | (create_pair_sim_list "b" (FileDict.to_list des_p_comp))); 145 | "empty entry second" >:: (fun _ -> assert_equal ~cmp:assoc_compare [("c",0.5);("a",0.0)] 146 | (create_pair_sim_list "b" (FileDict.to_list emp_e_s_p_comp))); 147 | "empty entry third" >:: (fun _ -> assert_equal ~cmp:unordered_list_compare ["b";"a"] 148 | ((create_pair_sim_list "c" (FileDict.to_list emp_e_t_p_comp)) |> get_files)); 149 | 150 | ] -------------------------------------------------------------------------------- /test_dictionary.ml: -------------------------------------------------------------------------------- 1 | open Dictionary 2 | open OUnit2 3 | 4 | let assoc_compare l1 l2 = 5 | if List.length l1 <> List.length l2 then false 6 | else 7 | List.fold_left (fun acc (k,v) -> acc && List.assoc k l2 = v) true l1 8 | 9 | module ValString = struct 10 | type t = string 11 | let format s = 12 | print_string s; 13 | end 14 | 15 | module KeyString = struct 16 | type t = string 17 | let compare x y = Stdlib.compare x y 18 | end 19 | 20 | module DictString = HashtblDict (KeyString) (ValString) 21 | 22 | let t1 = DictString.(insert "A" "a" empty) 23 | let t2 = DictString.(insert "L" "l" t1) 24 | let t3 = DictString.(insert "G" "g" t2) 25 | let t4 = DictString.(insert "O" "o" t3) 26 | let t5 = DictString.(insert "R" "r" t4) 27 | let t6 = DictString.(insert "I" "i" t5) 28 | let t7 = DictString.(insert "T" "t" t6) 29 | let t8 = DictString.(insert "H" "h" t7) 30 | let t9 = DictString.(insert "M" "m" t8) 31 | let t = DictString.(insert "S" "s" t9) 32 | 33 | let tests = [ 34 | "insert first" >::(fun _ -> assert_equal ~cmp:assoc_compare [("A","a")] (DictString.to_list t1)); 35 | "insert 2" >:: (fun _ -> assert_equal ~cmp:assoc_compare [("A","a");("L","l")] 36 | (DictString.to_list t2)); 37 | "insert 2" >:: (fun _ -> assert_equal ~cmp:assoc_compare [("A","a"); ("G", "g");("L","l")] 38 | (DictString.to_list t3)); 39 | "insert 3" >:: (fun _ -> assert_equal ~cmp:assoc_compare [("A","a"); ("G", "g");("L","l"); 40 | ("O","o")] (DictString.to_list t4)); 41 | "insert 4" >:: (fun _ -> assert_equal ~cmp:assoc_compare 42 | [("A","a"); ("G","g");("L","l"); ("O","o");("R","r")] 43 | (DictString.to_list t5)); 44 | "insert 5" >:: (fun _ -> assert_equal ~cmp:assoc_compare 45 | [("A","a"); ("G","g"); ("I", "i");("L","l"); ("O","o");("R","r")] 46 | (DictString.to_list t6)); 47 | "insert 6" >:: (fun _ -> assert_equal ~cmp:assoc_compare 48 | [("A","a"); ("G","g");("I","i");("L","l"); ("O","o");("R","r"); ("T","t")] 49 | (DictString.to_list t7)); 50 | "insert 7" >:: (fun _ -> assert_equal ~cmp:assoc_compare 51 | [("A","a"); ("G","g");("H","h");("I","i");("L","l"); ("O","o");("R","r"); 52 | ("T","t")] (DictString.to_list t8)); 53 | "insert 8" >:: (fun _ -> assert_equal ~cmp:assoc_compare 54 | [("A","a"); ("G","g");("H","h");("I","i");("L","l"); 55 | ("M","m");("O","o");("R","r"); ("T","t")] 56 | (DictString.to_list t9)); 57 | "Inserted Correct" >:: (fun _ -> 58 | assert_equal ~cmp:assoc_compare [("A", "a"); ("G", "g"); ("H", "h"); ("I", "i"); ("L", "l"); 59 | ("M", "m"); ("O", "o"); ("R", "r"); ("S", "s"); ("T", "t")] 60 | (DictString.to_list t)); 61 | 62 | 63 | "size_empty" >:: (fun _ -> assert_equal 0 DictString.(size empty)); 64 | "size_1" >:: (fun _ -> assert_equal 1 DictString.(size t1)); 65 | "size_mid" >:: (fun _ -> assert_equal 5 DictString.(size t5)); 66 | "size_full" >:: (fun _ -> assert_equal 10 DictString.(size t)); 67 | 68 | "string_member" >:: (fun _ -> assert_equal true 69 | (DictString.member "A" t1)); 70 | "member_empty" >:: (fun _ -> assert_equal false 71 | (DictString.(member "empty" empty))); 72 | "member_fake" >:: (fun _ -> assert_equal false (DictString.member "B" t1)); 73 | "member_two" >:: (fun _ -> assert_equal true (DictString.member "R" t)); 74 | "member_three" >:: (fun _ -> assert_equal true (DictString.member "S" t)); 75 | 76 | "find_fake" >:: (fun _ -> assert_equal (None) (DictString.find "fake" t)); 77 | "find_none" >:: (fun _ -> assert_equal (None) DictString.(find "K" empty)); 78 | "find_first" >:: (fun _ -> assert_equal (Some("a")) 79 | (DictString.find "A" t1)); 80 | 81 | "find_two" >:: (fun _ -> assert_equal (Some "g") DictString.(find "G" t)); 82 | "find_three" >:: (fun _ -> assert_equal (Some "m") DictString.(find "M" t)); 83 | ] 84 | -------------------------------------------------------------------------------- /test_preprocessing.ml: -------------------------------------------------------------------------------- 1 | open OUnit2 2 | open Preprocessing 3 | 4 | let ocaml_keywords = 5 | ["and"; "as"; "assert"; "asr"; "begin"; "class"; "constraint"; 6 | "do"; "done"; "downto"; "else"; "end"; "exception"; "external"; 7 | "false"; "for"; "fun"; "function"; "functor"; "if"; "in"; "include"; 8 | "inherit"; "initializer"; "land"; "lazy"; "let"; "lor"; "lsl"; "lsr"; 9 | "lxor"; "match"; "method"; "mod"; "module"; "mutable"; "new"; "nonrec"; 10 | "object"; "of"; "open"; "or"; "private"; "rec"; "sig"; "struct"; "then"; 11 | "to"; "true"; "try"; "type"; "val"; "virtual"; "when"; "while"; "with"; 12 | "Arg"; "Array"; "ArrayLabels"; "Buffer"; "Bytes"; "BytesLabels"; "Callback"; 13 | "Char"; "Complex"; "Digest"; "Ephemeron"; "Filename"; "Format"; "Gc"; 14 | "Genlex"; "Hashtbl"; "Int32"; "Int64"; "Lazy"; "Lexing"; "List"; 15 | "ListLabels"; "Map"; "Marshal"; "MoreLabels"; "Nativeint"; "Oo"; "Parsing"; 16 | "Printexc"; "Printf"; "Queue"; "Random"; "Scanf"; "Set"; "Sort"; 17 | "Spacetime"; "Stack"; "StdLabels"; "Stream"; "String"; "StringLabels"; 18 | "Sys"; "Uchar"; "Weak"; "failwith"] 19 | 20 | let ocaml_spec_chars = 21 | ['!'; '$'; '%'; '&'; '*'; '+'; '-'; '.'; '/'; ':'; ';'; '<'; 22 | '='; '>'; '?'; '@'; '^'; '|'; '~'; '#'; '\"'; '('; ')'; ','; 23 | '['; ']'; '{'; '}'] 24 | 25 | let ocaml_comments_info = 26 | { 27 | single_comment = ""; 28 | multi_comment_start = "(*"; 29 | multi_comment_end = "*)"; 30 | nest= true; 31 | strings= true; 32 | } 33 | 34 | let java_keywords = 35 | ["abstract"; "continue"; "for"; "new"; "switch"; "assert"; "default"; 36 | "package"; "synchronized"; "boolean"; "do"; "if"; "private"; "this"; "break"; 37 | "double"; "implements"; "protected"; "throw"; "byte"; "else"; "import"; 38 | "public"; "throws"; "case"; "enum"; "instanceof"; "return"; "transient"; 39 | "catch"; "extends"; "int"; "short"; "try"; "char"; "final"; "interface"; 40 | "static"; "void"; "class"; "finally"; "long"; "strictfp"; "volatile"; 41 | "float"; "native"; "super"; "while"; "Boolean"; "Byte"; "Character"; "Class"; 42 | "ClassLoader"; "ClassValue"; "Compiler"; "Double"; "Enum"; "Float"; 43 | "InheritableThreadLocal"; "Integer "; "Long"; "Math"; "Number"; "Object"; 44 | "Package"; "Process"; "ProcessBuilder"; "Runtime"; "RuntimePermission"; 45 | "SecurityManager"; "Short"; "StackTraceElement"; "StrictMath"; "String"; 46 | "StringBuffer"; "StringBuilder"; "System"; "Thread"; "ThreadGroup"; 47 | "ThreadLocal"; "Throwable"; "Void"; "AbstractCollection"; "AbstractList"; 48 | "AbstractMap"; "AbstractQueue"; "AbstractSequentialList"; "AbstractSet"; 49 | "ArrayDeque"; "ArrayList"; "Arrays"; "BitSet"; "Calendar"; "Collections"; 50 | "Currency"; "Date"; "Dictionary"; "EnumMap"; "EnumSet"; "EventListenerProxy"; 51 | "EventObject"; "FormattableFlags"; "Formatter"; "GregorianCalendar"; 52 | "HashMap";"HashSet"; "Hashtable"; "IdentityHashMap"; "LinkedHashMap"; 53 | "LinkedHashSet"; "LinkedList"; "ListResourceBundle"; "Locale"; "Objects"; 54 | "Observable"; "PriorityQueue"; "Properties"; "PropertyPermission"; 55 | "PropertyResourceBundle"; "Random"; "ResourceBundle"; 56 | "ResourceBundle.Control"; "Scanner"; "ServiceLoader"; "SimpleTimeZone"; 57 | "Stack"; "StringTokenizer"; "Timer"; "TimerTask"; "TimeZone"; "TreeMap"; 58 | "TreeSet"; "UUID"; "Vector"; "WeakHashMap"] 59 | 60 | let java_spec_chars = 61 | ['!'; '$'; '%'; '&'; '*'; '+'; '-'; '.'; '/'; ':'; ';'; 62 | '<'; '='; '>'; '?'; '^'; '|'; '\"'; '\''; '('; ')'; ','; '['; ']'; 63 | '{'; '}'; '~'; '@'] 64 | 65 | let java_comments_info = 66 | { 67 | single_comment = "//"; 68 | multi_comment_start = "/*"; 69 | multi_comment_end = "*/"; 70 | nest= false; 71 | strings= true; 72 | } 73 | 74 | let test_fun_str = 75 | "(* Hello World this is a comment *) 76 | (* (* This is a nested comment *) *) 77 | (* This is a multi line comment 78 | This is a multi line comment *) 79 | (* This is a multi line (* nested comment 80 | Wowie this is *) quite the comment *) 81 | let split_and_keep_on_spec_chars spec_chars str = 82 | let char_array = str_to_chr_arr str in 83 | (List.fold_left 84 | (fun acc_arr chr -> 85 | let str_of_chr = String.make 1 chr in 86 | if List.mem chr spec_chars then 87 | List.cons \"\" (List.cons str_of_chr acc_arr) 88 | else 89 | (* Hello I am yet another comment *) 90 | match acc_arr with 91 | | h::t -> (String.concat \"\" [h;str_of_chr])::t 92 | | [] -> failwith \"Array should never be empty\" 93 | ) 94 | [\"\"] 95 | char_array) |> List.filter (fun str -> str <> \"\") |> List.rev" 96 | 97 | let expected_res_str = String.concat "" 98 | ["letvvv=letv=vvin(List.v(funvv->letv=String.v1vinifList.vvvthenList.v"; 99 | "(List.vvv)elsematchvwith|v::v->(String.v[v;v])::v|[]->failwithv"; 100 | ")[]v)|>List.v(funv->v<>)|>List.v"] 101 | 102 | let test_fun_str3 = "wow(*wow wow wow*)wow" 103 | 104 | let expected_res_str3 = "vv" 105 | 106 | let test_fun_str4 = "wow (* wow wow wow" 107 | 108 | let expected_res_str4 = "v" 109 | 110 | let test_fun_str5 = 111 | "/** 112 | * A DumbAI is a Controller that always chooses the blank space with the 113 | * smallest column number from the row with the smallest row number. 114 | */ 115 | public class DumbAI extends Controller" 116 | 117 | let expected_res_str5 = "publicclassvextendsv" 118 | 119 | let test_fun_str6 = 120 | "// Note: Calling delay here will make the CLUI work a little more 121 | Hello World 122 | I am the World 123 | hahaha" 124 | 125 | let expected_res_str6 = "vvvvvvv" 126 | 127 | let test_fun_str7 = 128 | "package controller; 129 | 130 | import java.util.ArrayList; 131 | import java.util.List; 132 | 133 | import model.Board; 134 | import model.Game; 135 | import model.Location; 136 | import model.NotImplementedException; 137 | import model.Player; 138 | 139 | /** 140 | * A DumbAI is a Controller that always chooses the blank space with the 141 | * smallest column number from the row with the smallest row number. 142 | */ 143 | public class DumbAI extends Controller { 144 | 145 | public DumbAI(Player me) { 146 | super(me); 147 | // TODO Auto-generated constructor stub 148 | //throw new NotImplementedException(); 149 | } 150 | 151 | protected @Override Location nextMove(Game g) { 152 | // Note: Calling delay here will make the CLUI work a little more 153 | // nicely when competing different AIs against each other. 154 | 155 | // TODO Auto-generated method stub 156 | //throw new NotImplementedException(); 157 | 158 | Board b = g.getBoard(); 159 | // find available moves 160 | for (int row = 0;row:: (fun _ -> assert_equal (k_grams "test" 3) ["tes"; "est"]); 182 | "k_grams_1" >:: (fun _ -> assert_equal (k_grams "Hello World" 5) 183 | ["Hello"; "ello "; "llo W"; "lo Wo"; "o Wor"; " Worl"; "World"]); 184 | "ocaml_keywords" >:: (fun _ -> assert_equal 185 | ocaml_info.keywords 186 | ocaml_keywords); 187 | "ocaml_spec_chars" >:: (fun _ -> assert_equal 188 | ocaml_info.special_chars ocaml_spec_chars); 189 | "ocaml_comments_info" >:: (fun _ -> assert_equal 190 | ocaml_info.comment_info 191 | ocaml_comments_info); 192 | 193 | "java_keywords" >:: (fun _ -> assert_equal java_info.keywords java_keywords); 194 | "java_spec_chars" >:: (fun _ -> assert_equal java_info.special_chars java_spec_chars); 195 | "java_comments_info" >:: (fun _ -> assert_equal 196 | java_info.comment_info 197 | java_comments_info); 198 | 199 | 200 | "remove_noise" >:: 201 | (fun _ -> assert_equal 202 | (remove_noise 203 | ocaml_comments_info 204 | test_fun_str 205 | ocaml_keywords ocaml_spec_chars 206 | false) 207 | expected_res_str); 208 | 209 | "remove_noise_3" >:: 210 | (fun _ -> assert_equal 211 | (remove_noise 212 | ocaml_comments_info 213 | test_fun_str3 214 | ocaml_keywords ocaml_spec_chars 215 | false) 216 | expected_res_str3); 217 | 218 | "remove_noise_4" >:: 219 | (fun _ -> assert_equal 220 | (remove_noise 221 | ocaml_comments_info 222 | test_fun_str4 223 | ocaml_keywords ocaml_spec_chars 224 | false) 225 | expected_res_str4); 226 | 227 | "remove_noise_5" >:: 228 | (fun _ -> assert_equal 229 | (remove_noise 230 | java_comments_info 231 | test_fun_str5 232 | java_keywords java_spec_chars 233 | false) 234 | expected_res_str5); 235 | 236 | "remove_noise_6" >:: 237 | (fun _ -> assert_equal 238 | (remove_noise 239 | java_comments_info 240 | test_fun_str6 241 | java_keywords java_spec_chars 242 | false) 243 | expected_res_str6); 244 | 245 | "remove_noise_7" >:: 246 | (fun _ -> assert_equal 247 | (remove_noise 248 | java_comments_info 249 | "abc<=def" 250 | java_keywords java_spec_chars 251 | false) 252 | "v<=v"); 253 | 254 | "remove_noise_8" >:: 255 | (fun _ -> assert_equal 256 | (remove_noise 257 | ocaml_comments_info 258 | "let x = \"(*\" in let y = 5 in \"*)\"" 259 | ocaml_keywords ocaml_spec_chars 260 | false) 261 | "letv=vinletv=5inv"); 262 | 263 | "remove_noise_9" >:: 264 | (fun _ -> assert_equal 265 | (remove_noise 266 | ocaml_comments_info 267 | "let x = 'y'" 268 | ocaml_keywords ocaml_spec_chars 269 | false) 270 | "letv=v"); 271 | ] 272 | -------------------------------------------------------------------------------- /test_winnow.ml: -------------------------------------------------------------------------------- 1 | open OUnit2 2 | open Winnowing 3 | 4 | (* helper function for sorting winnowing results (int*int) list representing 5 | * hash * position tuples sorts from least to greatest, by hash value first, 6 | * then by position if hashes are equal 7 | *) 8 | let sort_results r = 9 | let cmp x y = 10 | let res = Stdlib.compare (fst x) (fst y) in 11 | if res = 0 then Stdlib.compare (snd x) (snd y) else res 12 | in 13 | List.sort (cmp) r 14 | 15 | (* helper function for converting results to strings 16 | * inputs: (int * int) list representing winnowing results 17 | * returns: a string representation of the hashes contained in the input 18 | * side effects: prints the string that is created *) 19 | let res_to_string r = 20 | List.rev r |> List.map (fun x -> fst x) |> List.map (string_of_int) |> 21 | List.fold_left (fun a x -> a ^ x ^ ",") "" 22 | 23 | (* Non-trivial test cases generated with a Python implementation of the same 24 | * algorithm *) 25 | (* 10 hashes, w = 5 *) 26 | let t1 = [407;345;-163;-695;54;898;-182;759;172;-345] 27 | let r1 = "407,345,-163,-695,-182,-345," 28 | 29 | (* 100 hashes, w = 10 *) 30 | let t2 = [-525;-765;990;457;-841;-446;-407;386;-433;-145;370;-133;-170;348;-532; 31 | 328;306;-325;-856;-131;971;266;-88;-608;-274;539;10;-367;389;68;147; 32 | 81;-745;51;750;640;148;416;-983;645;-692;-169;-162;-76;562;894;881; 33 | -883;244;121;-501;-281;311;-903;20;-285;-533;-818;-273;241;103;318; 34 | 161;763;-790;-348;961;655;431;301;217;-680;834;385;-92;76;-354;-683; 35 | 23;-898;-16;734;-806;-474;-728;-349;-900;107;-118;-160;808;273;351; 36 | 117;53;695;261;-803;-571;-564] 37 | let r2 = "-525,-765,-841,-532,-856,-608,-745,-983,-883,-903,-818,-790,-680,"^ 38 | "-683,-898,-900,-160,-803," 39 | 40 | (* 100 hashes, w = 5 *) 41 | let t3 = [-688;288;-953;-376;-521;480;-314;723;428;260;-804;-915;471;990;-243; 42 | -230;-684;-694;682;948;404;-474;-704;746;886;634;92;-87;778;-424;120; 43 | -883;-293;-463;594;-408;58;518;-300;-938;-641;413;873;102;-35;-978; 44 | -921;-909;-745;-693;-318;-612;-475;366;-173;749;181;215;-487;-264; 45 | -33;730;613;-43;-464;-779;435;123;-313;-252;116;-175;-291;21;-932; 46 | -105;-816;-697;312;-332;-140;702;949;864;-134;217;-579;-601;-616;59; 47 | -478;-381;107;-88;-696;872;-431;533;-397;-918] 48 | let r3 = "-688,-953,-521,-314,-804,-915,-684,-694,-704,-87,-424,-883,-463,"^ 49 | "-408,-938,-641,-978,-921,-909,-745,-693,-612,-475,-173,-487,-264,"^ 50 | "-464,-779,-313,-291,-932,-816,-697,-332,-140,-134,-579,-601,-616,"^ 51 | "-478,-696,-918," 52 | 53 | (* 100 hashes, w = 20 *) 54 | let t4 = [-776;271;540;-580;-710;803;690;980;611;-305;252;-404;-377;544;-982; 55 | -577;-792;139;574;-107;752;-108;-326;354;-339;-323;-317;-571;-995; 56 | 797;-517;-594;-130;-95;-343;-989;-979;-623;299;-941;534;-542;-328; 57 | -23;632;280;640;-74;-3;471;-770;356;-204;-354;-273;124;743;143;575; 58 | -75;-391;329;724;-253;680;-63;-891;-564;92;-100;-892;263;-671;100; 59 | 496;205;468;-936;408;-195;422;600;382;726;991;-397;172;164;373;559; 60 | 185;495;584;-311;-257;-869;-136;968;-12;932] 61 | let r4 = "-776,-982,-995,-989,-979,-941,-770,-891,-892,-936,-869," 62 | 63 | (* tests to check Winnowing functionality *) 64 | let tests = [ 65 | "winnow0" >:: (fun _ -> assert_equal "" (winnow 1 [] |> res_to_string)); 66 | "winnow1" >:: (fun _ -> assert_equal "1," (winnow 1 [1] |> res_to_string)); 67 | "winnow2" >:: (fun _ -> assert_equal "1,2,3,4,5," (winnow 1 [1;2;3;4;5] 68 | |> res_to_string)); 69 | "winnow3" >:: (fun _ -> assert_equal "5,4,3,2,1," (winnow 1 [5;4;3;2;1] 70 | |> res_to_string)); 71 | "winnow4" >:: (fun _ -> assert_equal "5,4,3,2,1," (winnow 1 [5;4;3;2;1] 72 | |> res_to_string)); 73 | "winnow5" >:: (fun _ -> assert_equal "1,2,3,4," (winnow 2 [1;2;3;4;5] 74 | |> res_to_string)); 75 | "winnow6" >:: (fun _ -> assert_equal r1 (winnow 5 t1 |> res_to_string)); 76 | "winnow7" >:: (fun _ -> assert_equal r2 (winnow 10 t2 |> res_to_string)); 77 | "winnow8" >:: (fun _ -> assert_equal r3 (winnow 5 t3 |> res_to_string)); 78 | "winnow9" >:: (fun _ -> assert_equal r4 (winnow 20 t4 |> res_to_string)); 79 | ] 80 | -------------------------------------------------------------------------------- /tests/MiniFactorialTests/Original.java: -------------------------------------------------------------------------------- 1 | 2 | public class main { 3 | public static void main(String[] args) { 4 | System.out.println(factorial(10)); 5 | } 6 | public static int factorial(int n) 7 | { 8 | int ret = 1; 9 | for (int i = 1; i <= n; ++i) ret *= i; 10 | return ret; 11 | } 12 | } 13 | -------------------------------------------------------------------------------- /tests/MiniFactorialTests/T1-Commented.java: -------------------------------------------------------------------------------- 1 | /** 2 | * Class with comments. 3 | * More comments. 4 | * 5 | * @author Author 6 | * @see #factorial(int) 7 | * 8 | */ 9 | public class main { 10 | /** 11 | * Function with comments. 12 | * More comments. 13 | * @param args 14 | */ 15 | public static void main(String[] args) 16 | { //prints factorial of ten 17 | System.out.println(factorial(10)); } 18 | /** 19 | * Function with comments. 20 | * More comments. 21 | * Factorial of n. 22 | * @param n 23 | * @return factorial 24 | */ 25 | public static int factorial(int n) { 26 | //lots of comments 27 | int ret = 1; 28 | //lots of comments 29 | for (int i = 1;i <= n;++i) 30 | //lots of comments 31 | ret *= i; 32 | //lots of comments 33 | return ret; 34 | } 35 | } -------------------------------------------------------------------------------- /tests/MiniFactorialTests/T1-Copy.java: -------------------------------------------------------------------------------- 1 | 2 | public class main { 3 | public static void main(String[] args) { 4 | System.out.println(factorial(10)); 5 | } 6 | public static int factorial(int n) 7 | { 8 | int ret = 1; 9 | for (int i = 1; i <= n; ++i) ret *= i; 10 | return ret; 11 | } 12 | } 13 | -------------------------------------------------------------------------------- /tests/MiniFactorialTests/T1-Whitespaces.java: -------------------------------------------------------------------------------- 1 | 2 | public class main { 3 | public static void main(String[] args) 4 | { System.out.println(factorial(10)); } 5 | public static int factorial(int n) { 6 | int ret = 1; 7 | for ( 8 | int i = 1; 9 | i <= n; 10 | ++i 11 | ) 12 | ret *= i; return ret; 13 | } } -------------------------------------------------------------------------------- /tests/MiniFactorialTests/T2-Renamed.java: -------------------------------------------------------------------------------- 1 | 2 | public class renamed { 3 | public static void renamed(String[] commandline_parameters) { 4 | System.out.println(fakultaet(10)); 5 | } 6 | public static int fakultaet(int parameter) 7 | { 8 | int result = 1; 9 | for (int current = 1; current <= parameter; ++current) result *= current; 10 | return result; 11 | } 12 | } 13 | -------------------------------------------------------------------------------- /tests/MiniFactorialTests/T2-VariableLong.java: -------------------------------------------------------------------------------- 1 | 2 | public class main { 3 | public static void main(String[] args) { 4 | System.out.println(factorial(10)); 5 | } 6 | public static long factorial(long n) 7 | { 8 | long ret = 1; 9 | for (long i = 1; i <= n; ++i) ret *= i; 10 | return ret; 11 | } 12 | } 13 | -------------------------------------------------------------------------------- /tests/MiniFactorialTests/T3-DummyMethod.java: -------------------------------------------------------------------------------- 1 | 2 | public class main { 3 | public static void main(String[] args) { 4 | System.out.println(factorial(10)); 5 | } 6 | public static int factorial(int n) 7 | { 8 | int ret = 1; 9 | for (int i = 1; i <= n; ++i) { 10 | dummy(); 11 | ret *= i; 12 | } 13 | return ret; 14 | } 15 | public static void dummy() { 16 | Thread.yield(); 17 | } 18 | } 19 | -------------------------------------------------------------------------------- /tests/MiniFactorialTests/T3-DummyMethodPlus.java: -------------------------------------------------------------------------------- 1 | 2 | public class main { 3 | public static void main(String[] args) { 4 | dummy(); 5 | System.out.println(factorial(10)); 6 | dummy(); 7 | } 8 | public static int factorial(int n) 9 | { 10 | dummy(); 11 | int ret = 1; 12 | dummy(); 13 | for (int i = 1; i <= n; ++i) { 14 | dummy(); 15 | ret *= i; 16 | dummy(); 17 | } 18 | dummy(); 19 | return ret; 20 | } 21 | public static boolean dummy() { 22 | assert true; 23 | Thread.yield(); 24 | assert true; 25 | 26 | Thread.yield(); 27 | assert true; 28 | return true; 29 | } 30 | } 31 | -------------------------------------------------------------------------------- /tests/MiniFactorialTests/T3-EndlessLoop.java: -------------------------------------------------------------------------------- 1 | 2 | public class main { 3 | public static void main(String[] args) { 4 | System.out.println(factorial(10)); 5 | } 6 | public static int factorial(int n) 7 | { 8 | int ret = 1; 9 | int i = 0; 10 | while (true) { 11 | i++; 12 | ret *= i; 13 | if (i >=n ) break; 14 | } 15 | 16 | return ret; 17 | } 18 | } 19 | -------------------------------------------------------------------------------- /tests/MiniFactorialTests/T3-ForWhile.java: -------------------------------------------------------------------------------- 1 | 2 | public class main { 3 | public static void main(String[] args) { 4 | System.out.println(factorial(10)); 5 | } 6 | public static int factorial(int n) 7 | { 8 | int ret = 1; 9 | int i = 1; 10 | while (i <= n) { 11 | ret *= i; 12 | i++; 13 | } 14 | return ret; 15 | } 16 | } 17 | -------------------------------------------------------------------------------- /tests/MiniFactorialTests/T3-Inlining.java: -------------------------------------------------------------------------------- 1 | 2 | public class main { 3 | public static void main(String[] args) { 4 | int ret = 1; 5 | for (int i = 1; i <= 10; ++i) ret *= i; 6 | System.out.println(ret); 7 | } 8 | } 9 | -------------------------------------------------------------------------------- /tests/MiniFactorialTests/T3-JumpLabel.java: -------------------------------------------------------------------------------- 1 | 2 | public class main { 3 | 4 | static int currentFactor = 1; 5 | static int currentResult = 1; 6 | 7 | public static void main(String[] args) { 8 | 9 | System.out.println(factorial(10)); 10 | 11 | 12 | } 13 | 14 | public static int factorial(int n) 15 | { 16 | fac: 17 | while(currentFactor!=n) { 18 | currentResult *= currentFactor; 19 | continue fac; 20 | } 21 | return currentResult; 22 | } 23 | } 24 | -------------------------------------------------------------------------------- /tests/MiniFactorialTests/T3-LoopEndpoint.java: -------------------------------------------------------------------------------- 1 | 2 | public class main { 3 | public static void main(String[] args) { 4 | System.out.println(factorial(10)); 5 | } 6 | public static int factorial(int n) 7 | { 8 | int ret = 1; 9 | for (int i = 1; i < n+1; ++i) ret *= i; 10 | return ret; 11 | } 12 | } 13 | -------------------------------------------------------------------------------- /tests/MiniFactorialTests/T3-LoopUnrolling.java: -------------------------------------------------------------------------------- 1 | 2 | public class main { 3 | 4 | public static void main(String[] args) { 5 | System.out.println(factorial10()); 6 | } 7 | 8 | public static int factorial10() 9 | { 10 | int ret = 1; 11 | ret *= 2; 12 | ret *= 3; 13 | ret *= 4; 14 | ret *= 5; 15 | ret *= 6; 16 | ret *= 7; 17 | ret *= 8; 18 | ret *= 9; 19 | ret *= 10; 20 | return ret; 21 | } 22 | } 23 | -------------------------------------------------------------------------------- /tests/MiniFactorialTests/T3-OutputStream.java: -------------------------------------------------------------------------------- 1 | import java.io.PrintWriter; 2 | 3 | 4 | public class main { 5 | public static void main(String[] args) { 6 | PrintWriter outStream; 7 | outStream = new PrintWriter(System.out); 8 | outStream.println(factorial(10)); 9 | } 10 | public static int factorial(int n) 11 | { 12 | int ret = 1; 13 | for (int i = 1; i <= n; ++i) ret *= i; 14 | return ret; 15 | } 16 | } 17 | -------------------------------------------------------------------------------- /tests/MiniFactorialTests/T3-VariableBigInt.java: -------------------------------------------------------------------------------- 1 | import java.math.BigInteger; 2 | 3 | 4 | public class main { 5 | 6 | public static void main(String[] args) { 7 | System.out.println(factorial(10)); 8 | } 9 | 10 | public static BigInteger factorial(int n) 11 | { 12 | BigInteger newNameForBigI = BigInteger.ONE; 13 | for (int j = 1; j <= n; ++j) { 14 | newNameForBigI = newNameForBigI.multiply(BigInteger.valueOf(j)); 15 | } 16 | return newNameForBigI; 17 | } 18 | } 19 | -------------------------------------------------------------------------------- /tests/MiniFactorialTests/T4-AlgorithmChange.java: -------------------------------------------------------------------------------- 1 | // Copyright (C) 2004-2009 Peter Luschny, MIT License applies. 2 | // See http://en.wikipedia.org/wiki/MIT_License 3 | // Visit http://www.luschny.de/math/factorial/FastFactorialFunctions.htm 4 | // Comments mail to: peter(at)luschny.de 5 | 6 | 7 | import java.util.ArrayList; 8 | import java.util.List; 9 | import java.util.concurrent.Callable; 10 | import java.util.concurrent.ExecutorService; 11 | import java.util.concurrent.Executors; 12 | import java.util.concurrent.Future; 13 | 14 | 15 | public class main { 16 | // Same algorithm as Split 17 | // but computing products concurrently. 18 | 19 | public static void main(String[] args) { 20 | main x = new main(); 21 | System.out.println(x.factorial(10)); 22 | } 23 | 24 | 25 | public Xint factorial(int n) { 26 | if (n < 0) { 27 | throw new ArithmeticException("Factorial: n has to be >= 0, but was " + n); 28 | } 29 | 30 | if (n < 2) { 31 | return Xint.ONE; 32 | } 33 | 34 | // -- log2n = floor(log2(n)); 35 | int log2n = 31 - Integer.numberOfLeadingZeros(n); 36 | int proc = Runtime.getRuntime().availableProcessors(); 37 | 38 | ExecutorService exe = Executors.newFixedThreadPool(proc); 39 | ArrayList> tasks = new ArrayList>(log2n); 40 | 41 | int high = n, low = n >>> 1, shift = low, taskCounter = 0; 42 | 43 | // -- It is more efficient to add the big intervals 44 | // -- first and the small ones later! 45 | while ((low + 1) < high) { 46 | tasks.add(new Product(low + 1, high)); 47 | high = low; 48 | low >>= 1; 49 | shift += low; 50 | taskCounter++; 51 | } 52 | 53 | Xint p = Xint.ONE, r = Xint.ZERO; 54 | 55 | try { 56 | List> products = exe.invokeAll(tasks); 57 | 58 | Future R = exe.submit(new Callable() { 59 | 60 | @Override 61 | public Xint call() { 62 | return Xint.ONE; 63 | } 64 | }); 65 | 66 | while (--taskCounter >= 0) { 67 | p = p.multiply(products.get(taskCounter).get()); 68 | R = exe.submit(new Multiply(R.get(), p)); 69 | } 70 | 71 | r = R.get(); 72 | } catch (Throwable e) { 73 | } 74 | 75 | exe.shutdownNow(); 76 | return r.shiftLeft(shift); 77 | } 78 | 79 | final static class Multiply implements Callable { 80 | 81 | private final Xint a, b; 82 | 83 | public Multiply(Xint a, Xint b) { 84 | this.a = a; 85 | this.b = b; 86 | } 87 | 88 | @Override 89 | public Xint call() { 90 | return a.multiply(b); 91 | } 92 | } 93 | } // endOfFactorialSplitRecursive 94 | 95 | final class Product implements Callable { 96 | 97 | private final int n, m; 98 | 99 | public Product(int n, int m) { 100 | this.n = n; 101 | this.m = m; 102 | } 103 | 104 | @Override 105 | public Xint call() { 106 | return product(n, m); 107 | } 108 | 109 | public static Xint product(int n, int m) { 110 | n = n | 1; // Round n up to the next odd number 111 | m = (m - 1) | 1; // Round m down to the next odd number 112 | 113 | if (m == n) { 114 | return Xint.valueOf(m); 115 | } 116 | if (m == (n + 2)) { 117 | return Xint.valueOf((long) n * m); 118 | } 119 | 120 | int k = (n + m) >>> 1; 121 | return product(n, k).multiply(product(k + 1, m)); 122 | } 123 | } -------------------------------------------------------------------------------- /tests/MiniFactorialTests/T4-Approximation.java: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/RobYang1024/OCaMOSS/5a78137bf717d2bb8248489f0619a01ebea9d1df/tests/MiniFactorialTests/T4-Approximation.java -------------------------------------------------------------------------------- /tests/MiniFactorialTests/T4-ProGuardObfuscation.java: -------------------------------------------------------------------------------- 1 | import java.io.PrintStream; 2 | 3 | public class main 4 | { 5 | public static void main(String[] paramArrayOfString) 6 | { 7 | paramArrayOfString = 1; 8 | for (String[] arrayOfString = 1; arrayOfString <= 10; arrayOfString++) 9 | paramArrayOfString *= arrayOfString; 10 | System.out.println(paramArrayOfString); 11 | } 12 | } 13 | 14 | /* Location: C:\Users\Admin\Desktop\totest\Main-JARExport\main-jar.jar 15 | * Qualified Name: main 16 | * JD-Core Version: 0.6.0 17 | */ -------------------------------------------------------------------------------- /tests/MiniFactorialTests/T4-Recursive.java: -------------------------------------------------------------------------------- 1 | 2 | public class main { 3 | 4 | public static void main(String[] args) { 5 | System.out.println(factorial(10)); 6 | } 7 | 8 | public static int factorial(int n) 9 | { 10 | if (n == 0) return 1; 11 | return n * factorial(n-1); 12 | } 13 | } 14 | -------------------------------------------------------------------------------- /tests/SSID_demo/01.java: -------------------------------------------------------------------------------- 1 | import java.util.*; 2 | 3 | /** 4 | * Driver class, you may have to change it to fit your implementation 5 | * Make sure you compile and run this class 6 | */ 7 | public class CitiesDriver { 8 | static Scanner sc; 9 | 10 | /** Read in the tree 11 | */ 12 | public static void readTree () { 13 | /// Read in the tree 14 | // read in one integer 15 | int n = sc.nextInt(); 16 | // read in tree, safety line 17 | for (int i=0;i= 0) { 145 | if (!myTree[index].isSafe()) return false; 146 | else { 147 | if (index == target) return true; 148 | 149 | if (directPath(myTree[index].left(),target)) return true; 150 | else return directPath(myTree[index].right(),target); 151 | } 152 | } 153 | 154 | return false; 155 | } 156 | 157 | public boolean search (int index, int target) { 158 | 159 | if (index >= 0) { 160 | if (index == target) return true; 161 | 162 | if (search(myTree[index].left(),target)) return false; 163 | else return search(myTree[index].right(),target); 164 | } 165 | 166 | return false; 167 | } 168 | 169 | public void print (MyNode[] tree, int index) { 170 | 171 | if (index >= 0) { 172 | print(tree,tree[index].left()); 173 | 174 | System.out.print(index); 175 | if (!tree[index].isSafe()) System.out.print("*"); 176 | System.out.print(" "); 177 | 178 | print(tree,tree[index].right()); 179 | } 180 | 181 | } 182 | 183 | } 184 | -------------------------------------------------------------------------------- /tests/SSID_demo/03.java: -------------------------------------------------------------------------------- 1 | import java.util.*; 2 | 3 | /** 4 | * Driver class 5 | */ 6 | 7 | public class CitiesDriver { 8 | 9 | public static Scanner sc; 10 | public static MyTree tree; 11 | 12 | // Read in the tree 13 | public static void readTree () { 14 | 15 | // Read in the tree 16 | // read in one integer 17 | int read1Integer = sc.nextInt(); 18 | 19 | tree = new MyTree (read1Integer ); 20 | 21 | // read in tree, safety line 22 | for (int i = 0; i < read1Integer ; i++) { 23 | tree.setSafe(i,sc.nextInt()); 24 | } 25 | 26 | // loop to read pairs of children 27 | for (int i = 0; i < read1Integer ; i++) { 28 | tree.setNode(i,sc.nextInt(),sc.nextInt()); 29 | } 30 | 31 | 32 | 33 | } 34 | 35 | // Read in query statements 36 | public static void readQueries () { 37 | 38 | // read in one integer 39 | int read1Integer = sc.nextInt(); 40 | 41 | // loop to read pairs of children for query 42 | for (int i=0;i= 0) { 148 | if (!myTree[index].isSafe()) return false; 149 | else { 150 | if (index == target) return true; 151 | 152 | if (directPath(myTree[index].left(),target)) return true; 153 | else return directPath(myTree[index].right(),target); 154 | } 155 | } 156 | 157 | return false; 158 | } 159 | 160 | public boolean searchTree (int index, int target) { 161 | 162 | if (index >= 0) { 163 | if (index == target) return true; 164 | 165 | if (searchTree(myTree[index].left(),target)){ 166 | return false; 167 | } 168 | else{ 169 | return searchTree(myTree[index].right(),target); 170 | } 171 | } 172 | 173 | return false; 174 | } 175 | 176 | public void print (MyNode[] tree, int index) { 177 | 178 | if (index >= 0) { 179 | print(tree,tree[index].left()); 180 | 181 | System.out.print(index); 182 | if (!tree[index].isSafe()) System.out.print("*"); 183 | System.out.print(" "); 184 | 185 | print(tree,tree[index].right()); 186 | } 187 | 188 | } 189 | 190 | } 191 | -------------------------------------------------------------------------------- /tests/SSID_demo/04.java: -------------------------------------------------------------------------------- 1 | import java.util.*; 2 | 3 | /** 4 | * Driver class, you may have to change it to fit your implementation 5 | * Make sure you compile and run this class 6 | */ 7 | public class CitiesDriver { 8 | static Scanner sc; 9 | static MyTree tree; 10 | 11 | /** Read in the tree 12 | */ 13 | public static void readTree () { 14 | // Read in the tree 15 | // Read in size of the tree 16 | int n = sc.nextInt(); 17 | tree = new MyTree(n); //Create MyTree with n nodes 18 | // read in tree, safety line 19 | for (int i=0;i q; //Queue for BFS 108 | 109 | /* 110 | Fill up the tree with the nodes and set the size of the tree 111 | Even more boring stuff 112 | */ 113 | public MyTree(int n){ 114 | for (int i = 0; i < n; i++) 115 | myTree[i] = new MyNode(); 116 | size = n; 117 | } 118 | public void updateSafety(int node, int safe){ 119 | myTree[node].setIsSafe(safe == 1); 120 | } 121 | public void updateNode(int node, int left, int right){ 122 | myTree[node].setLeft(left); 123 | myTree[node].setRight(right); 124 | if (left != -1) 125 | myTree[left].setParent(node); 126 | if (right != -1) 127 | myTree[right].setParent(node); 128 | } 129 | /* 130 | In this problem, we are given a tree. Therefore, given any nodes u and v, there is only one unique path from u to v. 131 | This is because a tree is acyclic and all the nodes are connected. The question asks whether it is possible to find a 132 | "safe" path from nodes u to v. 133 | 134 | The easiest way to solve this problem would be to view the binary tree as a graph instead of a binary tree and run BFS/DFS 135 | on the tree. Personally I prefer coding BFS, hence I coded BFS. I used the binary tree structure as an adjacency list, where 136 | there is an edge from the current node to its left child, an edge from the current node to its right child and an edge from the 137 | current node to its parent. 138 | 139 | After running BFS, I recreate the path using the array pre[] (which stores the predecessor of the node) and check whether the 140 | path is safe. The runtime for BFS is O(N) for every query (where N is the size of binary tree). Suppose there are M queries, then 141 | it will take O(MN) to run all M queries. 142 | */ 143 | public boolean isPathSafe(int start, int end){ 144 | int[] pre = new int[size]; //Stores who is the pre of the current node in the path 145 | boolean[] visited = new boolean[size]; //To store whether the particular node is visited 146 | q = new LinkedList (); 147 | //Start of BFS 148 | q.offer(new Integer(start)); 149 | visited[start] = true; 150 | while (q.size()!=0){ 151 | int u = q.poll(); 152 | if (u == end) 153 | break; 154 | int left = myTree[u].getLeft(); 155 | int right = myTree[u].getRight(); 156 | int parent = myTree[u].getParent(); 157 | if (left != -1 && visited[left] == false){ 158 | visited[left] = true; 159 | q.offer(new Integer(left)); 160 | pre[left] = u; 161 | } 162 | if (right != -1 && visited[right] == false){ 163 | visited[right] = true; 164 | q.offer(new Integer(right)); 165 | pre[right] = u; 166 | } 167 | if (parent != -1 && visited[parent] == false){ 168 | visited[parent] = true; 169 | q.offer(new Integer(parent)); 170 | pre[parent] = u; 171 | } 172 | } 173 | int curnode = end; 174 | //If the path is safe, then logical and of all the nodes in the path will yield whether the path is safe 175 | boolean isSafe = myTree[start].getIsSafe(); 176 | while (curnode != start){ 177 | isSafe = myTree[curnode].getIsSafe() && isSafe; 178 | curnode = pre[curnode]; 179 | } 180 | return isSafe; 181 | } 182 | } 183 | -------------------------------------------------------------------------------- /tests/SSID_demo/05.java: -------------------------------------------------------------------------------- 1 | import java.util.*; 2 | 3 | /** 4 | * Driver class, you may have to change it to fit your implementation 5 | * Make sure you compile and run this class 6 | */ 7 | public class CitiesDriver { 8 | static Scanner sc; 9 | static MyTree tree; 10 | 11 | 12 | public static void main(String[] args) { 13 | sc = new Scanner(System.in); 14 | 15 | readTree(); // read in the tree 16 | readQ(); // read in the queries 17 | } 18 | 19 | 20 | 21 | /** Read in query statements 22 | */ 23 | public static void readQ () { 24 | // read in one integer 25 | int j = sc.nextInt(); 26 | // loop to read pairs of children for query 27 | for (int i=0;i q; //Queue for BFS 115 | 116 | /* 117 | Fill up the tree with the nodes and set the size of the tree 118 | Even more boring stuff 119 | */ 120 | 121 | public void updateNode(int node, int left, int right){ 122 | myTree[node].setLeft(left); 123 | myTree[node].setRight(right); 124 | if (left != -1) 125 | myTree[left].setParent(node); 126 | if (right != -1) 127 | myTree[right].setParent(node); 128 | } 129 | public MyTree(int n){ 130 | for (int i = 0; i < n; i++) 131 | myTree[i] = new MyNode(); 132 | size = n; 133 | } 134 | public void updateSafety(int node, int safe){ 135 | myTree[node].setIsSafe(safe == 1); 136 | } 137 | 138 | /* 139 | In this problem, we are given a tree. Therefore, given any nodes u and v, there is only one unique path from u to v. 140 | This is because a tree is acyclic and all the nodes are connected. The question asks whether it is possible to find a 141 | "safe" path from nodes u to v. 142 | 143 | The easiest way to solve this problem would be to view the binary tree as a graph instead of a binary tree and run BFS/DFS 144 | on the tree. Personally I prefer coding BFS, hence I coded BFS. I used the binary tree structure as an adjacency list, where 145 | there is an edge from the current node to its left child, an edge from the current node to its right child and an edge from the 146 | current node to its parent. 147 | 148 | After running BFS, I recreate the path using the array pre[] (which stores the predecessor of the node) and check whether the 149 | path is safe. The runtime for BFS is O(N) for every query (where N is the size of binary tree). Suppose there are M queries, then 150 | it will take O(MN) to run all M queries. 151 | */ 152 | public boolean isPathOk(int start, int end){ 153 | int[] pre = new int[size]; //Stores who is the pre of the current node in the path 154 | boolean[] visited = new boolean[size]; //To store whether the particular node is visited 155 | q = new LinkedList (); 156 | //Start of BFS 157 | q.offer(new Integer(start)); 158 | visited[start] = true; 159 | while (q.size()!=0){ 160 | int u = q.poll(); 161 | if (u == end) 162 | break; 163 | 164 | int right = myTree[u].getRight(); 165 | int left = myTree[u].getLeft(); 166 | int parent = myTree[u].getParent(); 167 | 168 | if (right != -1 && visited[right] == false){ 169 | visited[right] = true; 170 | q.offer(new Integer(right)); 171 | pre[right] = u; 172 | } 173 | if (left != -1 && visited[left] == false){ 174 | visited[left] = true; 175 | q.offer(new Integer(left)); 176 | pre[left] = u; 177 | } 178 | if (parent != -1 && visited[parent] == false){ 179 | visited[parent] = true; 180 | q.offer(new Integer(parent)); 181 | pre[parent] = u; 182 | } 183 | } 184 | int curnode = end; 185 | //If the path is safe, then logical and of all the nodes in the path will yield whether the path is safe 186 | boolean isSafe = myTree[start].getIsSafe(); 187 | while (curnode != start){ 188 | isSafe = myTree[curnode].getIsSafe() && isSafe; 189 | curnode = pre[curnode]; 190 | } 191 | return isSafe; 192 | } 193 | } 194 | -------------------------------------------------------------------------------- /tests/SSID_demo/06.java: -------------------------------------------------------------------------------- 1 | import java.util.*; 2 | 3 | 4 | public class CitiesDriver { 5 | static Scanner scanner; 6 | static MyTree tree; 7 | 8 | 9 | 10 | public static void readTree () { 11 | 12 | int n = scanner.nextInt(); 13 | tree = new MyTree(n); 14 | 15 | 16 | int i = 0; 17 | while(i q; 101 | 102 | 103 | public MyTree(int n){ 104 | for (int i = 0; i < n; i++) 105 | myTree[i] = new MyNode(); 106 | size = n; 107 | } 108 | public void updateSafety(int node, int safe){ 109 | myTree[node].setIsCitySafe(safe == 1); 110 | } 111 | public void updateNode(int node, int left, int right){ 112 | myTree[node].setLeft(left); 113 | myTree[node].setRight(right); 114 | if (left != -1) 115 | myTree[left].setParent(node); 116 | if (right != -1) 117 | myTree[right].setParent(node); 118 | } 119 | 120 | public boolean isPathSafe(int start, int end){ 121 | int[] pre = new int[size]; 122 | boolean[] visited = new boolean[size]; 123 | q = new LinkedList (); 124 | 125 | q.offer(new Integer(start)); 126 | visited[start] = true; 127 | while (q.size()!=0){ 128 | int u = q.poll(); 129 | if (u == end) 130 | break; 131 | int left = myTree[u].getLeft(); 132 | int right = myTree[u].getRight(); 133 | int parent = myTree[u].getParent(); 134 | if (left != -1 && visited[left] == false){ 135 | visited[left] = true; 136 | q.offer(new Integer(left)); 137 | pre[left] = u; 138 | } 139 | if (right != -1 && visited[right] == false){ 140 | visited[right] = true; 141 | q.offer(new Integer(right)); 142 | pre[right] = u; 143 | } 144 | if (parent != -1 && visited[parent] == false){ 145 | visited[parent] = true; 146 | q.offer(new Integer(parent)); 147 | pre[parent] = u; 148 | } 149 | } 150 | int curnode = end; 151 | 152 | boolean isCitySafe = myTree[start].isIsCitySafe(); 153 | while (curnode != start){ 154 | isCitySafe = myTree[curnode].isIsCitySafe() && isCitySafe; 155 | curnode = pre[curnode]; 156 | } 157 | return isCitySafe; 158 | } 159 | } 160 | -------------------------------------------------------------------------------- /tests/SSID_demo/07.java: -------------------------------------------------------------------------------- 1 | /** Class for a tree node 2 | */ 3 | class MyNode { 4 | // You may use this class if you'd like. It may help you if you use 5 | // an array based implementation of a binary tree 6 | 7 | // you can add other variables if you'd like 8 | boolean isSafe; // is the city safe? 9 | int leftChildIndex; // left child index in array 10 | int rightChildIndex; // right child index in array 11 | 12 | // fill in your accessor and mutator methods here 13 | // ... 14 | 15 | public MyNode( int i ) { 16 | if( i == 0 ) { 17 | isSafe = false; 18 | } else 19 | isSafe = true; 20 | } 21 | 22 | //accessors 23 | public int getLeft(){ 24 | return leftChildIndex; 25 | } 26 | 27 | public int getRight(){ 28 | return rightChildIndex; 29 | } 30 | 31 | //mutators 32 | public void setLeft(int left){ 33 | this.leftChildIndex = left; 34 | } 35 | 36 | public void setRight (int right){ 37 | this.rightChildIndex = right; 38 | } 39 | 40 | public boolean isSafe(){ 41 | return isSafe; 42 | } 43 | } 44 | 45 | /** Class for a binary tree ADT 46 | */ 47 | public class MyTree { 48 | // You may want to use an array based implementation for 49 | // your tree, or change this to another implementation 50 | 51 | // Note that this code and the driver code do not necessarily 52 | // match well -- you decide how you want these two parts to work 53 | // together. 54 | 55 | private final int MAX_NODES = 1000; 56 | MyNode[] myTree = new MyNode[MAX_NODES]; 57 | int size = 0; // make sure to update this variable as needed 58 | 59 | // fill in your ADT methods here 60 | // ... 61 | 62 | //insert the cities 63 | public void insert (int n, int leftIndex, int rightIndex){ 64 | myTree[size] = new MyNode(n); 65 | myTree[size].setLeft(leftIndex); 66 | myTree[size].setRight(rightIndex); 67 | size++; 68 | } 69 | 70 | //use recursive methods to find result 71 | public boolean queries(int depature, int arrive){ 72 | if (depature != arrive){ 73 | return queries(getParent(depature), 0)&& queries(getParent(arrive), 0)&& myTree[depature].isSafe && myTree[arrive].isSafe; 74 | } else return myTree[depature].isSafe; 75 | } 76 | 77 | /*public boolean allSafe(int depature, int root){ 78 | if (departure == root){ 79 | return myTree[0].isSafe; 80 | } else 81 | return myTree[departure].isSafe && allSafe(getParent(depature), myTree[0]); 82 | }*/ 83 | 84 | //method to find the parents of the city 85 | public int getParent(int city){ 86 | for (int i = city; i >=0; i --){ 87 | if(myTree[i].getRight() == city || myTree[i].getLeft() == city){ 88 | return i; 89 | } 90 | } 91 | //return 0 if no parent, meaning this city is the root 92 | return 0; 93 | } 94 | } 95 | 96 | import java.util.*; 97 | 98 | /** 99 | * Driver class, you may have to change it to fit your implementation 100 | * Make sure you compile and run this class 101 | */ 102 | public class CitiesDriver { 103 | static Scanner sc; 104 | //create all the array lists for storing all the input read 105 | static int [] cities; 106 | static int [] leftChild; 107 | static int [] rightChild; 108 | static int [] departCities; 109 | static int [] arriveCities; 110 | //initialize a Mytree instance 111 | static MyTree tree = new MyTree(); 112 | 113 | /** Read in the tree 114 | */ 115 | public static void readTree () { 116 | /// Read in the tree 117 | // read in one integer 118 | int n = sc.nextInt(); 119 | // read in tree, safety line 120 | 121 | cities = new int [n]; 122 | //read in the cities 123 | for (int i=0;i rep_ok 18 | 19 | let size s = 20 | List.length (rep_ok s) 21 | 22 | let insert x s = 23 | List.sort_uniq compare (x :: rep_ok s) |> rep_ok 24 | 25 | let member x s = 26 | List.mem x (rep_ok s) 27 | 28 | let remove x s = 29 | List.filter (fun y -> x <> y) (rep_ok s) |> rep_ok 30 | 31 | let choose s = 32 | match (rep_ok s) with 33 | | [] -> None 34 | | x :: xs -> Some x 35 | 36 | 37 | let to_list s = 38 | rep_ok s 39 | -------------------------------------------------------------------------------- /tests/test1/intset1.ml: -------------------------------------------------------------------------------- 1 | (* Abstraction Function: [[x_1, ..., x_n]] represents the set 2 | * ${x_1, ..., x_n}$. 3 | * Representation Invariant: [[x_1, ..., x_n]] must form a strictly increasing 4 | * sequence. That is, the list should be sorted with no duplicates. 5 | *) 6 | type t = 7 | int list 8 | 9 | let rep_ok s = 10 | if s = List.sort_uniq compare s then 11 | s 12 | else 13 | failwith "RI" 14 | 15 | 16 | let empty = 17 | [] |> rep_ok 18 | 19 | let size s = 20 | List.length (rep_ok s) 21 | 22 | let insert x s = 23 | List.sort_uniq compare (x :: rep_ok s) |> rep_ok 24 | 25 | let member x s = 26 | List.mem x (rep_ok s) 27 | 28 | let remove x s = 29 | List.filter (fun y -> x <> y) (rep_ok s) |> rep_ok 30 | 31 | let choose s = 32 | match (rep_ok s) with 33 | | [] -> None 34 | | x :: xs -> Some x 35 | 36 | 37 | let to_list s = 38 | rep_ok s 39 | -------------------------------------------------------------------------------- /tests/test10/add.ml: -------------------------------------------------------------------------------- 1 | let add x y = 2 | x+y 3 | -------------------------------------------------------------------------------- /tests/test10/add_test.ml: -------------------------------------------------------------------------------- 1 | open OUnit 2 | open Add 3 | 4 | let tests = "test suite for add" >::: [ 5 | "onetwo" >:: (fun _ -> assert_equal 3 (add 1 2)); 6 | "sevone" >:: (fun _ -> assert_equal 8 (add 7 1)); 7 | ] 8 | 9 | let _ = run_test_tt_main tests 10 | -------------------------------------------------------------------------------- /tests/test10/btrees.ml: -------------------------------------------------------------------------------- 1 | type 'a tree = Leaf | Node of 'a tree * 'a * 'a tree 2 | 3 | let rec preorder a = function 4 | | Leaf -> (match a with 5 | | [] -> [] 6 | | h::t -> preorder t h) 7 | | Node (l, v, r) -> v:: preorder (r::a) l 8 | 9 | let rec inorder a = function 10 | | Leaf -> [] 11 | | Node (Leaf, v, _) -> (match a with 12 | | [] -> [] 13 | | h::t -> v::inorder t h) 14 | | Node (l,v,r) -> inorder 15 | -------------------------------------------------------------------------------- /tests/test10/discussiongame.ml: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/RobYang1024/OCaMOSS/5a78137bf717d2bb8248489f0619a01ebea9d1df/tests/test10/discussiongame.ml -------------------------------------------------------------------------------- /tests/test10/hello.ml: -------------------------------------------------------------------------------- 1 | print_endline "Does this change something" 2 | -------------------------------------------------------------------------------- /tests/test10/lab03_test.ml: -------------------------------------------------------------------------------- 1 | open OUnit 2 | open Lab03 3 | 4 | let tests = "testing lab03" >::: [ 5 | "prod1" >:: (fun _ -> assert_equal 1 (mult [])); 6 | "prod2" >:: (fun _ -> assert_equal 24 (mult [1;2;3;4])); 7 | "prod3" >:: (fun _ -> assert_equal 60 (mult [3;4;5])); 8 | 9 | "bigred" >:: (fun _ -> assert_equal true (bigred ["bigred"; "i"])); 10 | "bigred1" >:: (fun _ -> assert_equal false (bigred [])); 11 | "bigred2" >:: (fun _ -> assert_equal false (bigred ["hello"])); 12 | 13 | "twoorfour3" >:: (fun _ -> assert_equal true (twoOrFour [1;2;3;4])); 14 | "twoorfour" >:: (fun _ -> assert_equal true (twoOrFour ["bigred"; "i"])); 15 | "twoorfour1" >:: (fun _ -> assert_equal false (twoOrFour [])); 16 | "twoorfour2" >:: (fun _ -> assert_equal false (twoOrFour ["hello"])); 17 | "twoorfour4" >:: (fun _ -> assert_equal false (twoOrFour [1;2;3;4;5;5])); 18 | 19 | "1" >:: (fun _ -> assert_equal true (twoEl [1;1;3])); 20 | "2" >:: (fun _ -> assert_equal false (twoEl [1;2;3])); 21 | "3" >:: (fun _ -> assert_equal false (twoEl [1;3])); 22 | "4" >:: (fun _ -> assert_equal false (twoEl [1])); 23 | "5" >:: (fun _ -> assert_equal true (twoEl [1;1])); 24 | 25 | 26 | 27 | 28 | 29 | 30 | ] 31 | 32 | let _ = run_test_tt_main tests 33 | -------------------------------------------------------------------------------- /tests/test11/Camel.txt: -------------------------------------------------------------------------------- 1 | A camel is an even-toed ungulate in the genus Camelus that bears distinctive fatty deposits known as "humps" on its back. Camels have long been domesticated and, as livestock, they provide food (milk and meat) and textiles (fiber and felt from hair). As working animals, camels—who are uniquely suited to their desert habitats—are a vital means of transport for passengers and cargo. There are three surviving species of camel. The one-humped dromedary makes up 94% of the world's camel population, and the two-humped Bactrian camel makes up the remainder. The Wild Bactrian camel is a separate species and is now critically endangered. 2 | The word camel is derived via Latin: camelus and Greek: κάμηλος (kamēlos) from Hebrew or Phoenician: gāmāl.[4][5] Used informally, "camel" (or, more correctly, "camelid") refers to any of the seven members of the family Camelidae: the dromedary, the Bactrian, and the wild Bactrian (the true camels) plus the llama, the alpaca, the guanaco, and the vicuña[6] (the "New World" camelids). 3 | -------------------------------------------------------------------------------- /tests/test11/CamelMaybeCopy.txt: -------------------------------------------------------------------------------- 1 | A camel is an even-toed ungulate in the genus Camelus that walks in deserts. Camels are domesticated and provide food and textiles from their hair. Camels are important forms of transportation through deserts. There are three species of camel. The one-humped dromedary, two-humped Bactrian camel, and the Wild Bactrian camel which is critically endangered. 2 | Camel comes from the Latin word: camelus and Greek: κάμηλος (kamēlos) from Hebrew or Phoenician: gāmāl. “Camelid” informally refers to any of the seven members of the family Camelidae: the dromedary, the Bactrian, the wild Bactrian, the llama, the alpaca, the guanaco, and the vicuña[6] (the "New World" camelids) 3 | Camels are pretty cool. They can do it all and are awesome. They also love functional programming. A lot! Their next mission is to take over the world using the enigma machine. 4 | -------------------------------------------------------------------------------- /tests/test11/Camelcopy.txt: -------------------------------------------------------------------------------- 1 | Camels are even-toed ungulate in the genus Camelus that bear distinctive fatty deposits known as "humps" on their backs. Camels provide food (milk and meat) and textiles. Camels are super awesome!!!!! Woohooo!. 2 | 3 | 4 | The word camel is derived via Latin: camelus and Greek: κάμηλος (kamēlos) from Hebrew or Phoenician: gāmāl. Camels are LITERALLY SO COOL!!!! Used informally, "camel" (or, more correctly, "camelid") refers to any of the seven members of the family Camelidae: the dromedary, the Bactrian, and the wild Bactrian plus the llama, the alpaca, the guanaco, and the vicuña[6] (the "New World" camelids). 5 | 6 | 7 | 8 | 9 | 10 | As working animals, camels—who are uniquely suited to their desert habitats—are a vital means of transport for passengers and cargo. CAMELS ARE AMAAAAAAAAAAAAAAAAAAAAAAAAAAZINGGGGGGGGGGGGGGG!!!!!!!!!!!!!!!!!! There are three surviving species of camel. The one-humped dromedary makes up 94% of the world's camel population, and the two-humped Bactrian camel makes up the remainder. The Wild Bactrian camel is a separate species and is now critically endangered. -------------------------------------------------------------------------------- /tests/test11/Camelcopy2.txt: -------------------------------------------------------------------------------- 1 | The word camel is derived via Latin: camelus and Greek: κάμηλος (kamēlos) from Hebrew or Phoenician: gāmāl.[4][5] A camel is an even-toed ungulate in the genus Camelus that bears distinctive fatty deposits known as "humps" on its back. Used informally, "camel" (or, more correctly, "camelid") refers to any of the seven members of the family Camelidae: the dromedary, the Bactrian, and the wild Bactrian (the true camels) plus the llama, the alpaca, the guanaco, and the vicuña[6] (the "New World" camelids). 2 | Camels have long been domesticated and, as livestock, they provide food (milk and meat) and textiles (fiber and felt from hair). As working animals, camels—who are uniquely suited to their desert habitats—are a vital means of transport for passengers and cargo. There are three surviving species of camel. The one-humped dromedary makes up 94% of the world's camel population, and the two-humped Bactrian camel makes up the remainder. The Wild Bactrian camel is a separate species and is now critically endangered. 3 | -------------------------------------------------------------------------------- /tests/test11/Camelcopy3.txt: -------------------------------------------------------------------------------- 1 | A camel is an even-toed ungulate in the genus Camelus that bears distinctive fatty deposits known as "humps" on its back. Camels have long been domesticated and, as livestock, they provide food (milk and meat) and textiles (fiber and felt from hair). As working animals, camels—who are uniquely suited to their desert habitats—are a vital means of transport for passengers and cargo. There are three surviving species of camel. The one-humped dromedary makes up 94% of the world's camel population, and the two-humped Bactrian camel makes up the remainder. The Wild Bactrian camel is a separate species and is now critically endangered. 2 | The word camel is derived via Latin: camelus and Greek: κάμηλος (kamēlos) from Hebrew or Phoenician: gāmāl.[4][5] Used informally, "camel" (or, more correctly, "camelid") refers to any of the seven members of the family Camelidae: the dromedary, the Bactrian, and the wild Bactrian (the true camels) plus the llama, the alpaca, the guanaco, and the vicuña[6] (the "New World" camelids). 3 | -------------------------------------------------------------------------------- /tests/test11/Camels.txt: -------------------------------------------------------------------------------- 1 | Camel camel camel camel camel. -------------------------------------------------------------------------------- /tests/test12/DumbAI.java: -------------------------------------------------------------------------------- 1 | package controller; 2 | 3 | import java.util.ArrayList; 4 | import java.util.List; 5 | 6 | import model.Board; 7 | import model.Game; 8 | import model.Location; 9 | import model.NotImplementedException; 10 | import model.Player; 11 | 12 | /** 13 | * A DumbAI is a Controller that always chooses the blank space with the 14 | * smallest column number from the row with the smallest row number. 15 | */ 16 | public class DumbAI extends Controller { 17 | 18 | public DumbAI(Player me) { 19 | super(me); 20 | // TODO Auto-generated constructor stub 21 | //throw new NotImplementedException(); 22 | } 23 | 24 | protected @Override Location nextMove(Game g) { 25 | // Note: Calling delay here will make the CLUI work a little more 26 | // nicely when competing different AIs against each other. 27 | 28 | // TODO Auto-generated method stub 29 | //throw new NotImplementedException(); 30 | 31 | Board b = g.getBoard(); 32 | // find available moves 33 | for (int row = 0;row 2 | #include 3 | #include "heaplib.h" 4 | #include 5 | #include 6 | #include 7 | #include 8 | #include 9 | 10 | /* Useful shorthand: casts a pointer to a (char *) before adding */ 11 | #define ADD_BYTES(base_addr, num_bytes) (((char *)(base_addr)) + (num_bytes)) 12 | 13 | typedef struct _block_info_t { 14 | unsigned int block_size; 15 | //unsigned int alloc_status; 16 | }block_info_t; 17 | 18 | void coalesceNext(block_info_t* block) { 19 | block_info_t * next_ptr = ((block_info_t *)ADD_BYTES(block, block->block_size)); 20 | if((next_ptr->block_size%2)==0) { 21 | block->block_size += next_ptr->block_size; 22 | } 23 | } 24 | 25 | /* See the .h for the advertised behavior of this library function. 26 | * These comments describe the implementation, not the interface. 27 | * 28 | * YOUR COMMENTS GO HERE. 29 | */ 30 | void hl_init(void *heap, unsigned int heap_size) { 31 | 32 | int start_offset = ((uintptr_t)(heap) % 8==0)?0:(8 - ((uintptr_t)(heap) % 8)); 33 | 34 | int * heap_size_val = (int *)(ADD_BYTES(heap, start_offset)); 35 | *heap_size_val = (heap_size - start_offset - 8); 36 | 37 | block_info_t * start_ptr = (block_info_t *)(ADD_BYTES(heap, start_offset+4)); 38 | start_ptr->block_size = heap_size - start_offset - 8; 39 | return; 40 | } 41 | 42 | /* See the .h for the advertised behavior of this library function. 43 | * These comments describe the implementation, not the interface. 44 | * 45 | * YOUR COMMENTS GO HERE. 46 | */ 47 | void *hl_alloc(void *heap, unsigned int block_size) { 48 | 49 | int start_offset = ((uintptr_t)(heap) % 8==0)?0:(8 - ((uintptr_t)(heap) % 8)); 50 | int heap_size = *((int *)(ADD_BYTES(heap, start_offset))); 51 | 52 | int bestSize = INT_MAX; 53 | block_info_t * bestBlock = NULL; 54 | 55 | block_info_t * current_ptr = (block_info_t *)(ADD_BYTES(heap, start_offset+4)); 56 | 57 | if(block_size==0){ 58 | return (void *)(current_ptr); 59 | } 60 | 61 | int totalSize = 0; 62 | 63 | while(totalSize<(heap_size)) { 64 | totalSize+=((current_ptr->block_size/2)*2); 65 | 66 | 67 | if((current_ptr->block_size >= (block_size + (8 - ((4+block_size)%8)) + 4))&&((current_ptr->block_size % 2) == 0)) { 68 | if(current_ptr->block_size < bestSize) { 69 | bestBlock = current_ptr; 70 | bestSize = current_ptr->block_size; 71 | } 72 | } 73 | if(totalSizeblock_size/2)*2))); 75 | } 76 | } 77 | 78 | if(!bestBlock) { 79 | return 0; 80 | } 81 | 82 | bestBlock->block_size+=1; 83 | 84 | if(bestBlock->block_size >= (4 + block_size + (8 - ((4 + block_size)%8)) + 8)) { 85 | 86 | block_info_t * splitBlock = (block_info_t *)(ADD_BYTES(bestBlock, 4 + block_size + (8 - (((4 +block_size)%8))))); 87 | splitBlock->block_size = ((bestSize/2)*2) - (block_size + (8 - (4+block_size)%8) + 4); 88 | 89 | bestBlock->block_size = block_size + (8 - (4+block_size)%8) + 5; 90 | 91 | if(current_ptr!=bestBlock) { 92 | coalesceNext(splitBlock); 93 | } 94 | 95 | } 96 | 97 | return ((void *)ADD_BYTES(bestBlock, 4)); 98 | } 99 | 100 | /* See the .h for the advertised behavior of this library function. 101 | * These comments describe the implementation, not the interface. 102 | * 103 | * YOUR COMMENTS GO HERE. 104 | */ 105 | void hl_release(void *heap, void *block) { 106 | 107 | if(block){ 108 | block_info_t * block_ptr = (block_info_t *)(ADD_BYTES(block, -4)); 109 | block_ptr->block_size = ((block_ptr->block_size/2)*2); 110 | 111 | int start_offset = ((uintptr_t)(heap) % 8==0)?0:(8 - ((uintptr_t)(heap) % 8)); 112 | int heap_size = *((int *)(ADD_BYTES(heap, start_offset))); 113 | 114 | int totalSize = 0; 115 | block_info_t * prev_ptr = NULL; 116 | block_info_t * current_ptr = (block_info_t *)(ADD_BYTES(heap, start_offset+4)); 117 | block_info_t * next_ptr = NULL; 118 | 119 | while(totalSize<(heap_size)) { 120 | totalSize+=((current_ptr->block_size/2)*2); 121 | if(((block_info_t *)(ADD_BYTES(current_ptr, 4)))==block) { 122 | break; 123 | } 124 | if (totalSize<(heap_size)) { 125 | prev_ptr = current_ptr; 126 | current_ptr = ((block_info_t *)(ADD_BYTES(current_ptr, ((current_ptr->block_size/2)*2)))); 127 | } 128 | } 129 | 130 | if(totalSizeblock_size/2)*2)))); 132 | } 133 | 134 | if(next_ptr) { 135 | coalesceNext(current_ptr); 136 | } 137 | 138 | if(prev_ptr) { 139 | 140 | if((prev_ptr->block_size%2) == 0) { 141 | coalesceNext(prev_ptr); 142 | } 143 | 144 | } 145 | 146 | } 147 | 148 | return; 149 | 150 | } 151 | 152 | /* See the .h for the advertised behavior of this library function. 153 | * These comments describe the implementation, not the interface. 154 | * 155 | * YOUR COMMENTS GO HERE. 156 | */ 157 | void *hl_resize(void *heap, void *block, unsigned int new_size) { 158 | 159 | if(!block) { 160 | return hl_alloc(heap, new_size); 161 | } 162 | block_info_t * block_ptr = (block_info_t *)(ADD_BYTES(block, -4)); 163 | int start_offset = ((uintptr_t)(heap) % 8==0)?0:(8 - ((uintptr_t)(heap) % 8)); 164 | int heap_size = *((int *)(ADD_BYTES(heap, start_offset))); 165 | 166 | int bestSize = INT_MAX; 167 | block_info_t * bestBlock = NULL; 168 | 169 | block_info_t * current_ptr = (block_info_t *)(ADD_BYTES(heap, start_offset+4)); 170 | //block_info_t * prev_ptr = NULL; 171 | 172 | //block_info_t * prev_block_ptr = NULL; 173 | 174 | int totalSize = 0; 175 | 176 | while(totalSize<(heap_size)) { 177 | totalSize+=((current_ptr->block_size/2)*2); 178 | 179 | if((current_ptr->block_size >= (new_size + (8 - ((4+new_size)%8)) + 4))&&(((current_ptr->block_size%2) == 0) 180 | ||(current_ptr == block_ptr))) { 181 | if(current_ptr->block_size < bestSize) { 182 | bestBlock = current_ptr; 183 | bestSize = current_ptr->block_size; 184 | } 185 | } 186 | 187 | if(current_ptr == block_ptr) { 188 | //prev_block_ptr = prev_ptr; 189 | } 190 | 191 | if(totalSizeblock_size/2)*2))); 194 | } 195 | } 196 | //printf("After the while loop\n"); 197 | if(!bestBlock) { 198 | return 0; 199 | } 200 | 201 | 202 | block_ptr->block_size = (block_ptr->block_size/2)*2; 203 | 204 | int content_copy_size = (((block_ptr->block_size-4) > new_size)?new_size:(block_ptr->block_size-4)); 205 | memmove(((void *)(ADD_BYTES(bestBlock, 4))), block, content_copy_size); 206 | 207 | //printf("After memmove\n"); 208 | 209 | bestBlock->block_size = ((bestBlock->block_size/2)*2)+1; 210 | 211 | if(bestBlock->block_size >= (4 + new_size + (8 - ((4+new_size)%8)) + 8)) { 212 | 213 | block_info_t * splitBlock = (block_info_t *)(ADD_BYTES(bestBlock, 4 + new_size + (8 - (((4 +new_size)%8))))); 214 | splitBlock->block_size = ((bestSize/2)*2) - (new_size + (8 - (4+new_size)%8) + 4); 215 | //printf("%d\n", bestSize); 216 | //printf("%d\n", splitBlock->block_size); 217 | 218 | bestBlock->block_size = new_size + (8 - (4+new_size)%8) + 5; 219 | //printf("%d\n", bestBlock->block_size); 220 | 221 | if(current_ptr!=bestBlock) { 222 | coalesceNext(splitBlock); 223 | } 224 | } 225 | /* 226 | if(bestBlock!= block_ptr) { 227 | if(block_ptr!=current_ptr) { 228 | coalesceNext(block_ptr); 229 | } 230 | 231 | if(prev_block_ptr) { 232 | if(prev_block_ptr->block_size%2==0) { 233 | coalesceNext(prev_block_ptr); 234 | } 235 | } 236 | } 237 | */ 238 | 239 | return ((void *)ADD_BYTES(bestBlock, 4)); 240 | } 241 | -------------------------------------------------------------------------------- /tests/test13/heaplib2.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include "heaplib.h" 4 | #include 5 | #include 6 | #include 7 | #include 8 | #include 9 | 10 | #define ADD_BYTES(base_addr, num_bytes) (((char *)(base_addr)) + (num_bytes)) 11 | 12 | typedef struct _block_info_t { 13 | unsigned int block_size; 14 | }block_info_t; 15 | 16 | void coalesceNext(block_info_t* block) { 17 | block_info_t * next_ptr = ((block_info_t *)ADD_BYTES(block, block->block_size)); 18 | if((next_ptr->block_size%2)==0) { 19 | block->block_size += next_ptr->block_size; 20 | } 21 | } 22 | 23 | void hl_init(void *heap, unsigned int heap_size) { 24 | 25 | int start_offset = ((uintptr_t)(heap) % 8==0)?0:(8 - ((uintptr_t)(heap) % 8)); 26 | 27 | int * heap_size_val = (int *)(ADD_BYTES(heap, start_offset)); 28 | *heap_size_val = (heap_size - start_offset - 8); 29 | 30 | block_info_t * start_ptr = (block_info_t *)(ADD_BYTES(heap, start_offset+4)); 31 | start_ptr->block_size = heap_size - start_offset - 8; 32 | return; 33 | } 34 | 35 | void *hl_alloc(void *heap, unsigned int block_size) { 36 | 37 | int start_offset = ((uintptr_t)(heap) % 8==0)?0:(8 - ((uintptr_t)(heap) % 8)); 38 | int heap_size = *((int *)(ADD_BYTES(heap, start_offset))); 39 | 40 | int bestSize = INT_MAX; 41 | block_info_t * bestBlock = NULL; 42 | 43 | block_info_t * current_ptr = (block_info_t *)(ADD_BYTES(heap, start_offset+4)); 44 | 45 | if(block_size==0){ 46 | return (void *)(current_ptr); 47 | } 48 | 49 | int totalSize = 0; 50 | 51 | while(totalSize<(heap_size)) { 52 | totalSize+=((current_ptr->block_size/2)*2); 53 | 54 | 55 | if((current_ptr->block_size >= (block_size + (8 - ((4+block_size)%8)) + 4))&&((current_ptr->block_size % 2) == 0)) { 56 | if(current_ptr->block_size < bestSize) { 57 | bestBlock = current_ptr; 58 | bestSize = current_ptr->block_size; 59 | } 60 | } 61 | if(totalSizeblock_size/2)*2))); 63 | } 64 | } 65 | 66 | if(!bestBlock) { 67 | return 0; 68 | } 69 | 70 | bestBlock->block_size+=1; 71 | 72 | if(bestBlock->block_size >= (4 + block_size + (8 - ((4 + block_size)%8)) + 8)) { 73 | 74 | block_info_t * splitBlock = (block_info_t *)(ADD_BYTES(bestBlock, 4 + block_size + (8 - (((4 +block_size)%8))))); 75 | splitBlock->block_size = ((bestSize/2)*2) - (block_size + (8 - (4+block_size)%8) + 4); 76 | 77 | bestBlock->block_size = block_size + (8 - (4+block_size)%8) + 5; 78 | 79 | if(current_ptr!=bestBlock) { 80 | coalesceNext(splitBlock); 81 | } 82 | 83 | } 84 | 85 | return ((void *)ADD_BYTES(bestBlock, 4)); 86 | } 87 | 88 | void hl_release(void *heap, void *block) { 89 | 90 | if(block){ 91 | block_info_t * block_ptr = (block_info_t *)(ADD_BYTES(block, -4)); 92 | block_ptr->block_size = ((block_ptr->block_size/2)*2); 93 | 94 | int start_offset = ((uintptr_t)(heap) % 8==0)?0:(8 - ((uintptr_t)(heap) % 8)); 95 | int heap_size = *((int *)(ADD_BYTES(heap, start_offset))); 96 | 97 | int totalSize = 0; 98 | block_info_t * prev_ptr = NULL; 99 | block_info_t * current_ptr = (block_info_t *)(ADD_BYTES(heap, start_offset+4)); 100 | block_info_t * next_ptr = NULL; 101 | 102 | while(totalSize<(heap_size)) { 103 | totalSize+=((current_ptr->block_size/2)*2); 104 | if(((block_info_t *)(ADD_BYTES(current_ptr, 4)))==block) { 105 | break; 106 | } 107 | if (totalSize<(heap_size)) { 108 | prev_ptr = current_ptr; 109 | current_ptr = ((block_info_t *)(ADD_BYTES(current_ptr, ((current_ptr->block_size/2)*2)))); 110 | } 111 | } 112 | 113 | if(totalSizeblock_size/2)*2)))); 115 | } 116 | 117 | if(next_ptr) { 118 | coalesceNext(current_ptr); 119 | } 120 | 121 | if(prev_ptr) { 122 | 123 | if((prev_ptr->block_size%2) == 0) { 124 | coalesceNext(prev_ptr); 125 | } 126 | } 127 | } 128 | return; 129 | 130 | } 131 | 132 | void *hl_resize(void *heap, void *block, unsigned int new_size) { 133 | 134 | if(!block) { 135 | return hl_alloc(heap, new_size); 136 | } 137 | block_info_t * block_ptr = (block_info_t *)(ADD_BYTES(block, -4)); 138 | int start_offset = ((uintptr_t)(heap) % 8==0)?0:(8 - ((uintptr_t)(heap) % 8)); 139 | int heap_size = *((int *)(ADD_BYTES(heap, start_offset))); 140 | 141 | int bestSize = INT_MAX; 142 | block_info_t * bestBlock = NULL; 143 | 144 | block_info_t * current_ptr = (block_info_t *)(ADD_BYTES(heap, start_offset+4)); 145 | 146 | int totalSize = 0; 147 | 148 | while(totalSize<(heap_size)) { 149 | totalSize+=((current_ptr->block_size/2)*2); 150 | 151 | if((current_ptr->block_size >= (new_size + (8 - ((4+new_size)%8)) + 4))&&(((current_ptr->block_size%2) == 0) 152 | ||(current_ptr == block_ptr))) { 153 | if(current_ptr->block_size < bestSize) { 154 | bestBlock = current_ptr; 155 | bestSize = current_ptr->block_size; 156 | } 157 | } 158 | 159 | if(current_ptr == block_ptr) { 160 | } 161 | 162 | if(totalSizeblock_size/2)*2))); 164 | } 165 | } 166 | if(!bestBlock) { 167 | return 0; 168 | } 169 | 170 | 171 | block_ptr->block_size = (block_ptr->block_size/2)*2; 172 | 173 | int content_copy_size = (((block_ptr->block_size-4) > new_size)?new_size:(block_ptr->block_size-4)); 174 | memmove(((void *)(ADD_BYTES(bestBlock, 4))), block, content_copy_size); 175 | 176 | bestBlock->block_size = ((bestBlock->block_size/2)*2)+1; 177 | 178 | if(bestBlock->block_size >= (4 + new_size + (8 - ((4+new_size)%8)) + 8)) { 179 | 180 | block_info_t * splitBlock = (block_info_t *)(ADD_BYTES(bestBlock, 4 + new_size + (8 - (((4 +new_size)%8))))); 181 | splitBlock->block_size = ((bestSize/2)*2) - (new_size + (8 - (4+new_size)%8) + 4); 182 | 183 | bestBlock->block_size = new_size + (8 - (4+new_size)%8) + 5; 184 | 185 | if(current_ptr!=bestBlock) { 186 | coalesceNext(splitBlock); 187 | } 188 | } 189 | 190 | return ((void *)ADD_BYTES(bestBlock, 4)); 191 | } 192 | -------------------------------------------------------------------------------- /tests/test15/all_subarray.cpp: -------------------------------------------------------------------------------- 1 | // https://www.geeksforgeeks.org/print-all-subarrays-with-sum-in-a-given-range/ 2 | #include 3 | using namespace std; 4 | 5 | // Function to find subarrrays in given range 6 | void subArraySum(int arr[], int n, 7 | int leftsum, int rightsum) 8 | { 9 | int curr_sum, i, j, res = 0; 10 | 11 | // Pick a starting point 12 | for (i = 0; i < n; i++) { 13 | curr_sum = arr[i]; 14 | 15 | // Try all subarrays starting with 'i' 16 | for (j = i + 1; j <= n; j++) { 17 | if (curr_sum > leftsum 18 | && curr_sum < rightsum) { 19 | cout << "{ "; 20 | 21 | for (int k = i; k < j; k++) 22 | cout << arr[k] << " "; 23 | 24 | cout << "}\n"; 25 | } 26 | if (curr_sum > rightsum || j == n) 27 | break; 28 | curr_sum = curr_sum + arr[j]; 29 | } 30 | } 31 | } 32 | 33 | // Driver Code 34 | int main() 35 | { 36 | int arr[] = { 15, 2, 4, 8, 9, 5, 10, 23 }; 37 | int N = sizeof(arr) / sizeof(arr[0]); 38 | 39 | int L = 10, R = 23; 40 | 41 | subArraySum(arr, N, L, R); 42 | 43 | return 0; 44 | } -------------------------------------------------------------------------------- /tests/test15/all_subarray_2.cpp: -------------------------------------------------------------------------------- 1 | // https://www.geeksforgeeks.org/print-all-subarrays-with-sum-in-a-given-range/ 2 | #include 3 | using namespace std; 4 | 5 | // Function to find subarrrays in given range 6 | void subArraySum(int arr[], int n, 7 | int left_sum, int right_sum) 8 | { 9 | int current_sum, i, j, res = 0; 10 | 11 | // Pick a starting point 12 | for (i = 0; i < n; i++) { 13 | current_sum = arr[i]; 14 | 15 | // Try all subarrays starting with 'i' 16 | for (j = i + 1; j <= n; j++) { 17 | if (current_sum > left_sum 18 | && current_sum < right_sum) { 19 | cout << "{ "; 20 | 21 | for (int k = i; k < j; k++) 22 | cout << arr[k] << " "; 23 | 24 | cout << "}\n"; 25 | } 26 | if (current_sum > right_sum || j == n) 27 | break; 28 | current_sum = current_sum + arr[j]; 29 | } 30 | } 31 | } 32 | 33 | // Driver Code 34 | int main() 35 | { 36 | int arr[] = { 15, 2, 4, 8, 9, 5, 10, 23 }; 37 | int N = sizeof(arr) / sizeof(arr[0]); 38 | 39 | int L = 10, R = 23; 40 | 41 | subArraySum(arr, N, L, R); 42 | 43 | return 0; 44 | } -------------------------------------------------------------------------------- /tests/test2/main.ml: -------------------------------------------------------------------------------- 1 | open Ast 2 | 3 | (* [is_value e] is whether [e] is a syntactic value *) 4 | let is_value : expr -> bool = function 5 | | Int _ | Bool _ -> true 6 | | Binop _ | Var _ | Let _ | If _ -> false 7 | 8 | (* [subst e v x] is e{v/x}, that is, [e] with [v] 9 | * substituted for [x]. *) 10 | let rec subst e v x = match e with 11 | | Var y -> if x=y then v else e 12 | | Bool b -> Bool b (* NEW *) 13 | | Int n -> Int n 14 | | Binop(op,el,er) -> Binop(op, subst el v x, subst er v x) (* NEW *) 15 | | Let(y,ebind,ebody) -> 16 | let ebind' = subst ebind v x in 17 | if x=y 18 | then Let(y, ebind', ebody) 19 | else Let(y, ebind', subst ebody v x) 20 | | If(eguard,ethen,eelse) -> (* NEW *) 21 | If(subst eguard v x, subst ethen v x, subst eelse v x) 22 | 23 | (* A single step of evaluation. *) 24 | let rec step = function 25 | | Int _ | Bool _ -> failwith "Does not step" 26 | | Var _ -> failwith "Unbound variable" 27 | | Binop(Plus, Int n1, Int n2) -> Int (n1+n2) (* NEW *) 28 | | Binop(Mult, Int n1, Int n2) -> Int (n1*n2) (* NEW *) 29 | | Binop(Leq, Int n1, Int n2) -> Bool (n1<=n2) (* NEW *) 30 | | Binop(op, Int n1, e2) -> Binop(op, Int n1, step e2) (* NEW *) 31 | | Binop(op, e1, e2) -> Binop(op, step e1, e2) 32 | | Let(x,Int n,e2) -> subst e2 (Int n) x 33 | | Let(x,Bool b,e2) -> subst e2 (Bool b) x 34 | | Let(x,e1,e2) -> Let(x,step e1, e2) 35 | | If(Bool true, e2, _) -> e2 36 | | If(Bool false, _, e3) -> e3 37 | | If(e1,e2,e3) -> If(step e1, e2, e3) 38 | 39 | (* [eval e] is the [e -->* v] judgement. That is, 40 | * keep applying [step] until a value is produced. *) 41 | let rec eval : expr -> expr = fun e -> 42 | if is_value e then e 43 | else eval (step e) 44 | 45 | (* Parse a string into an ast *) 46 | let parse s = 47 | let lexbuf = Lexing.from_string s in 48 | let ast = Parser.prog Lexer.read lexbuf in 49 | ast 50 | 51 | (* Extract a value from an ast node. 52 | Raises Failure if the argument is a node containing a value. *) 53 | let extract_value = function 54 | | Int i -> VInt i 55 | | Bool b -> VBool b (* NEW *) 56 | | _ -> failwith "Not a value" 57 | 58 | (* Interpret an expression *) 59 | let interp e = 60 | e |> parse |> eval |> extract_value 61 | 62 | 63 | 64 | -------------------------------------------------------------------------------- /tests/test2/main1.ml: -------------------------------------------------------------------------------- 1 | open Ast 2 | 3 | (* [is_value e] is whether [e] is a syntactic value *) 4 | let is_value : expr -> bool = function 5 | | I _ | B _ -> true 6 | | Bop _ | Var _ | Let _ | If _ -> false 7 | 8 | (* [subst e v x] is e{v/x}, that is, [e] with [v] 9 | * substituted for [x]. *) 10 | let rec subst e v x = match e with 11 | | Var y -> if x=y then v else e 12 | | B b -> B b (* NEW *) 13 | | I n -> I n 14 | | Bop(op,el,er) -> Bop(op, subst el v x, subst er v x) (* NEW *) 15 | | Let(y,ebind,ebody) -> 16 | let ebind' = subst ebind v x in 17 | if x=y 18 | then Let(y, ebind', ebody) 19 | else Let(y, ebind', subst ebody v x) 20 | | If(eguard,ethen,eelse) -> (* NEW *) 21 | If(subst eguard v x, subst ethen v x, subst eelse v x) 22 | 23 | (* A single step of evaluation. *) 24 | let rec step = function 25 | | I _ | B _ -> failwith "Does not step" 26 | | Var _ -> failwith "Unbound variable" 27 | | Bop(Plus, I n1, I n2) -> I (n1+n2) (* NEW *) 28 | | Bop(Mult, I n1, I n2) -> I (n1*n2) (* NEW *) 29 | | Bop(Leq, I n1, I n2) -> B (n1<=n2) (* NEW *) 30 | | Bop(op, I n1, e2) -> Bop(op, I n1, step e2) (* NEW *) 31 | | Bop(op, e1, e2) -> Bop(op, step e1, e2) 32 | | Let(x,I n,e2) -> subst e2 (I n) x 33 | | Let(x,B b,e2) -> subst e2 (B b) x 34 | | Let(x,e1,e2) -> Let(x,step e1, e2) 35 | | If(B true, e2, _) -> e2 36 | | If(B false, _, e3) -> e3 37 | | If(e1,e2,e3) -> If(step e1, e2, e3) 38 | 39 | (* [eval e] is the [e -->* v] judgement. That is, 40 | * keep applying [step] until a value is produced. *) 41 | let rec eval : expr -> expr = fun e -> 42 | if is_value e then e 43 | else eval (step e) 44 | 45 | (* Parse a string Io an ast *) 46 | let parse s = 47 | let lexbuf = Lexing.from_string s in 48 | let ast = Parser.prog Lexer.read lexbuf in 49 | ast 50 | 51 | (* Extract a value from an ast node. 52 | Raises Failure if the argument is a node containing a value. *) 53 | let extract_value = function 54 | | I i -> VI i 55 | | B b -> VB b (* NEW *) 56 | | _ -> failwith "Not a value" 57 | 58 | (* Interpret an expression *) 59 | let interp e = 60 | e |> parse |> eval |> extract_value 61 | 62 | 63 | 64 | -------------------------------------------------------------------------------- /tests/test3/labsoln.ml: -------------------------------------------------------------------------------- 1 | (******************************************************************** 2 | * exercise: list expressions 3 | ********************************************************************) 4 | 5 | let lst1 = [1;2;3;4;5] 6 | let lst2 = 1::2::3::4::5::[] 7 | let lst3 = [1]@[2;3;4]@[5] 8 | 9 | (******************************************************************** 10 | * exercise: product 11 | ********************************************************************) 12 | 13 | (* returns: the product of all the elements of [lst], or [1] if [lst] 14 | * is empty. 15 | *) 16 | let rec product lst = 17 | match lst with 18 | | [] -> 1 19 | | h::t -> h * product t 20 | 21 | (* Here's a simpler way to write that using the [function] syntactic sugar 22 | * discussed in the notes... 23 | *) 24 | let rec product' = function 25 | | [] -> 1 26 | | h::t -> h * product' t 27 | 28 | (******************************************************************** 29 | * exercise: bad add 30 | ********************************************************************) 31 | 32 | (* see the files add.ml and add_test.ml *) 33 | 34 | (******************************************************************** 35 | * exercise: patterns 36 | ********************************************************************) 37 | 38 | (* returns: whether the first element of the input is ["bigred"] 39 | *) 40 | let first_is_bigred = function 41 | | [] -> false 42 | | h::_ -> h = "bigred" 43 | 44 | (* returns: whether the input has exactly two or four elements 45 | *) 46 | let two_or_four_elements = function 47 | | _::_::[] -> true 48 | | _::_::_::_::[] -> true 49 | | _ -> false 50 | 51 | (* returns: whether the first two elements of the input are equal 52 | *) 53 | let eq_first_two = function 54 | | a::b::_ -> a = b 55 | | _ -> false 56 | 57 | (******************************************************************** 58 | * exercise: library 59 | ********************************************************************) 60 | 61 | (* returns: the fifth element of the input list, or zero if the 62 | * list is empty 63 | *) 64 | let fifth_element lst = 65 | if (List.length lst) >= 5 then List.nth lst 4 else 0 66 | 67 | (* returns: the input list, sorted in descending order 68 | *) 69 | let sort_list_descending lst = 70 | List.rev (List.sort Pervasives.compare lst) 71 | 72 | (* A more idiomatic way to write the above function is 73 | * with the pipeline operator. This makes use of 74 | * partial application with List.sort. 75 | *) 76 | let sort_list_descending' lst = 77 | lst |> List.sort Pervasives.compare |> List.rev 78 | 79 | (******************************************************************** 80 | * exercise: library puzzle 81 | ********************************************************************) 82 | 83 | (* returns: the last element of [lst] 84 | * requires: [lst] is nonempty 85 | *) 86 | let last_element lst = 87 | List.nth lst (List.length lst - 1) 88 | 89 | (* another solution... 90 | *) 91 | let last_element' lst = 92 | lst |> List.rev |> List.hd 93 | 94 | (* returns: whether [lst] contains any zeros 95 | *) 96 | let any_zeros lst = 97 | List.exists (fun x -> x = 0) lst 98 | 99 | (******************************************************************** 100 | * exercise: take drop 101 | ********************************************************************) 102 | 103 | (* returns: [take n lst] is the first [n] elements of [lst], or 104 | * just [lst] if [lst] has fewer than [n] elements. 105 | * requires: [n >= 0] 106 | *) 107 | let rec take n lst = 108 | if n = 0 then [] else match lst with 109 | | [] -> [] 110 | | x::xs -> x :: take (n-1) xs 111 | 112 | (* returns: [drop n lst] is all but the first [n] elements of [lst], 113 | * or just [[]] if [lst] has fewer than [n] elements. 114 | * requires: [n >= 0] 115 | *) 116 | let rec drop n lst = 117 | if n = 0 then lst else match lst with 118 | | [] -> [] 119 | | x::xs -> drop (n-1) xs 120 | 121 | (******************************************************************** 122 | * exercise: take drop tail 123 | ********************************************************************) 124 | 125 | (* returns: [take_rev n xs acc] is [lst1 @ acc], where [lst] is 126 | * the first [n] elements of [xs] (or just [xs] if [xs] has 127 | * fewer than [n] elements) in reverse order. 128 | * requires: [n >= 0] *) 129 | let rec take_rev n xs acc = 130 | if n = 0 then acc else match xs with 131 | | [] -> acc 132 | | x::xs' -> take_rev (n-1) xs' (x::acc) 133 | 134 | (* returns: [take n lst] is the first [n] elements of [lst], or 135 | * just [lst] if [lst] has fewer than [n] elements. 136 | * requires: [n >= 0] 137 | *) 138 | let take_tr n lst = 139 | take_rev n lst [] |> List.rev 140 | 141 | (* In the solution above, we factored out a helper function called 142 | * [take_rev]. It is tail recursive. The helper function takes 143 | * the same arguments as the original function, and one additional 144 | * argument [acc] called an *accumulator*. We accumulate the answer 145 | * in it, eventually returning it when either [xs] is empty 146 | * or [n] is 0. This is a general recipe one can follow in making 147 | * any recursive function be tail recursive. That same recipe was 148 | * followed in creating the definition of [(--)] below. *) 149 | 150 | (* the "natural" solution to [drop] above is already tail recursive *) 151 | let drop_tr = drop 152 | 153 | (* returns: [from i j l] is the list containing the integers from 154 | * [i] to [j], inclusive, followed by the list [l]. 155 | * example: [from 1 3 [0] = [1;2;3;0]] *) 156 | let rec from i j l = 157 | if i>j then l 158 | else from i (j-1) (j::l) 159 | 160 | (* returns: [i -- j] is the list containing the integers from 161 | * [i] to [j], inclusive. 162 | *) 163 | let (--) i j = 164 | from i j [] 165 | 166 | let longlist = 0 -- 1_000_000 167 | 168 | (* [take 1_000_000 longlist] should produce a stack overflow, 169 | * but [take_tr 1_000_000 longlist] should not. *) 170 | -------------------------------------------------------------------------------- /tests/test3/labsoln1.ml: -------------------------------------------------------------------------------- 1 | (******************************************************************** 2 | * exercise: list expressions 3 | ********************************************************************) 4 | 5 | let lst1 = [1;2;3;4;5] 6 | let lst2 = 1::2::3::4::5::[] 7 | let lst3 = [1]@[2;3;4]@[5] 8 | 9 | (******************************************************************** 10 | * exercise: bad add 11 | ********************************************************************) 12 | 13 | (* see the files add.ml and add_test.ml *) 14 | 15 | (******************************************************************** 16 | * exercise: patterns 17 | ********************************************************************) 18 | 19 | (* returns: whether the first element of the input is ["bigred"] 20 | *) 21 | let first_is_bigred = function 22 | | [] -> false 23 | | h::_ -> h = "bigred" 24 | 25 | (* returns: whether the input has exactly two or four elements 26 | *) 27 | let two_or_four_elements = function 28 | | _::_::[] -> true 29 | | _::_::_::_::[] -> true 30 | | _ -> false 31 | 32 | (* returns: whether the first two elements of the input are equal 33 | *) 34 | let eq_first_two = function 35 | | a::b::_ -> a = b 36 | | _ -> false 37 | 38 | (******************************************************************** 39 | * exercise: library 40 | ********************************************************************) 41 | 42 | (* returns: the fifth element of the input list, or zero if the 43 | * list is empty 44 | *) 45 | let fifth_element lst = 46 | if (List.length lst) >= 5 then List.nth lst 4 else 0 47 | 48 | (* returns: the input list, sorted in descending order 49 | *) 50 | let sort_list_descending lst = 51 | List.rev (List.sort Pervasives.compare lst) 52 | 53 | (* A more idiomatic way to write the above function is 54 | * with the pipeline operator. This makes use of 55 | * partial application with List.sort. 56 | *) 57 | let sort_list_descending' lst = 58 | lst |> List.sort Pervasives.compare |> List.rev 59 | 60 | (******************************************************************** 61 | * exercise: library puzzle 62 | ********************************************************************) 63 | 64 | (* returns: the last element of [lst] 65 | * requires: [lst] is nonempty 66 | *) 67 | let last_element lst = 68 | List.nth lst (List.length lst - 1) 69 | 70 | (* another solution... 71 | *) 72 | let last_element' lst = 73 | lst |> List.rev |> List.hd 74 | 75 | (* returns: whether [lst] contains any zeros 76 | *) 77 | let any_zeros lst = 78 | List.exists (fun x -> x = 0) lst 79 | 80 | (* returns: [take_rev n xs acc] is [lst1 @ acc], where [lst] is 81 | * the first [n] elements of [xs] (or just [xs] if [xs] has 82 | * fewer than [n] elements) in reverse order. 83 | * requires: [n >= 0] *) 84 | let rec take_rev n xs acc = 85 | if n = 0 then acc else match xs with 86 | | [] -> acc 87 | | x::xs' -> take_rev (n-1) xs' (x::acc) 88 | 89 | (******************************************************************** 90 | * exercise: take drop 91 | ********************************************************************) 92 | 93 | (* returns: [take n lst] is the first [n] elements of [lst], or 94 | * just [lst] if [lst] has fewer than [n] elements. 95 | * requires: [n >= 0] 96 | *) 97 | let rec take n lst = 98 | if n = 0 then [] else match lst with 99 | | [] -> [] 100 | | x::xs -> x :: take (n-1) xs 101 | 102 | (* returns: [drop n lst] is all but the first [n] elements of [lst], 103 | * or just [[]] if [lst] has fewer than [n] elements. 104 | * requires: [n >= 0] 105 | *) 106 | let rec drop n lst = 107 | if n = 0 then lst else match lst with 108 | | [] -> [] 109 | | x::xs -> drop (n-1) xs 110 | 111 | (******************************************************************** 112 | * exercise: take drop tail 113 | ********************************************************************) 114 | 115 | (* returns: [take n lst] is the first [n] elements of [lst], or 116 | * just [lst] if [lst] has fewer than [n] elements. 117 | * requires: [n >= 0] 118 | *) 119 | let take_tr n lst = 120 | take_rev n lst [] |> List.rev 121 | 122 | (* In the solution above, we factored out a helper function called 123 | * [take_rev]. It is tail recursive. The helper function takes 124 | * the same arguments as the original function, and one additional 125 | * argument [acc] called an *accumulator*. We accumulate the answer 126 | * in it, eventually returning it when either [xs] is empty 127 | * or [n] is 0. This is a general recipe one can follow in making 128 | * any recursive function be tail recursive. That same recipe was 129 | * followed in creating the definition of [(--)] below. *) 130 | 131 | (* the "natural" solution to [drop] above is already tail recursive *) 132 | let drop_tr = drop 133 | 134 | (* returns: [from i j l] is the list containing the integers from 135 | * [i] to [j], inclusive, followed by the list [l]. 136 | * example: [from 1 3 [0] = [1;2;3;0]] *) 137 | let rec from i j l = 138 | if i>j then l 139 | else from i (j-1) (j::l) 140 | 141 | (* returns: [i -- j] is the list containing the integers from 142 | * [i] to [j], inclusive. 143 | *) 144 | let (--) i j = 145 | from i j [] 146 | 147 | let longlist = 0 -- 1_000_000 148 | 149 | (* [take 1_000_000 longlist] should produce a stack overflow, 150 | * but [take_tr 1_000_000 longlist] should not. *) 151 | 152 | (******************************************************************** 153 | * exercise: product 154 | ********************************************************************) 155 | 156 | (* returns: the product of all the elements of [lst], or [1] if [lst] 157 | * is empty. 158 | *) 159 | let rec product lst = 160 | match lst with 161 | | [] -> 1 162 | | h::t -> h * product t 163 | 164 | (* Here's a simpler way to write that using the [function] syntactic sugar 165 | * discussed in the notes... 166 | *) 167 | let rec product' = function 168 | | [] -> 1 169 | | h::t -> h * product' t 170 | -------------------------------------------------------------------------------- /tests/test4/functions.ml: -------------------------------------------------------------------------------- 1 | (******************************************************************** 2 | * exercise: fib 3 | ********************************************************************) 4 | 5 | (* returns: element [n] of the Fibonacci sequence *) 6 | (* requires: [n >= 0] *) 7 | let rec fib n = 8 | if n = 0 then 0 9 | else if n = 1 then 1 10 | else fib (n-1) + fib (n-2) 11 | 12 | (******************************************************************** 13 | * exercise: fib fast 14 | ********************************************************************) 15 | 16 | (* requires: n > 0 *) 17 | (* returns: element [n] of the Fibonacci-like sequence, assuming 18 | * the first two elements are [pp] and [p]. *) 19 | let rec h n pp p = 20 | if n = 1 then p 21 | else h (n-1) p (pp+p) 22 | 23 | (* returns: element [n] of the Fibonacci sequence 24 | * requires: [n >= 0] *) 25 | let fib_fast n = 26 | if n=0 then 0 27 | else h n 0 1 28 | 29 | (* on a 64-bit OCaml implementation, fib_fast 91 overflows. *) 30 | 31 | (******************************************************************** 32 | * exercise: poly types 33 | ********************************************************************) 34 | 35 | let f x = if x then x else x 36 | (* bool -> bool *) 37 | (* x must be a bool to to be used as the conditional in the if expression *) 38 | 39 | let g x y = if y then x else x 40 | (* 'a -> bool -> 'a *) 41 | (* x could have any type *) 42 | 43 | let h x y z = if x then y else z 44 | (* bool -> 'a -> 'a -> 'a *) 45 | (* both branches of the if expression must have the same type, 46 | * so y and z must have the same type (which could be anything) *) 47 | 48 | let i x y z = if x then y else y 49 | (* bool -> 'a -> 'b -> 'a *) 50 | (* z could have any type, and moreover, that type could be different 51 | * than the type of y *) 52 | 53 | (******************************************************************** 54 | * exercise: divide 55 | ********************************************************************) 56 | 57 | let divide ~numerator:x ~denominator:y = x /. y 58 | 59 | (******************************************************************** 60 | * exercise: addx 61 | ********************************************************************) 62 | 63 | let addx x = fun y -> x + y 64 | (* int -> int -> int*) 65 | 66 | let add5 = addx 5 67 | (* int -> int *) 68 | (* [add 5 2] is equivalent to [fun y -> 5 y] 69 | so [add5 2] evaluates to 7 *) 70 | 71 | let add3 = addx 3 72 | (* int -> int *) 73 | (* add3 8 = 11 *) 74 | 75 | (******************************************************************** 76 | * exercise: associativity 77 | ********************************************************************) 78 | 79 | let add x y = x+y 80 | 81 | (* Only add (5 1) produces an error, because it tries to apply 82 | * the value 5 to the argument 1, but 5 is not a function, so it 83 | * cannot be applied. *) 84 | 85 | (******************************************************************** 86 | * exercise: average 87 | ********************************************************************) 88 | 89 | let ($$) a b = 90 | (a +. b) /. 2. 91 | -------------------------------------------------------------------------------- /tests/test4/functions1.ml: -------------------------------------------------------------------------------- 1 | (******************************************************************** 2 | * exercise: fib 3 | ********************************************************************) 4 | 5 | (* returns: element [n] of the Fibonacci sequence *) 6 | (* requires: [n >= 0] *) 7 | let rec fib n = 8 | if n = 0 then 0 9 | else if n = 1 then 1 10 | else fib (n-1) + fib (n-2) 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | (******************************************************************** 22 | * exercise: associativity 23 | ********************************************************************) 24 | 25 | let add x y = x+y 26 | 27 | (* Only add (5 1) produces an error, because it tries to apply 28 | * the value 5 to the argument 1, but 5 is not a function, so it 29 | * cannot be applied. *) 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | 42 | 43 | 44 | 45 | 46 | 47 | 48 | 49 | (******************************************************************** 50 | * exercise: poly types 51 | ********************************************************************) 52 | 53 | let f x = if x then x else x 54 | (* bool -> bool *) 55 | (* x must be a bool to to be used as the conditional in the if expression *) 56 | 57 | let g x y = if y then x else x 58 | (* 'a -> bool -> 'a *) 59 | (* x could have any type *) 60 | 61 | let h x y z = if x then y else z 62 | (* bool -> 'a -> 'a -> 'a *) 63 | (* both branches of the if expression must have the same type, 64 | * so y and z must have the same type (which could be anything) *) 65 | 66 | let i x y z = if x then y else y 67 | (* bool -> 'a -> 'b -> 'a *) 68 | (* z could have any type, and moreover, that type could be different 69 | * than the type of y *) 70 | 71 | (******************************************************************** 72 | * exercise: fib fast 73 | ********************************************************************) 74 | 75 | 76 | 77 | 78 | 79 | 80 | (* requires: n > 0 *) 81 | (* returns: element [n] of the Fibonacci-like sequence, assuming 82 | * the first two elements are [pp] and [p]. *) 83 | let rec h n pp p = 84 | if n = 1 then p 85 | else h (n-1) p (pp+p) 86 | 87 | (* returns: element [n] of the Fibonacci sequence 88 | * requires: [n >= 0] *) 89 | let fib_fast n = 90 | if n=0 then 0 91 | else h n 0 1 92 | 93 | (* on a 64-bit OCaml implementation, fib_fast 91 overflows. *) 94 | 95 | 96 | (******************************************************************** 97 | * exercise: divide 98 | ********************************************************************) 99 | 100 | let divide ~numerator:x ~denominator:y = x /. y 101 | 102 | (******************************************************************** 103 | * exercise: addx 104 | ********************************************************************) 105 | 106 | let addx x = fun y -> x + y 107 | (* int -> int -> int*) 108 | 109 | 110 | 111 | 112 | 113 | 114 | 115 | let add5 = addx 5 116 | (* int -> int *) 117 | (* [add 5 2] is equivalent to [fun y -> 5 y] 118 | so [add5 2] evaluates to 7 *) 119 | 120 | let add3 = addx 3 121 | (* int -> int *) 122 | (* add3 8 = 11 *) 123 | 124 | (******************************************************************** 125 | * exercise: average 126 | ********************************************************************) 127 | 128 | let ($$) a b = 129 | (a +. b) /. 2. 130 | -------------------------------------------------------------------------------- /tests/test5/queens_lazy.ml: -------------------------------------------------------------------------------- 1 | type 'a lval = 2 | | Val of 'a 3 | | Delayed of (unit -> 'a);; 4 | 5 | (* The forcing function. *) 6 | let force = function 7 | | Val v -> v 8 | | Delayed f -> f ();; 9 | 10 | (* The type of lazy lists. *) 11 | type 'a llist = 12 | | Nil 13 | | Cons of 'a lcell 14 | 15 | and 'a lcell = { mutable hd : 'a lval; mutable tl : 'a llist lval};; 16 | 17 | let ( *::* ) x y = Cons { hd = Delayed x; tl = Delayed y };; 18 | let ( -::* ) x y = Cons { hd = Val x; tl = Delayed y };; 19 | let ( -::- ) x y = Cons { hd = Val x; tl = Val y };; 20 | let ( --::* ) x y = Cons { hd = x; tl = Delayed y };; 21 | let ( --::-- ) x y = Cons { hd = x; tl = y };; 22 | 23 | let force_hd = function 24 | | Cons {hd = Val v} -> v 25 | | Cons ({hd = lv} as c) -> 26 | let v = force lv in 27 | c.hd <- Val v; 28 | v 29 | | Nil -> 30 | failwith "force_hd";; 31 | 32 | let force_tl = function 33 | | Cons {tl = Val v} -> v 34 | | Cons ({tl = lv} as c) -> 35 | let v = force lv in 36 | c.tl <- Val v; 37 | v; 38 | | Nil -> 39 | failwith "force_tl";; 40 | 41 | let force_hd = function 42 | | {hd = Val v} -> v 43 | | {hd = lv} as c -> 44 | let v = force lv in 45 | c.hd <- Val v; 46 | v;; 47 | 48 | let force_tl = function 49 | | {tl = Val v} -> v 50 | | {tl = lv} as c -> 51 | let v = force lv in 52 | c.tl <- Val v; 53 | v;; 54 | 55 | (* The corresponding functions and functionals: 56 | interval, map, filter_append, concmap. *) 57 | let rec map f = function 58 | | Nil -> Nil 59 | | Cons c -> 60 | f (force_hd c) -::* (fun () -> map f (force_tl c));; 61 | 62 | let rec iter f = function 63 | | Nil -> () 64 | | Cons c -> 65 | f (force_hd c); iter f (force_tl c);; 66 | 67 | let rec length = function 68 | | Nil -> 0 69 | | Cons c -> 70 | 1 + length (force_tl c);; 71 | 72 | let rec interval n m = 73 | if n > m then Nil else n -::* (fun () -> interval (n + 1) m);; 74 | 75 | let rec rev_append l1 l2 = 76 | match l1 with 77 | | Nil -> l2 78 | | Cons { hd = x; tl = l} -> 79 | x --::* (fun () -> rev_append (force l) l2);; 80 | 81 | let rec filter_append p l l0 = 82 | match (l : 'a llist) with 83 | | Nil -> l0 84 | | Cons c -> 85 | let x = force_hd c in 86 | if p x then x -::* (fun () -> filter_append p (force_tl c) l0) 87 | else filter_append p (force_tl c) l0;; 88 | 89 | let rec concmap f = function 90 | | Nil -> Nil 91 | | Cons c -> 92 | f (force_hd c) 93 | (concmap f (force_tl c));; 94 | 95 | let rec safe x d = function 96 | | Nil -> true 97 | | Cons { hd = h; tl = t} -> 98 | let h = force h in 99 | x <> h && x <> h + d && x <> h - d && safe x (d + 1) (force t);; 100 | 101 | let rec ok = function 102 | | Nil -> true 103 | | Cons { hd = h; tl = t} -> 104 | safe (force h) 1 (force t);; 105 | 106 | let find_solutions size = 107 | let line = interval 1 size in 108 | let rec gen n size = 109 | if n = 0 then Nil -::- Nil else 110 | concmap 111 | (fun b -> filter_append ok (map (fun q -> q -::- b) line)) 112 | (gen (n - 1) size) in 113 | gen size size;; 114 | 115 | (* 2. Printing results. *) 116 | 117 | let print_solutions size solutions = 118 | let sol_num = ref 1 in 119 | iter 120 | (fun chess -> 121 | Printf.printf "\nSolution number %i\n" !sol_num; 122 | sol_num := !sol_num + 1; 123 | iter 124 | (fun line -> 125 | let count = ref 1 in 126 | while !count <= size do 127 | if !count = line then print_string "Q " else print_string "- "; 128 | count := !count + 1 129 | done; 130 | print_newline ()) 131 | chess) 132 | solutions;; 133 | 134 | let print_number_of_solutions size sols = 135 | let sol_num = length sols in 136 | Printf.printf "The %i queens problem has %i solutions.\n" size sol_num;; 137 | 138 | let print_result size = 139 | let sols = find_solutions size in 140 | print_number_of_solutions size sols; 141 | print_newline (); 142 | let pr = 143 | print_string "Do you want to see the solutions ? "; read_line () in 144 | if pr = "y" then print_solutions size sols;; 145 | 146 | (* 3. Main program. *) 147 | 148 | let queens () = 149 | let size = 150 | print_string "Chess boards's size ? "; read_int () in 151 | print_result size;; 152 | 153 | if !Sys.interactive then queens () else 154 | let size = 155 | if Array.length Sys.argv <> 2 then 8 else (int_of_string Sys.argv.(1)) in 156 | let sols = find_solutions size in 157 | print_number_of_solutions size sols;; 158 | -------------------------------------------------------------------------------- /tests/test5/queens_tail.ml: -------------------------------------------------------------------------------- 1 | open List;; 2 | 3 | let map f l = 4 | let rec loop accu = function 5 | | [] -> accu 6 | | x :: l -> loop (f x :: accu) l in 7 | loop [] l;; 8 | 9 | let rec interval n m = 10 | if n > m then [] else n :: interval (n + 1) m;; 11 | 12 | let rev_append l1 l2 = 13 | let rec loop accu = function 14 | | [] -> accu 15 | | h :: t -> loop (h :: accu) t in 16 | loop l2 l1;; 17 | 18 | let filter_append p l l0 = 19 | let rec loop accu = function 20 | | [] -> accu 21 | | h :: t -> if p h then loop (h :: accu) t else loop accu t in 22 | let rev_res = loop [] l in 23 | rev_append rev_res l0;; 24 | 25 | let concmap f l = 26 | let rec loop accu = function 27 | | [] -> accu 28 | | h :: t -> loop (f h accu) t in 29 | loop [] l;; 30 | 31 | let rec safe x d = function 32 | | [] -> true 33 | | h :: t -> 34 | x <> h && x <> h + d && x <> h - d && safe x (d + 1) t;; 35 | 36 | let rec ok = function 37 | | [] -> true 38 | | h :: t -> safe h 1 t;; 39 | 40 | let find_solutions size = 41 | let line = interval 1 size in 42 | let rec gen n size = 43 | if n = 0 then [[]] else 44 | concmap 45 | (fun b -> filter_append ok (map (fun q -> q :: b) line)) 46 | (gen (n - 1) size) in 47 | gen size size;; 48 | 49 | (* 2. Printing results. *) 50 | 51 | let print_solutions size solutions = 52 | let sol_num = ref 1 in 53 | iter 54 | (fun chess -> 55 | Printf.printf "\nSolution number %i\n" !sol_num; 56 | sol_num := !sol_num + 1; 57 | iter 58 | (fun line -> 59 | let count = ref 1 in 60 | while !count <= size do 61 | if !count = line then print_string "Q " else print_string "- "; 62 | count := !count + 1 63 | done; 64 | print_newline ()) 65 | chess) 66 | solutions;; 67 | 68 | let print_result size = 69 | let solutions = find_solutions size in 70 | let sol_num = List.length solutions in 71 | Printf.printf "The %i queens problem has %i solutions.\n" size sol_num; 72 | print_newline (); 73 | let pr = 74 | print_string "Do you want to see the solutions ? "; read_line () in 75 | if pr = "y" then print_solutions size solutions;; 76 | 77 | (* 3. Main program. *) 78 | 79 | let queens () = 80 | let size = 81 | print_string "Chess boards's size ? "; read_int () in 82 | print_result size;; 83 | 84 | if !Sys.interactive then () else queens ();; -------------------------------------------------------------------------------- /tests/test6/kmp.ml: -------------------------------------------------------------------------------- 1 | let init_next p = 2 | let m = String.length p in 3 | let next = Array.create m 0 in 4 | let i = ref 1 and j = ref 0 in 5 | while !i < m - 1 do 6 | if p.[!i] = p.[!j] then begin incr i; incr j; next.(!i) <- !j end else 7 | if !j = 0 then begin incr i; next.(!i) <- 0 end else j := next.(!j) 8 | done; 9 | next;; 10 | 11 | let kmp p = 12 | let next = init_next p 13 | and m = String.length p in 14 | function s -> 15 | let n = String.length s 16 | and i = ref 0 17 | and j = ref 0 in 18 | while !j < m && !i < n do 19 | if s.[!i] = p.[!j] then begin incr i; incr j end else 20 | if !j = 0 then incr i else j := next.(!j) 21 | done; 22 | if !j >= m then !i - m else raise Not_found;; 23 | 24 | let find_pat p s = 25 | try 26 | let i = kmp p s in 27 | print_string "Match found at character "; 28 | print_int i; 29 | print_newline (); 30 | exit 0 31 | with Not_found -> 32 | print_string "Pattern "; 33 | print_string p; 34 | print_string " does not match string "; 35 | print_string s; 36 | print_newline (); 37 | exit 2;; 38 | 39 | let usage () = 40 | print_string 41 | "Usage: kmp \n\ 42 | returns the index of the first occurrence of in string \n"; 43 | exit 2;; 44 | 45 | let main () = 46 | let args = Sys.argv in 47 | if Array.length args < 2 then usage () else 48 | let p = Sys.argv.(1) 49 | and s = Sys.argv.(2) in 50 | find_pat p s;; 51 | 52 | if !Sys.interactive then () else main ();; -------------------------------------------------------------------------------- /tests/test6/strpos.ml: -------------------------------------------------------------------------------- 1 | let find_sub_string p s = 2 | let plen = String.length p in 3 | if plen = 0 then 0 else 4 | let slen = String.length s in 5 | if slen = 0 then raise Not_found else 6 | let rec find c i = 7 | if i >= slen then raise Not_found else 8 | if s.[i] = c then find_rest c 1 (i + 1) else find c (i + 1) 9 | and find_rest c j i = 10 | if j >= plen then (i - plen) else 11 | if i >= slen then raise Not_found else 12 | if p.[j] = s.[i] then find_rest c (j + 1) (i + 1) else 13 | find c (i + 1 - j) in 14 | find p.[0] 0;; 15 | 16 | let find_pat p s = 17 | try 18 | let i = find_sub_string p s in 19 | print_string "Match found at character "; 20 | print_int i; 21 | print_newline (); 22 | exit 0 23 | with Not_found -> 24 | print_string "Pattern "; 25 | print_string p; 26 | print_string " does not match string "; 27 | print_string s; 28 | print_newline (); 29 | exit 2;; 30 | 31 | let usage () = 32 | print_string 33 | "Usage: strstr2 \n\ 34 | returns the index of the first occurrence of in string \n"; 35 | exit 2;; 36 | 37 | let main () = 38 | let args = Sys.argv in 39 | if Array.length args < 2 then usage () else 40 | let p = Sys.argv.(1) 41 | and s = Sys.argv.(2) in 42 | find_pat p s;; 43 | 44 | if !Sys.interactive then () else main ();; -------------------------------------------------------------------------------- /tests/test7/strpos.ml: -------------------------------------------------------------------------------- 1 | let find_sub_string p s = 2 | let plen = String.length p in 3 | if plen = 0 then 0 else 4 | let slen = String.length s in 5 | if slen = 0 then raise Not_found else 6 | let rec find c i = 7 | if i >= slen then raise Not_found else 8 | if s.[i] = c then find_rest c 1 (i + 1) else find c (i + 1) 9 | and find_rest c j i = 10 | if j >= plen then (i - plen) else 11 | if i >= slen then raise Not_found else 12 | if p.[j] = s.[i] then find_rest c (j + 1) (i + 1) else 13 | find c (i + 1 - j) in 14 | find p.[0] 0;; 15 | 16 | let find_pat p s = 17 | try 18 | let i = find_sub_string p s in 19 | print_string "Match found at character "; 20 | print_int i; 21 | print_newline (); 22 | exit 0 23 | with Not_found -> 24 | print_string "Pattern "; 25 | print_string p; 26 | print_string " does not match string "; 27 | print_string s; 28 | print_newline (); 29 | exit 2;; 30 | 31 | let usage () = 32 | print_string 33 | "Usage: strstr2 \n\ 34 | returns the index of the first occurrence of in string \n"; 35 | exit 2;; 36 | 37 | let main () = 38 | let args = Sys.argv in 39 | if Array.length args < 2 then usage () else 40 | let p = Sys.argv.(1) 41 | and s = Sys.argv.(2) in 42 | find_pat p s;; 43 | 44 | if !Sys.interactive then () else main ();; -------------------------------------------------------------------------------- /tests/test7/strpos2.ml: -------------------------------------------------------------------------------- 1 | 2 | 3 | let usage () = 4 | print_string 5 | "Usage: strstr2 \n\ 6 | returns the index of the first occurrence of in string \n"; 7 | exit 2;; 8 | 9 | let main () = 10 | let args = Sys.argv in 11 | if Array.length args < 2 then usage () else 12 | let p = Sys.argv.(1) 13 | and s = Sys.argv.(2) in 14 | find_pat p s;; 15 | 16 | if !Sys.interactive then () else main ();; 17 | 18 | let find_pat p s = 19 | try 20 | let i = find_sub_string p s in 21 | print_string "Match found at character "; 22 | print_int i; 23 | print_newline (); 24 | exit 0 25 | with Not_found -> 26 | print_string "Pattern "; 27 | print_string p; 28 | print_string " does not match string "; 29 | print_string s; 30 | print_newline (); 31 | exit 2;; 32 | 33 | 34 | 35 | 36 | 37 | let find_sub_string p s = 38 | let plen = String.length p in 39 | if plen = 0 then 0 else 40 | let slen = String.length s in 41 | if slen = 0 then raise Not_found else 42 | let rec find c i = 43 | if i >= slen then raise Not_found else 44 | if s.[i] = c then find_rest c 1 (i + 1) else find c (i + 1) 45 | and find_rest c j i = 46 | if j >= plen then (i - plen) else 47 | if i >= slen then raise Not_found else 48 | if p.[j] = s.[i] then find_rest c (j + 1) (i + 1) else 49 | find c (i + 1 - j) in 50 | find p.[0] 0;; -------------------------------------------------------------------------------- /tests/test8/lab03.ml: -------------------------------------------------------------------------------- 1 | let rec mult x = 2 | match x with 3 | | [] -> 1 4 | | h::t -> h * mult t 5 | 6 | let rec stringadd x = 7 | match x with 8 | | [] -> "" 9 | | h::t -> h ^ stringadd t 10 | 11 | let bigred x = 12 | match x with 13 | | [] -> false 14 | | h::t -> if h = "bigred" then true else false 15 | 16 | let rec twoOrFour_helper x acc = 17 | match x with 18 | | [] -> if acc = 2 || acc = 4 then true else false 19 | | h::t -> twoOrFour_helper t (acc+1) 20 | 21 | let twoOrFour x = twoOrFour_helper x 0 22 | 23 | let twoEl x = 24 | match x with 25 | | [] -> false 26 | | h::[] -> false 27 | | h::h1::t -> if h=h1 then true else false 28 | 29 | let fifth x = 30 | match x with 31 | | [] -> 0 32 | | h::t -> if List.length x <5 then 0 else List.nth x 5 33 | 34 | let backsort x = List.rev (List.sort Pervasives.compare x) 35 | 36 | let last x = List.nth x (List.length x - 1) 37 | 38 | let has0 x = List.exists (fun x -> x=0) x 39 | 40 | let rec take n x y size = 41 | match x with 42 | | [] -> y 43 | | h::t -> if n = size then y else take n t (List.append y [h]) (size + 1) 44 | 45 | let rec drop n x size = 46 | match x with 47 | | [] -> x 48 | | h::t -> if n = size then x else drop n t (size + 1) 49 | 50 | (* returns: [from i j l] is the list containing the integers from 51 | * [i] to [j], inclusive, followed by the list [l]. 52 | * example: [from 1 3 [0] = [1;2;3;0]] *) 53 | let rec from i j l = 54 | if i>j then l 55 | else from i (j-1) (j::l) 56 | 57 | (* returns: [i -- j] is the list containing the integers from 58 | * [i] to [j], inclusive. 59 | *) 60 | let (--) i j = 61 | from i j [] 62 | -------------------------------------------------------------------------------- /tests/test8/lab031.ml: -------------------------------------------------------------------------------- 1 | (*function/variable names changed from lab03 and order of functions changed*) 2 | 3 | let bagreed i = 4 | match i with 5 | | [] -> false 6 | | h::t -> if h = "bigred" then true else false 7 | 8 | (* returns: [from i j l] is the list containing the integers from 9 | * [i] to [j], inclusive, followed by the list [l]. 10 | * example: [from 1 3 [0] = [1;2;3;0]] *) 11 | let rec froooom i j l = 12 | if i>j then l 13 | else froooom i (j-1) (j::l) 14 | 15 | (* returns: [i -- j] is the list containing the integers from 16 | * [i] to [j], inclusive. 17 | *) 18 | let (--) i j = 19 | froooom i j [] 20 | 21 | let rec twoOr4_hulper x acc = 22 | match x with 23 | | [] -> if acc = 2 || acc = 4 then true else false 24 | | h::t -> twoOr4_hulper t (acc+1) 25 | 26 | let rec drap n x size = 27 | match x with 28 | | [] -> x 29 | | h::t -> if n = size then x else drap n t (size + 1) 30 | 31 | let twoOrFour x = twoOr4_hulper x 0 32 | 33 | let twoEl x = 34 | match x with 35 | | [] -> false 36 | | h::[] -> false 37 | | h::h1::t -> if h=h1 then true else false 38 | 39 | let fifth x = 40 | match x with 41 | | [] -> 0 42 | | h::t -> if List.length x <5 then 0 else List.nth x 5 43 | 44 | let rec malt z = 45 | match z with 46 | | [] -> 1 47 | | h::t -> h * malt t 48 | 49 | let rec strongidd wow = 50 | match wow with 51 | | [] -> "" 52 | | h::t -> h ^ strongidd t 53 | 54 | let backsort x = List.rev (List.sort Pervasives.compare x) 55 | 56 | let last x = List.nth x (List.length x - 1) 57 | 58 | let has0 x = List.exists (fun x -> x=0) x 59 | 60 | let rec take n x y size = 61 | match x with 62 | | [] -> y 63 | | h::t -> if n = size then y else take n t (List.append y [h]) (size + 1) 64 | -------------------------------------------------------------------------------- /tests/test8/lab032.ml: -------------------------------------------------------------------------------- 1 | (*exact replica of lab031 with extra spaces and indents*) 2 | 3 | let bagreed i = 4 | match i with 5 | 6 | | [] -> false 7 | | h:: t -> if h = "bigred" then true else false 8 | 9 | (* returns: [from i j l] is the list containing the integers from 10 | * [i] to [j], inclusive, followed by the list [l]. 11 | * example: [from 1 3 [0] = [1;2;3;0]] *) 12 | let rec froooom i j l = 13 | if i>j then l 14 | 15 | 16 | 17 | 18 | else froooom i (j-1) (j::l) 19 | 20 | (* returns: [i -- j] is the list containing the integers from 21 | * [i] to [j], inclusive. 22 | *) 23 | let (--) i j = 24 | froooom i j [] 25 | 26 | let rec twoOr4_hulper x acc = 27 | match x with 28 | | [] -> if acc = 2 || acc = 4 then true else false 29 | | h::t -> twoOr4_hulper t (acc+1 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | 42 | 43 | 44 | 45 | 46 | ) 47 | 48 | let rec drap n x size = 49 | match x with 50 | | [ ] -> 51 | 52 | 53 | 54 | 55 | 56 | 57 | x 58 | | h::t -> if n = size then x else drap n t (size + 1) 59 | 60 | let twoOrFour x = twoOr4_hulper x 0 61 | 62 | let twoEl x = 63 | match x with 64 | | [] -> false 65 | | h::[] -> false 66 | | h::h1::t -> if h=h1 then true else false 67 | 68 | let fifth x = 69 | match x with 70 | | [] -> 0 71 | | h::t 72 | 73 | 74 | 75 | -> if List.length x <5 then 0 else List.nth x 5 76 | 77 | let rec malt z = 78 | match z with 79 | | [] -> 1 80 | | h::t -> h * malt t 81 | 82 | let rec strongidd wow = 83 | match wow with 84 | | [] -> "" 85 | | h::t -> h ^ strongidd t 86 | 87 | let backsort x = List.rev (List.sort Pervasives.compare x) 88 | 89 | let last x = List.nth x (List.length x - 1) 90 | 91 | let has0 x = List.exists (fun x -> x=0) x 92 | 93 | let rec take n x y size = 94 | match x with 95 | | [] -> y 96 | 97 | | h::t -> if n = size then y 98 | 99 | 100 | else take n t (List.append y [h]) (size + 1) 101 | -------------------------------------------------------------------------------- /tests/test8/lab033.ml: -------------------------------------------------------------------------------- 1 | (* More function/varuable names and orders changed. Add random rec declarations 2 | and get rid of lines for matching*) 3 | let bagreed i = 4 | match i with 5 | [] -> false 6 | | h::t -> if h = "bigred" then true else false 7 | 8 | (* returns: [from i j l] is the list containing the integers from 9 | * [i] to [j], inclusive, followed by the list [l]. 10 | * example: [from 1 3 [0] = [1;2;3;0]] *) 11 | let rec froooom i j l = 12 | if i>j then l 13 | else froooom i (j-1) (j::l) 14 | 15 | (* returns: [i -- j] is the list containing the integers from 16 | * [i] to [j], inclusive. 17 | *) 18 | let (--) i j = 19 | froooom i j [] 20 | 21 | let rec twoOr4_hulper x acc = 22 | match x with 23 | [] -> if acc = 2 || acc = 4 then true else false 24 | | h::t -> twoOr4_hulper t (acc+1) 25 | 26 | let rec drap n x size = 27 | match x with 28 | | [] -> x 29 | | h::t -> if n = size then x else drap n t (size + 1) 30 | 31 | let twoOrFour x = twoOr4_hulper x 0 32 | 33 | let twoEl x = 34 | match x with 35 | | [] -> false 36 | | h::[] -> false 37 | | h::h1::t -> if h=h1 then true else false 38 | 39 | let fifth x5x5x = 40 | match x5x5x with 41 | | [] -> 0 42 | | h::t -> if List.length x5x5x <5 then 0 else List.nth x5x5x 5 43 | 44 | let rec malt z = 45 | match z with 46 | | [] -> 1 47 | | h::t -> h * malt t 48 | 49 | let rec strongidd wow = 50 | match wow with 51 | | [] -> "" 52 | | r::m -> r ^ strongidd m 53 | 54 | let backsort x = List.rev (List.sort Pervasives.compare x) 55 | 56 | let last x = List.nth x (List.length x - 1) 57 | 58 | let hasssss0 x = List.exists (fun x -> x=0) x 59 | 60 | let rec take n x y size = 61 | match x with 62 | | [] -> y 63 | | s::l -> if n = size then y else take n l (List.append y [s]) (size + 1) 64 | -------------------------------------------------------------------------------- /tests/test8/lab034.ml: -------------------------------------------------------------------------------- 1 | let rec mult x = 2 | x*x 3 | 4 | let rec stringadd x = 5 | x^x 6 | 7 | let bigred x = 8 | x ^ "red" ^ x 9 | 10 | let rec twoOrFour_helper x acc = 11 | x + acc 12 | 13 | let twoOrFour x = twoOrFour_helper x 0 14 | 15 | let twoEl x = 16 | 908 17 | 18 | let fifth x = 19 | x + 5 20 | 21 | let backsort x = x * -1 22 | 23 | let last x = x - x 24 | 25 | let has0 x = 0 26 | 27 | let rec take n x y size = 28 | match x with 29 | | [] -> x 30 | | h::t -> t 31 | 32 | let rec drop n x size = 33 | match x with 34 | | [] -> 45 35 | | h::t -> size 36 | 37 | (* returns: [from i j l] is the list containing the integers from 38 | * [i] to [j], inclusive, followed by the list [l]. 39 | * example: [from 1 3 [0] = [1;2;3;0]] *) 40 | let rec from i j l = 41 | if i>j then l 42 | else j 43 | 44 | (* returns: [i -- j] is the list containing the integers from 45 | * [i] to [j], inclusive. 46 | *) 47 | let (--) i j = 48 | i - j 49 | -------------------------------------------------------------------------------- /tests/test9/prelimpract.ml: -------------------------------------------------------------------------------- 1 | (*unit -> 'a 2 | True -> P 3 | 4 | ('a, ('b,'c)) 5 | P and (Q and R) 6 | 7 | (('a*'b)or'*'c) or' 8 | (P or Q) or R 9 | 10 | void -> 'a 11 | False -> P 12 | 13 | ('a*'a neg) or' 14 | P \/ ~P 15 | 16 | 'a*'b or' -> 'b*'a or' 17 | 18 | ('a*'b neg) or' -> ('b->'a) 19 | 20 | ('a*'b)-> 'a 21 | (P/\Q) -> P 22 | f(1,2) -> substitution {(1,2)/x} snd ((fun x -> x,x) (fst x)) -> snd ((fun x -> x,x) (fst (1,2))) 23 | function application-> snd ((fun x -> x,x) (1)) 24 | substituion -> snd ({1/x} x,x) -> snd (1,1) 25 | function app -> 1 26 | 27 | desugar 28 | let fact = rec fact -> fun x -> 29 | if x <= 1 then 1 else x * (fact (x - 1)) in 30 | fact 3 31 | 32 | step rec 33 | let fact = 34 | fun x -> 35 | if x <= 1 then 1 else x * (fact (x - 1)) {F/fact} in fact 3 36 | 37 | substitute 38 | let fact = fun x -> 39 | if x <= 1 then 1 else x * (F (x - 1)) in 40 | (fact) 3 41 | 42 | application 43 | if x <= 1 then 1 else x * (F (x - 1)) {3/x} 44 | -> if 3 <= 1 then 1 else 3 * (F (3 - 1)) 45 | 46 | step bool 47 | if false then 1 else 3 * (F (3 - 1)) 48 | 49 | 3 * (rec fact -> fun x -> if x <= 1 then 1 else x * (fact (x-1))) 2 50 | 51 | 3 * fun x -> if x <= 1 then 1 else x * (fact (x-1))) 2 {F/fact} 52 | 53 | 3 * fun x -> if x <= 1 then 1 else x * (F (x-1))) 2 54 | 55 | 3 * (if x <= 1 then 1 else x * (F (x-1))) {2/x}) 56 | 57 | 3 * (if 2 <= 1 then 1 else 2 * (F (2-1)))) 58 | 3 * (if false then 1 else 2 * (F (2-1)))) 59 | 60 | 3 * 2 * F (2-1) 61 | 62 | 3 * 2 * rec fact -> fun x -> if x <= 1 then 1 else x * (fact (x-1)) (1) 63 | 64 | 3 * 2 * (fun x -> if x <= 1 then 1 else x * (fact (x-1)) (1) {F/fact}) 65 | 66 | 3 * 2 * (fun x -> if x <= 1 then 1 else x * (F (x-1)) (1)) 67 | 68 | 3 * 2 * (if 1 <= 1 then 1 else 1 * (fact (1-1)) 69 | 70 | 3 * 2 * (if true then 1 else 1 * (fact (1-1)) 71 | 72 | 3 * 2 * 1 73 | 74 | 6 75 | 76 | ('a*'b neg) or' -> ('b->'a) 77 | 78 | 79 | {} 110 + 3*1000 => 3110 op rule 80 | because {} 110 => 110 const rule 81 | and {} 3*1000 => 3000 op rule 82 | because {}3=> 3 const rule 83 | and {}1000=>1000 const rule 84 | and 3*1000 = 3000 85 | and 110 + 3000 = 3110 86 | 87 | {} if 2+3<4 then 1+1 else 2+2 => 4 if rule 88 | because {}2+3<4 => false op rule 89 | because {} 2+3 => 5 op rule 90 | because {} 2 => 2 const 91 | and {} 3 => 3 const 92 | and 2+3=5 93 | and {}4=> 4 const 94 | and 5<4 => false 95 | and {}2+2 => 4 op 96 | because {}2 => 2 const 97 | and {}2 => 2 const 98 | and 2++2 = 4 99 | 100 | {} let x=0 in x + (let x=1 in x) => 1 let rule 101 | because {}0=> 0 const rule 102 | and {(x,0)} (x + (let x=1 in x))=> 1 op + 103 | because {(x,0)} x => 0 var rule 104 | and {(x,0)} (let x = 1 in x) => 1 let rule 105 | because {x,0} 1=>1 const 106 | and {(x,1)} x => 1 var rule 107 | and 0 + 1 = 1 108 | 109 | {} match Left 2 with Left x-> x+1| Right x -> x-1 =>3 match rule 110 | because {}Left 2 => Left 2 left rule 111 | because 2=>2 const rule 112 | and {(x,2)} x+1 => 3 op + 113 | because x=>2 var rule 114 | and 1=>1 const rule 115 | and 2+1 = 3 116 | 117 | {} (fun x -> x+1) 2 => 3 application 118 | because {},fun x->x+1=> (|fun x -> x+1,{}|) closure 119 | and {}2 => 2 const 120 | and {(x,2)} x + 1 => 3 op + 121 | because x=>2 var 122 | and 1=>1 const 123 | and 1+2 = 3 124 | 125 | {} let f = fun x -> x+1 in f 2 => 3 let rule 126 | because {} fun x -> x+1 => (|fun x -> x+1|,{}) closure 127 | and {(f, fun x -> x+1)} f 2 => 3 application 128 | because {(f, fun x -> x+1)} f=> fun x -> x+1 var rule 129 | and {(f, fun x -> x+1)} 2=>2 const 130 | and {(x,2)} x + 1 => 3 op + 131 | because {(x,2)} x => 2 var 132 | and {(x,2)}1=>1 const 133 | and 2+1 = 3 134 | 135 | {} let x = 1 in let f = fun y -> x in let x = 2 in f 0 => 1 let rule 136 | because {}1=> 1 const 137 | and {(x,1)} let f = fun y -> x in let x = 2 in f 0 => 1 let rule 138 | because {(x,1)} fun y -> x => {fun y -> x, (x,1)} closure 139 | and {(x,1); (f, fun y -> x)} let x = 2 in f 0 => 1 let rule 140 | because {(x,1); (f, fun y -> x)} 2=>2 const 141 | and {(x,2); (f, closure)} f 0 => 1 application 142 | because f => {fun y -> x, (x,1)} var 143 | and {(x,2); (f, closure)} 0 =>0 const 144 | and {(x,1);(y,0)} x => 1 var rule 145 | 146 | 147 | 148 | *) 149 | 150 | type ('a,'b) or' = Left of 'a | Right of 'b 151 | 152 | let p_and_q_comm (p,q) = (q,p) 153 | 154 | let p_or_q_comm p_or_q = match p_or_q with 155 | | Left a -> Right a 156 | | Right b -> Left b 157 | 158 | type void = {nope : 'a .'a} 159 | type 'a neg = 'a -> void 160 | let explode (f:void) : 'b = f.nope 161 | 162 | let ex (p, (q:'a neg)) = explode (q p) 163 | let f x = fst x 164 | -------------------------------------------------------------------------------- /tests/test9/prelimpract1.ml: -------------------------------------------------------------------------------- 1 | (* comments are exactly same as prelimpract. functions are completely different 2 | 3 | unit -> 'a 4 | True -> P 5 | 6 | ('a, ('b,'c)) 7 | P and (Q and R) 8 | 9 | (('a*'b)or'*'c) or' 10 | (P or Q) or R 11 | 12 | void -> 'a 13 | False -> P 14 | 15 | ('a*'a neg) or' 16 | P \/ ~P 17 | 18 | 'a*'b or' -> 'b*'a or' 19 | 20 | ('a*'b neg) or' -> ('b->'a) 21 | 22 | ('a*'b)-> 'a 23 | (P/\Q) -> P 24 | f(1,2) -> substitution {(1,2)/x} snd ((fun x -> x,x) (fst x)) -> snd ((fun x -> x,x) (fst (1,2))) 25 | function application-> snd ((fun x -> x,x) (1)) 26 | substituion -> snd ({1/x} x,x) -> snd (1,1) 27 | function app -> 1 28 | 29 | desugar 30 | let fact = rec fact -> fun x -> 31 | if x <= 1 then 1 else x * (fact (x - 1)) in 32 | fact 3 33 | 34 | step rec 35 | let fact = 36 | fun x -> 37 | if x <= 1 then 1 else x * (fact (x - 1)) {F/fact} in fact 3 38 | 39 | substitute 40 | let fact = fun x -> 41 | if x <= 1 then 1 else x * (F (x - 1)) in 42 | (fact) 3 43 | 44 | application 45 | if x <= 1 then 1 else x * (F (x - 1)) {3/x} 46 | -> if 3 <= 1 then 1 else 3 * (F (3 - 1)) 47 | 48 | step bool 49 | if false then 1 else 3 * (F (3 - 1)) 50 | 51 | 3 * (rec fact -> fun x -> if x <= 1 then 1 else x * (fact (x-1))) 2 52 | 53 | 3 * fun x -> if x <= 1 then 1 else x * (fact (x-1))) 2 {F/fact} 54 | 55 | 3 * fun x -> if x <= 1 then 1 else x * (F (x-1))) 2 56 | 57 | 3 * (if x <= 1 then 1 else x * (F (x-1))) {2/x}) 58 | 59 | 3 * (if 2 <= 1 then 1 else 2 * (F (2-1)))) 60 | 3 * (if false then 1 else 2 * (F (2-1)))) 61 | 62 | 3 * 2 * F (2-1) 63 | 64 | 3 * 2 * rec fact -> fun x -> if x <= 1 then 1 else x * (fact (x-1)) (1) 65 | 66 | 3 * 2 * (fun x -> if x <= 1 then 1 else x * (fact (x-1)) (1) {F/fact}) 67 | 68 | 3 * 2 * (fun x -> if x <= 1 then 1 else x * (F (x-1)) (1)) 69 | 70 | 3 * 2 * (if 1 <= 1 then 1 else 1 * (fact (1-1)) 71 | 72 | 3 * 2 * (if true then 1 else 1 * (fact (1-1)) 73 | 74 | 3 * 2 * 1 75 | 76 | 6 77 | 78 | ('a*'b neg) or' -> ('b->'a) 79 | 80 | 81 | {} 110 + 3*1000 => 3110 op rule 82 | because {} 110 => 110 const rule 83 | and {} 3*1000 => 3000 op rule 84 | because {}3=> 3 const rule 85 | and {}1000=>1000 const rule 86 | and 3*1000 = 3000 87 | and 110 + 3000 = 3110 88 | 89 | {} if 2+3<4 then 1+1 else 2+2 => 4 if rule 90 | because {}2+3<4 => false op rule 91 | because {} 2+3 => 5 op rule 92 | because {} 2 => 2 const 93 | and {} 3 => 3 const 94 | and 2+3=5 95 | and {}4=> 4 const 96 | and 5<4 => false 97 | and {}2+2 => 4 op 98 | because {}2 => 2 const 99 | and {}2 => 2 const 100 | and 2++2 = 4 101 | 102 | {} let x=0 in x + (let x=1 in x) => 1 let rule 103 | because {}0=> 0 const rule 104 | and {(x,0)} (x + (let x=1 in x))=> 1 op + 105 | because {(x,0)} x => 0 var rule 106 | and {(x,0)} (let x = 1 in x) => 1 let rule 107 | because {x,0} 1=>1 const 108 | and {(x,1)} x => 1 var rule 109 | and 0 + 1 = 1 110 | 111 | {} match Left 2 with Left x-> x+1| Right x -> x-1 =>3 match rule 112 | because {}Left 2 => Left 2 left rule 113 | because 2=>2 const rule 114 | and {(x,2)} x+1 => 3 op + 115 | because x=>2 var rule 116 | and 1=>1 const rule 117 | and 2+1 = 3 118 | 119 | {} (fun x -> x+1) 2 => 3 application 120 | because {},fun x->x+1=> (|fun x -> x+1,{}|) closure 121 | and {}2 => 2 const 122 | and {(x,2)} x + 1 => 3 op + 123 | because x=>2 var 124 | and 1=>1 const 125 | and 1+2 = 3 126 | 127 | {} let f = fun x -> x+1 in f 2 => 3 let rule 128 | because {} fun x -> x+1 => (|fun x -> x+1|,{}) closure 129 | and {(f, fun x -> x+1)} f 2 => 3 application 130 | because {(f, fun x -> x+1)} f=> fun x -> x+1 var rule 131 | and {(f, fun x -> x+1)} 2=>2 const 132 | and {(x,2)} x + 1 => 3 op + 133 | because {(x,2)} x => 2 var 134 | and {(x,2)}1=>1 const 135 | and 2+1 = 3 136 | 137 | {} let x = 1 in let f = fun y -> x in let x = 2 in f 0 => 1 let rule 138 | because {}1=> 1 const 139 | and {(x,1)} let f = fun y -> x in let x = 2 in f 0 => 1 let rule 140 | because {(x,1)} fun y -> x => {fun y -> x, (x,1)} closure 141 | and {(x,1); (f, fun y -> x)} let x = 2 in f 0 => 1 let rule 142 | because {(x,1); (f, fun y -> x)} 2=>2 const 143 | and {(x,2); (f, closure)} f 0 => 1 application 144 | because f => {fun y -> x, (x,1)} var 145 | and {(x,2); (f, closure)} 0 =>0 const 146 | and {(x,1);(y,0)} x => 1 var rule 147 | 148 | 149 | 150 | *) 151 | 152 | type student = { 153 | name: string; 154 | mutable gpa: float; 155 | } 156 | 157 | let student1 = { 158 | name = "Alice"; 159 | gpa = 3.7; 160 | } 161 | 162 | type vector = float array 163 | 164 | let norm vec= sqrt (Array.fold_left (+.) 0. (Array.map (fun x -> x *. x) vec)) 165 | 166 | let normalize vec = 167 | for x = 0 to Array.length vec -1 168 | do vec.(x) <- vec.(x) * 2 done 169 | -------------------------------------------------------------------------------- /tests/test9/prelimpract2.ml: -------------------------------------------------------------------------------- 1 | (* all comments gone. Constructor names/ type variables changed. 2 | *) 3 | 4 | type ('z,'f) or' = Blah of 'z | Bloo of 'f 5 | 6 | let p_and_q_comm (p,q) = (q,p) 7 | 8 | let p_or_q_comm p_or_q = match p_or_q with 9 | | Blah a -> Bloo a 10 | | Bloo b -> Blah b 11 | 12 | type hi = {hehe : 'm .'m} 13 | type 'va neg = 'va -> hi 14 | let explode (f:hi) : 'b = f.hehe 15 | 16 | let ex (p, (q:'a neg)) = explode (q p) 17 | let f x = fst x 18 | -------------------------------------------------------------------------------- /winnowing.ml: -------------------------------------------------------------------------------- 1 | module type BoundedQueueWithCounter = sig 2 | type 'a t 3 | val empty : int -> 'a t 4 | val create : int -> 'a -> 'a t 5 | val is_empty : 'a t -> bool 6 | val is_full : 'a t -> bool 7 | val size : 'a t -> int 8 | val enqueue : 'a -> 'a t -> 'a t 9 | val dequeue : 'a t -> 'a option * 'a t 10 | val count : 'a t -> int 11 | val fold : ('b -> 'a -> 'b) -> 'b -> 'a t -> 'b 12 | val to_list: 'a t -> 'a list 13 | end 14 | 15 | module Window : BoundedQueueWithCounter = struct 16 | 17 | type 'a t = { data: ('a list) * ('a list) ; maxsize: int ; size: int ; count: int} 18 | 19 | let empty n = 20 | if n = 0 then failwith "Cannot create queue of size 0!" 21 | else 22 | { data = ([],[]); maxsize = n; size = n; count = 0} 23 | 24 | let create n i = 25 | let rec gen l acc i = 26 | if l = 0 then acc else gen (l - 1) (i::acc) i 27 | in 28 | if n = 0 then failwith "Cannot create queue of size 0!" 29 | else 30 | let initdata = gen n [] i in 31 | { data = (initdata,[]); maxsize = n; size = n; count = 0} 32 | 33 | let is_empty q = (q.size = 0) 34 | 35 | let is_full q = (q.size = q.maxsize) 36 | 37 | let size q = q.size 38 | 39 | let rec dequeue q = 40 | match q.data with 41 | |h::t, b -> (Some h, {q with data = (t,b) ; size = q.size - 1}) 42 | |[],[] -> (None, q) 43 | |[], h::t -> dequeue {q with data = (List.rev (h::t),[])} 44 | 45 | let rec enqueue item q = 46 | if is_full q then dequeue q |> snd |> enqueue item 47 | else 48 | match q.data with 49 | |f,b -> {q with data = (f,item::b); size = q.size + 1 ;count = q.count + 1} 50 | 51 | let count q = q.count 52 | 53 | let to_list q = (fst q.data)@(snd q.data |> List.rev) 54 | 55 | let fold f init q = 56 | List.fold_left f init (to_list q) 57 | 58 | 59 | end 60 | 61 | (* h = hashes list, w = window size *) 62 | let winnow w h = 63 | (* calculates the global position of the i-th hash in the window 64 | example: if [global_pos 5 W] = 100, then the 5th hash in W is the 100th 65 | hash that was processed by the winnowing algorithm. *) 66 | let global_pos i w = 67 | let c = Window.count w in 68 | let s = Window.size w in 69 | c - (s - 1 - i) 70 | in 71 | (* helper function *) 72 | let mincheck ((minval,minpos),count) x = 73 | if x <= minval then ((x, count), count + 1) 74 | else ((minval, minpos), count + 1) 75 | in 76 | 77 | (* At the end of each iteration, min is a tuple of the (value,position) 78 | of the rightmost minimal hash in the 79 | current window. hash x is only added to the fingerprint [res] the 80 | first time an instance of x is selected as the 81 | rightmost minimal hash of a window. 82 | 83 | hashes - the complete list of hashes 84 | window - window object 85 | acc - list of selected hash x position pairs 86 | n - counter for position of hashes 87 | (v,p) - value and position of minimum hash 88 | *) 89 | let rec winnowhelper hashes window acc n (v,p) = 90 | if n = List.length hashes then acc 91 | else begin 92 | let nexthash = List.nth hashes n in 93 | let new_window = Window.enqueue nexthash window in 94 | if nexthash <= v then 95 | let new_acc = (nexthash, global_pos (Window.size new_window - 1) 96 | new_window)::acc in 97 | winnowhelper hashes new_window new_acc (n+1) (nexthash, 98 | Window.size new_window - 1) 99 | else begin 100 | let p = p - 1 in 101 | if p < 0 then 102 | let new_min = fst (Window.fold mincheck ((max_int,0),0) new_window) in 103 | let new_acc = (fst new_min, global_pos (snd new_min) new_window)::acc in 104 | winnowhelper hashes new_window new_acc (n+1) new_min 105 | else 106 | winnowhelper hashes new_window acc (n+1) (v,p) 107 | end 108 | end 109 | in 110 | let window = Window.create w max_int in 111 | let res = winnowhelper h window [] 0 (max_int, 0) in res 112 | -------------------------------------------------------------------------------- /winnowing.mli: -------------------------------------------------------------------------------- 1 | (* custom data structure representing a bounded queue which also keeps track 2 | * of its current size 3 | * and the total number of times enqueue has been called *) 4 | module type BoundedQueueWithCounter = sig 5 | type 'a t 6 | 7 | (* [empty n] returns an empty queue with capacity n *) 8 | val empty : int -> 'a t 9 | 10 | (* [create n i] returns a full queue with capacity n, 11 | * with every element initialized to i *) 12 | val create : int -> 'a -> 'a t 13 | 14 | (* [is_empty q] checks if q is empty and returns a boolean *) 15 | val is_empty : 'a t -> bool 16 | 17 | (* [is_full q] checks if q is full and returns a boolean *) 18 | val is_full : 'a t -> bool 19 | 20 | (* [size q] returns the number of elements currently in q *) 21 | val size : 'a t -> int 22 | 23 | (* [enqueue v q] returns a queue that has the contents of q with the 24 | * value v enqueued at the tail 25 | * if q is full, then the first element will be dequeued before v is 26 | * enqueued *) 27 | val enqueue : 'a -> 'a t -> 'a t 28 | 29 | (* [dequeue q] dequeues the first element (head) of q and returns a tuple 30 | * of the element and the updated queue the dequeued element is stored as 31 | * an option 32 | * if q is empty then the first value of the tuple will be None*) 33 | val dequeue : 'a t -> 'a option * 'a t 34 | 35 | (* [count q] returns the number of elements that have been enqueued 36 | * (including ones that are no longer in the queue) *) 37 | val count : 'a t -> int 38 | 39 | (* [fold f init q] folds [f] over a list of the elements in [q] from 40 | * the head to the tail with initial value [init] *) 41 | val fold : ('b -> 'a -> 'b) -> 'b -> 'a t -> 'b 42 | 43 | (* [to_list q] returns a list representation of the elements of q in order, 44 | * with the first element being the head and the last element being the tail 45 | *) 46 | val to_list: 'a t -> 'a list 47 | end 48 | 49 | (* an implementation of BoundedQueueWithCounter using a record type and using 50 | * two lists to store data. The first list stores the front of the queue, 51 | * the second list stores the back of the queue in reverse order. 52 | * 53 | * AF: the elements of the queue is stored in the [data] field, the current 54 | * size stored in [size], the maximum size stored in [maxsize], and number of 55 | * times an element has been enqueued stored in [count] 56 | * 57 | * RI: [size] <= [maxsize], [size],[maxsize],[count] cannot be negative, [size] 58 | * is sum of the lengths of both lists in [data], the head of the first list 59 | * in data is the head of the queue, the head of the second list is the tail 60 | * of the queue 61 | *) 62 | module Window : BoundedQueueWithCounter 63 | 64 | (* [winnow w h] applies the winnowing algorithm for a list of hashes [h] with 65 | * window size [w] returns: a list of (v,p) tuples where v is a hash value and 66 | * p is the position in the original input the (v,p) list is not guaranteed to 67 | * be in any particular order requires: [w] is a positive integer 68 | *) 69 | val winnow: int -> int list -> (int * int) list 70 | --------------------------------------------------------------------------------