• 5 min read

Catching code plagiarism without vector embeddings

Table of Contents

Astra is a code similarity detection system that analyzes Python assignments based on their structure rather than their raw text.

You can read more about this project in this

notebook

Why we built it

Astra started from an observation in our own classes.

When looking at programming assignments, some solutions naturally looked very similar. Whether that similarity came from collaboration, shared resources, or simply students arriving at the same solution was not the question we wanted to answer.

We were interested in a simpler question: how can we measure similarity between pieces of code?

Text comparison is a poor fit for programming assignments.

Two programs can solve the same problem while looking completely different because of renamed variables, changed formatting, reordered functions, or different coding styles. At the same time, two pieces of code can look different as text while sharing almost identical logic.

Since this was an algorithms course project, we approached the problem from an algorithmic perspective.

Code is not just text. It has structure.

Instead of asking whether two files contain similar words, Astra asks whether two programs are built from similar structures.

How it turned out

Astra became a Python-based system that analyzes code similarity through a structural comparison pipeline.

It is available as both a command-line tool and a web application.

The CLI is designed for batch analysis. Given a folder of submissions, it compares files and produces ranked similarity results.

The web application exposes the same pipeline through an interface, making it easier to inspect suspicious pairs and understand why they were considered similar.

Comparing programs by structure, not appearance

The core idea behind Astra is that source code has meaning beyond its characters.

A Python program is first parsed into an Abstract Syntax Tree (AST), which represents the actual structure of the program.

For example, changing:

score = total / count

to:

average = numbers / length

changes the text but keeps the same underlying structure.

Astra removes irrelevant differences through AST normalization, allowing it to focus on the parts that actually describe how the program works.

Breaking programs into comparable pieces

Comparing entire files at once makes it difficult to identify partial similarities.

Astra divides programs into smaller structural chunks such as functions and classes.

This allows the system to identify cases where only certain parts of a submission are similar instead of treating the entire file as one block.

The chunking approach also makes the comparison more flexible when students organize their code differently.

Using classic algorithms for a modern problem

Astra does not use machine learning or vector embeddings.

Instead, it uses traditional algorithms designed around the actual problem.

After converting code structures into sequences, Astra compares them using edit distance techniques.

Specifically, it uses Damerau-Levenshtein distance, which measures how many changes are needed to transform one sequence into another while accounting for insertions, deletions, substitutions, and transpositions.

These algorithms are decades old, but they remain effective because they directly model the problem they are solving.

How we built it

The system was built as an experiment in applying algorithmic thinking to a practical problem.

The pipeline follows several stages:

  1. Parse Python source code into an AST
  2. Normalize the tree by removing irrelevant details
  3. Extract structural chunks
  4. Convert chunks into comparable sequences
  5. Calculate similarity scores between submissions

The hardest part was not implementing the comparison algorithm itself. The harder question was deciding what information matters.

Removing too much structure makes unrelated programs appear similar. Keeping too much detail makes simple changes like variable renaming reduce similarity.

What I learned

Astra reinforced something I have become more conscious of when building software: the newest technology is not always the right technology.

With the rise of AI and ML, it is tempting to reach for embeddings or language models whenever a problem involves understanding text or code. But the first step should always be understanding the problem itself.

For code similarity, the important information is not the wording of the program. It is the structure. A carefully designed algorithm can capture that structure directly, making the system more explainable and easier to reason about.

This project is not meant to argue against AI. It is a reminder that good engineering starts with choosing the right abstraction.

Sometimes that means using a modern model. Sometimes it means using an algorithm from decades ago that already solves the problem well.

Astra was my experiment in the latter.