Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Fix similarity distribution in JPlagResult #794

Merged
merged 1 commit into from
Nov 16, 2022
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 1 addition & 2 deletions core/src/main/java/de/jplag/JPlagResult.java
Original file line number Diff line number Diff line change
Expand Up @@ -141,8 +141,7 @@ private int[] calculateDistributionFor(List<JPlagComparison> comparisons, ToDoub
int index = (int) (similarity * SIMILARITY_DISTRIBUTION_SIZE); // divide similarity by bucket size to find index of correct bucket.
index = Math.min(index, SIMILARITY_DISTRIBUTION_SIZE - 1);// index is out of bounds when similarity is 1.0. decrease by one to count
// towards the highest value bucket
similarityDistribution[SIMILARITY_DISTRIBUTION_SIZE - 1 - index]++; // count comparison towards its determined bucket. bucket order is
// reversed, so that the highest value bucket has the lowest index
similarityDistribution[index]++; // count comparison towards its determined bucket.
}
return similarityDistribution;
}
Expand Down
Original file line number Diff line number Diff line change
@@ -1,10 +1,11 @@
package de.jplag.reporting.reportobject.mapper;

import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collections;
import java.util.Comparator;
import java.util.List;
import java.util.function.Function;
import java.util.stream.Collectors;

import de.jplag.JPlagComparison;
import de.jplag.JPlagResult;
Expand All @@ -25,12 +26,12 @@ public MetricMapper(Function<Submission, String> submissionToIdFunction) {
}

public Metric getAverageMetric(JPlagResult result) {
return new Metric(SimilarityMetric.AVG.name(), intArrayToList(result.getSimilarityDistribution()), getTopComparisons(getComparisons(result)),
Messages.getString("SimilarityMetric.Avg.Description"));
return new Metric(SimilarityMetric.AVG.name(), convertDistribution(result.getSimilarityDistribution()),
getTopComparisons(getComparisons(result)), Messages.getString("SimilarityMetric.Avg.Description"));
}

