Data Structures and Algorithms

Lab 7: Plagiarism Detector

Due on Sunday, November 13th at 11:59 PM. This is a team lab. You and your assigned lab partner(s) will complete this lab together. Make sure that you are familiar with the Partner Etiquette guidelines. You may discuss the concepts of this lab with other classmates, but you may not share your code with anyone other than course staff and your lab partner(s). Do not look at solutions written by students other than your team. If your team needs help, please post on the Piazza forum or contact the instructor or ninjas. If you have any doubts about what is okay and what is not, it’s much safer to ask than to risk violating the Academic Integrity Policy.

Overview

This lab consists of two parts. The first part is a written assignment involving algorithms for AVL trees and heaps. The second part involves writing a program to detect plagiarism in essays. Both of these parts involve some amount of material on the heap data structure; if you encounter that part of the work before heaps have been covered in class, set it aside and move on to the other part. (If you get to the heap material on both parts of this lab before heaps are covered in lecture, then well done; you deserve a break!)

Part I: Written Lab

Writing Hand

For this part of your assignment, you will give written answers much in the same way as you did in previous labs. Your submission must be in a typeset PDF format; please see that link for instructions and see your Lab 3 template for instructions on how to use LaTeX.

textree.py

This part of the lab involves drawing trees. This is difficult in LaTeX (and in most diagram software), so we’ve given you a Makefile rule that will make things much easier. This rule calls the script textree.py, which has been provided for you. Between this and the provided WrittenLab.tex, all you need to do is draw some ASCII art trees in text files and your PDF will be built for you.

In the written-trees directory, there are a series of files named e.g. problem1.1.tree. The textree.py script turns these tree files into .tex code which will draw those trees in the PDF. To complete the written part of the assignment, you just need edit the .tree files to contain the right trees. The following rules apply in these .tree files:

For instance, this example diagram is produced by the following .tree file.

Example `.tree` File
: This is a sample BST.

 2
1 3

# This line is a comment.

: I can put slashes into my tree if I want; they don't do anything.

  2
 / \
1   3

: Each node decides its parent by the text that is closest to it.  For instance,
: the 3 below is the left child of 4 (and not the right child of 1) because the
: 4 is closer to the three.  The blank lines are ignored just like lines with
: symbols are.

  2

1   4

   3

AVL Tree Questions

  1. Show the left rotation of the following tree. In this rotation, what are the X, Y, and Z subtrees?

  2. Show the right rotation of the subtree with the root node 6. In this rotation, what are the X, Y, and Z subtrees?

  3. Using the AVL tree algorithm, insert the value 2 into the following tree. Show the tree before and after rebalancing.

  4. Using the AVL tree algorithm, remove the value 12 from the following tree. Show the tree before and after each rebalancing.

Heap Questions

Note that these questions rely upon the discussion of heaps in lecture.

  1. Show the addition of element 5 to max-heap below. First, show the addition of 5 to the tree; then, show each bubbling step.

  2. Show the removal of the top element of this max-heap. First, show the swap of the root node; then, show each bubbling step.

  3. Consider the sequence of elements [7,1,5,2,8,3,4]. Using the representation discussed in class, show the tree to which this sequence corresponds. Then, show the heapification of this tree; that is, show how this tree is transformed into a heap. Demonstrate each bubbling step.

Part II: The Plagiarism Detector

Plagiarism Detector

In this part of the lab, you will write a program for detecting plagiarism in written essays. To do this, we will make one fundamental assumption: plagiarized documents will have a significant number of phrases in common. Our plagiarism detector will then proceed according to the following high-level algorithm:

  1. Determine which phrases appear in each document and how often.
  2. Compare each pair of documents to determine how similar their phrase counts are.
  3. Report the most similar pairs of documents.

You will not have to write tests for your program; they have been provided. To approach this problem, we will break the work into a few parts. We’ll start by writing code to represent a single document. Next, we’ll write code to perform the comparison between documents. Finally, we’ll put it all together into a main function.

The Document Class

Similar Documents

We will begin by splitting the text files that we are checking into “phrases”. Here, a phrase will be a sequence of three words that appear next to each other in the document. For instance, the text “hedgehog in a balloon factory” contains the phrases “hedgehog in a”, “in a balloon”, and “a balloon factory”.

The files documentUtils.h and documentUtils.cpp already contain code that will read the files for you and split them into phrases; you must write the Document class that this code uses to remember the phrases for a particular document. Look at document.h for a description of how the Document class should work; write your implementations in document.cpp. Note that we do not have a document__definitions.h file; we only need to put definitions in .h files for templated classes.

When writing your code, note that each Document will need a Dictionary to keep track of how many times it has seen each phrase. You can find a balanced BST implementation of the Dictionary interface in adts/impls/stlBST.h.

Note that you must provide the private field declarations for the classes in this lab. Destructors are declared for each class, but how they should operate will depend upon the particular fields you pick. It’s possible, for instance, that the right destructor implementation involves no lines of code at all.

Testing the Document Class

Tests for this lab have been provided for you, but they have been split into several groups to allow you to run them separately. If you run tests as normal…

    make tests
    ./tests

…then you will receive a message requesting which tests to run. Your choices are all, document, detectorShort, detectorMedium, and detectorLong. You should avoid all until you have completed your lab. For now, just run

    make tests
    ./tests document

You should make sure your Document class tests succeed before you continue.

The PlagiarismDetector Class

Magnifying Glass

Once you have implemented the Document class, you are able to load documents, count their phrases, and determine how similar they are to each other. Next, we need to write code that uses this class to analyze numerous documents. We’ll write this code in the PlagiarismDetector class to keep it organized; when we’ve finished, we’ll be able to think of a PlagiarismDetector object as a device for detecting similar documents without focusing on the details of e.g. AVL trees.

