Other Analyzers

Beyond cosine similarity and winnowing, Analogi uses several supplementary analyzers that catch different plagiarism patterns.


Structure Similarity (Jaccard on Function Names)

Weight: 0.5

Extracts function/method names from both files using language-specific regex, then computes Jaccard similarity:

J(A, B) = |A ∩ B| / |A ∪ B|

What it catches: Students who copy the overall program structure (same function names, same decomposition) even if the implementation details differ.

Threshold: 0.5 (50% of function names shared)


Import/Include Overlap

Weight: 0.3

Jaccard similarity on the list of imported modules/headers.

What it catches: Unusual shared dependencies. If two students both import <algorithm>, <unordered_map>, and <functional> — that’s a signal. Common imports like <iostream> are less suspicious individually, but the combination matters.

Threshold: 0.7 (70% import overlap)


Comment Similarity

Weight: 0.4

Cosine similarity computed on comment text only (extracted separately from code).

What it catches: Students who copy code and forget to change the comments. Even “personalized” code often has identical comment blocks.

Threshold: 0.7 (70% comment similarity)


File Size Ratio

Weight: 0.3

ratio = 1 - |sizeA - sizeB| / max(sizeA, sizeB)

What it catches: A weak signal on its own, but combined with other analyzers, near-identical file sizes (>95% ratio) add confidence that files share a common origin.

Threshold: 0.95 (file sizes within 5% of each other)


Line Count Match

Weight: 0.2

Same formula as file size ratio, but applied to the number of code lines (after comment stripping).

Threshold: 0.95 (line counts within 5%)


Why Multiple Analyzers?

No single metric is perfect:

Attack Cosine Winnowing Structure Comments Size
Copy-paste (no changes)
Rename variables ✗* ✗*
Reorder functions ~✓
Add whitespace/comments ~✗ ~✗
Rewrite logic, keep structure ~✓
Complete rewrite

* = After IdentifierNormalize preprocessing, these become ✓

By combining all signals with weights, Analogi produces a score that’s hard to game without genuinely rewriting the code.