public Metric getMaxMetric(JPlagResult result) {
return new Metric(SimilarityMetric.MAX.name(), intArrayToList(result.getMaxSimilarityDistribution()),
return new Metric(SimilarityMetric.MAX.name(), convertDistribution(result.getMaxSimilarityDistribution()),
getMaxSimilarityTopComparisons(getComparisons(result)), Messages.getString("SimilarityMetric.Max.Description"));
}

Expand All @@ -39,8 +40,10 @@ private List<JPlagComparison> getComparisons(JPlagResult result) {
return result.getComparisons(maxNumberOfComparisons);
}

private List<Integer> intArrayToList(int[] array) {
return Arrays.stream(array).boxed().collect(Collectors.toList());
private List<Integer> convertDistribution(int[] array) {
List<Integer> list = new ArrayList<>(Arrays.stream(array).boxed().toList());
Collections.reverse(list);
return list;
}

private List<TopComparison> getTopComparisons(List<JPlagComparison> comparisons, Function<JPlagComparison, Double> similarityExtractor) {
Expand Down
4 changes: 2 additions & 2 deletions core/src/test/java/de/jplag/BaseCodeTest.java
Original file line number Diff line number Diff line change
Expand Up @@ -38,7 +38,7 @@ protected void verifyResults(JPlagResult result) {
assertEquals(2, result.getNumberOfSubmissions());
assertEquals(1, result.getAllComparisons().size());
assertEquals(1, result.getAllComparisons().get(0).matches().size());
assertEquals(1, result.getSimilarityDistribution()[1]);
assertEquals(1, result.getSimilarityDistribution()[8]);
assertEquals(0.85, result.getAllComparisons().get(0).similarity(), DELTA);
}

Expand Down Expand Up @@ -87,7 +87,7 @@ protected void verifySimpleSubdirectoryDuplicate(JPlagResult result, int submiss
assertEquals(submissions, result.getNumberOfSubmissions());
assertEquals(comparisons, result.getAllComparisons().size());
assertEquals(1, result.getAllComparisons().get(0).matches().size());
assertEquals(1, result.getSimilarityDistribution()[3]);
assertEquals(1, result.getSimilarityDistribution()[6]);
assertEquals(0.6207, result.getAllComparisons().get(0).similarity(), DELTA);
}

Expand Down
4 changes: 2 additions & 2 deletions core/src/test/java/de/jplag/ParallelComparisonTest.java
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,7 @@ void testSimpleDuplicate() throws ExitException {
assertEquals(2, result.getNumberOfSubmissions());
assertEquals(1, result.getAllComparisons().size());
assertEquals(1, result.getAllComparisons().get(0).matches().size());
assertEquals(1, result.getSimilarityDistribution()[3]);
assertEquals(1, result.getSimilarityDistribution()[6]);
assertEquals(0.6207, result.getAllComparisons().get(0).similarity(), DELTA);
}

Expand All @@ -32,7 +32,7 @@ void testSimpleDuplicate() throws ExitException {
*/
@Test
void testWithMinTokenMatch() throws ExitException {
var expectedDistribution = new int[] {1, 0, 0, 0, 0, 0, 0, 0, 0, 0};
var expectedDistribution = new int[] {0, 0, 0, 0, 0, 0, 0, 0, 0, 1};
JPlagResult result = runJPlag("SimpleDuplicate", it -> it.withMinimumTokenMatch(5));

assertEquals(2, result.getNumberOfSubmissions());
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@
import static org.mockito.Mockito.mock;

import java.util.ArrayList;
import java.util.Collections;
import java.util.List;

import org.junit.jupiter.api.Assertions;
Expand All @@ -17,19 +18,20 @@
import de.jplag.reporting.reportobject.model.TopComparison;

public class MetricMapperTest {
private static final List<Integer> EXPECTED_DISTRIBUTION = List.of(29, 23, 19, 17, 13, 11, 7, 5, 3, 2);
private final MetricMapper metricMapper = new MetricMapper(Submission::getName);

@Test
public void test_getAverageMetric() {
// given
JPlagResult jPlagResult = createJPlagResult(MockMetric.AVG, distribution(2, 3, 5, 7, 11, 13, 17, 19, 23, 29),
JPlagResult jPlagResult = createJPlagResult(MockMetric.AVG, distribution(EXPECTED_DISTRIBUTION),
comparison(submission("1"), submission("2"), .7), comparison(submission("3"), submission("4"), .3));
// when
var result = metricMapper.getAverageMetric(jPlagResult);

// then
Assertions.assertEquals("AVG", result.name());
Assertions.assertIterableEquals(List.of(2, 3, 5, 7, 11, 13, 17, 19, 23, 29), result.distribution());
Assertions.assertIterableEquals(EXPECTED_DISTRIBUTION, result.distribution());
Assertions.assertEquals(List.of(new TopComparison("1", "2", .7), new TopComparison("3", "4", .3)), result.topComparisons());
Assertions.assertEquals(
"Average of both program coverages. This is the default similarity which"
Expand All @@ -40,23 +42,25 @@ public void test_getAverageMetric() {
@Test
public void test_getMaxMetric() {
// given
JPlagResult jPlagResult = createJPlagResult(MockMetric.MAX, distribution(2, 3, 5, 7, 11, 13, 17, 19, 23, 29),
JPlagResult jPlagResult = createJPlagResult(MockMetric.MAX, distribution(EXPECTED_DISTRIBUTION),
comparison(submission("00"), submission("01"), .7), comparison(submission("10"), submission("11"), .3));
// when
var result = metricMapper.getMaxMetric(jPlagResult);

// then
Assertions.assertEquals("MAX", result.name());
Assertions.assertIterableEquals(List.of(2, 3, 5, 7, 11, 13, 17, 19, 23, 29), result.distribution());
Assertions.assertIterableEquals(EXPECTED_DISTRIBUTION, result.distribution());
Assertions.assertEquals(List.of(new TopComparison("00", "01", .7), new TopComparison("10", "11", .3)), result.topComparisons());
Assertions.assertEquals(
"Maximum of both program coverages. This ranking is especially useful if the programs are very "
+ "different in size. This can happen when dead code was inserted to disguise the origin of the plagiarized program.",
result.description());
}

private int[] distribution(int... numbers) {
return numbers;
private int[] distribution(List<Integer> expectedDistribution) {
var reversedDistribution = new ArrayList<>(expectedDistribution);
Collections.reverse(reversedDistribution);
return reversedDistribution.stream().mapToInt(Integer::intValue).toArray();
}

private CreateSubmission submission(String name) {
Expand Down