The first important method of the PlagiarismDetector class is the addDocument method. Given a filename, this method loads that file using the documentUtils.h functions and keeps the resulting Document* for later analysis. You will need to add an appropriate field to store this information but, since both the loadDocument function and the Document class have already been written, there aren’t that many lines of code involved.

The second important method of PlagiarismDetector is the findSuspiciousDocuments method. This method must compare each added document to each other, producing a list of SimilarityResult objects. It must then produce some number of the top matches based upon a parameter; for instance, the caller may want the top ten matches. The findSuspiciousDocuments method is required to use a heap to find these most suspicious documents. Sorting the entire list of results isn’t an option.

For large sets of documents, findSuspiciousDocuments takes a very long time. Feel free to add a progress indicator to help you keep track of which files you are comparing or how much work you have left to do.

SimilarityResult and Copying

The findSuspiciousDocuments method of the PlagiarismDetector class allows you to find the most suspicious documents that the detector has loaded. This method returns a vector containing objects of type SimilarityResult, a class which has been written for you. SimilarityResult is similar to pair or string in that it knows how to copy itself; that is, the following code works:

SimilarityResult myResult("file1.txt", "file2.txt", 20);
SimilarityResult otherResult = myResult; // this doesn't usually work for classes we write

This means that you don’t need to create dynamically-allocated SimilarityResult objects; you can statically allocate them like you have done with pair objects in previous labs.

Testing the PlagiarismDetector Class

As mentioned above, the tests for this lab have been split into groups. For the PlagiarismDetector class, there are three groups: detectorShort, detectorMedium, and detectorLong. These groups reflect how long the tests will take to run. Because the plagiarism detection process is computationally intensive, you’ll want to start by debugging the short tests and move on to the longer tests when they’re the only ones left that fail. Make sure you read the following section on performance before moving on to the longer tests!

Performance

The plagiarism detection process is fairly slow. Fortunately, there’s one key optimization you can introduce which improves the wall time of your program considerably. This optimization could make the difference between your unit tests running for five minutes or five hours, so make sure to include it before running detectorMedium or detectorLong.

The optimization only involves changing a few lines of code. In your Document class where the similarity method is defined, your algorithm probably works something like this:

  1. Create a vector to contain the phrases.
  2. Set that vector to contain all phrases from this document.
  3. For each phrase in that vector, accumulate either the phrase count from this document or the phrase count from the other document, whichever is smaller.

This algorithm works well on documents of similar size. If, however, one of the documents is much larger than the other, we run the risk of calling getPhraseCount many, many times only to get a lot of zeroes. To fix this problem, use the following algorithm instead:

  1. Create a vector to contain the phrases.
  2. Set that vector to contain all phrases from either this document or the other document, based upon which document has fewer phrases.
  3. For each phrase in that vector, accumulate either the phrase count from this document or the phrase count from the other document, whichever is smaller.

With this algorithm in place, the tests should take roughly the following times on the CS network machines:

Your main Function

Once you’ve written the PlagiarismDetector class, you should be prepared to write your main method. The first argument of your program should be the number of results to display. Every remaining argument is the name of a document to use when running your program. For instance, a user might write

./plagiarismDetector 4 essay1.txt essay2.txt essay3.txt essay4.txt essay5.txt

to get the top four examples of plagiarism among the provided five files. In bash (the language used by the terminals on the CS network machines), you can accomplish the same thing by writing

./plagiarismDetector 4 essay*.txt

The terminal will interpret the “*” in the filename to mean “any amount of text goes here”; it will then find all files matching that description and use each of their names as a different argument. For instance, you can try

./plagiarismDetector 10 test_data/small/*

to test the small data set. For instance, the above command might return the following:

test_data/small/bgt61.txt test_data/small/sra31.txt 1639
test_data/small/bgt157.txt test_data/small/bgt160.txt 754
test_data/small/bmu392.txt test_data/small/mul30.txt 24
test_data/small/esv276.txt test_data/small/toi94.txt 23
test_data/small/bah105.txt test_data/small/esv276.txt 22
test_data/small/bah27.txt test_data/small/esv276.txt 21
test_data/small/bgt61.txt test_data/small/toi94.txt 20
test_data/small/sra31.txt test_data/small/toi94.txt 19
test_data/small/esv276.txt test_data/small/toi141.txt 18
test_data/small/ecu179.txt test_data/small/esv276.txt 18

The specific format of the output is up to you.

Invalid Input

Your program is expected to run without crashing or throwing an exception from main regardless of how it is run; in case of bad input, you should provide an appropriate error message. In particular, you must handle all of the following bad cases:

Memory

Your program must run without any memory errors; make sure to use valgrind to find them. Memory leaks, on the other hand, are acceptable in small amounts and will not significantly impact your grade. In particular, “still reachable” memory is acceptable; “lost” memory should not occur in large amounts (e.g. millions of bytes).

Coding Style Requirements

You are required to observe some good coding practices:

Well-dressed people (style)

Peer Review

As this is a team assignment, you are required to complete a peer review of your lab partner or partners. You must do this even if everything is fine. You should complete this peer review after you have turned in your assignment. The peer review comes in the form of a simple Google Form and can be accessed here; in most cases, it will likely take less than a minute to complete. If you have trouble accessing this peer review, please make sure that you are logged into Google using your Swarthmore credentials.

Your peer review will be kept private; only course staff will have access to this information. You can also update your peer review after you have submitted it. However, if you do not submit a peer review, you will lose participation grade points. Please don’t forget!

Summary of Requirements

When you are finished, you should have