sieve-scope 1.3.0__tar.gz
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- sieve_scope-1.3.0/LICENSE +21 -0
- sieve_scope-1.3.0/PKG-INFO +168 -0
- sieve_scope-1.3.0/README.md +143 -0
- sieve_scope-1.3.0/pyproject.toml +36 -0
- sieve_scope-1.3.0/setup.cfg +4 -0
- sieve_scope-1.3.0/sieve_scope.egg-info/PKG-INFO +168 -0
- sieve_scope-1.3.0/sieve_scope.egg-info/SOURCES.txt +11 -0
- sieve_scope-1.3.0/sieve_scope.egg-info/dependency_links.txt +1 -0
- sieve_scope-1.3.0/sieve_scope.egg-info/top_level.txt +1 -0
- sieve_scope-1.3.0/sieve_scope.py +326 -0
- sieve_scope-1.3.0/tests/test_v1_3_edge_cases.py +157 -0
- sieve_scope-1.3.0/tests/test_v1_3_full_suite.py +246 -0
- sieve_scope-1.3.0/tests/test_v1_3_regression.py +88 -0
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2026 Kai IWASAKI
|
|
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.
|
|
@@ -0,0 +1,168 @@
|
|
|
1
|
+
Metadata-Version: 2.4
|
|
2
|
+
Name: sieve-scope
|
|
3
|
+
Version: 1.3.0
|
|
4
|
+
Summary: Deterministic and Explainable Code Plagiarism Detection Engine with 7-bit Observation Space
|
|
5
|
+
Author: Kai IWASAKI
|
|
6
|
+
License: MIT
|
|
7
|
+
Project-URL: Homepage, https://github.com/neguseatama/sieve-scope
|
|
8
|
+
Project-URL: Repository, https://github.com/neguseatama/sieve-scope.git
|
|
9
|
+
Project-URL: Bug Tracker, https://github.com/neguseatama/sieve-scope/issues
|
|
10
|
+
Classifier: Development Status :: 5 - Production/Stable
|
|
11
|
+
Classifier: Intended Audience :: Developers
|
|
12
|
+
Classifier: Intended Audience :: Education
|
|
13
|
+
Classifier: License :: OSI Approved :: MIT License
|
|
14
|
+
Classifier: Programming Language :: Python :: 3
|
|
15
|
+
Classifier: Programming Language :: Python :: 3.9
|
|
16
|
+
Classifier: Programming Language :: Python :: 3.10
|
|
17
|
+
Classifier: Programming Language :: Python :: 3.11
|
|
18
|
+
Classifier: Programming Language :: Python :: 3.12
|
|
19
|
+
Classifier: Topic :: Software Development :: Libraries :: Python Modules
|
|
20
|
+
Classifier: Topic :: Text Processing :: Linguistic
|
|
21
|
+
Requires-Python: >=3.9
|
|
22
|
+
Description-Content-Type: text/markdown
|
|
23
|
+
License-File: LICENSE
|
|
24
|
+
Dynamic: license-file
|
|
25
|
+
|
|
26
|
+
# Sieve Scope v1.3
|
|
27
|
+
|
|
28
|
+
**English** | [日本語](README.ja.md)
|
|
29
|
+
|
|
30
|
+
> **"See through the formatting, and look into the pure logic of the algorithm."**
|
|
31
|
+
> A fully local, zero-dependency, deterministic (100% reproducible) code plagiarism and structural similarity detection engine.
|
|
32
|
+
> Extends [Sieve-Core](https://github.com/neguseatama/sieve-core)'s deterministic similarity engine and [Sieve-Referee](https://github.com/neguseatama/sieve-referee)'s multi-hypothesis LUT judgment philosophy to the **source code domain**.
|
|
33
|
+
|
|
34
|
+
[](https://github.com/neguseatama/sieve-scope/actions/workflows/test.yml)
|
|
35
|
+
[](https://opensource.org/licenses/MIT)
|
|
36
|
+
[](https://www.python.org/)
|
|
37
|
+
|
|
38
|
+
---
|
|
39
|
+
|
|
40
|
+
## 💡 Concept & Philosophy
|
|
41
|
+
|
|
42
|
+
The starting point of this project is **Sieve-Core**, a core engine that applies the "sieve of set theory" design philosophy of **Sieve-AI**—inspired by the Sieve of Eratosthenes—to the more general domain of text and data processing.
|
|
43
|
+
|
|
44
|
+
Next, **Sieve Referee**, which adds a "sieve of combinatorics" to Sieve-Core, is a zero-dependency Python library that extracts reliable information from noise based on corroboration from multiple independent sources.
|
|
45
|
+
|
|
46
|
+
Then, **Sieve Scope** further adds a two-axis evaluation and redesigns the approach, making it an explainable code plagiarism detection engine that observes the **surface format** (variable names, comments, whitespace) and the **essential logic** (algorithm structure) separately.
|
|
47
|
+
|
|
48
|
+
Traditional string comparison and simple similarity measures struggle to distinguish between:
|
|
49
|
+
- Plagiarism by merely renaming variables (**variable laundering**)
|
|
50
|
+
- Coincidental matches due to shared templates (**boilerplate**)
|
|
51
|
+
|
|
52
|
+
`Sieve Scope` observes two axes independently:
|
|
53
|
+
- **AST (Abstract Syntax Tree)** — extracting the "logic skeleton" with identifiers removed
|
|
54
|
+
- **tokenize** — extracting "identifier vocabulary and order"
|
|
55
|
+
|
|
56
|
+
By inheriting the hypothesis mask (H1–H7) and LUT from Sieve-Referee, it fully explains why a judgment was made.
|
|
57
|
+
|
|
58
|
+
> The name "Sieve Scope" comes from the design philosophy of seeing through the surface of code (format) and comparing only the pure logic, like a microscope.
|
|
59
|
+
|
|
60
|
+
---
|
|
61
|
+
|
|
62
|
+
## 🔥 Key Features
|
|
63
|
+
|
|
64
|
+
- **7-bit Observation Space (H1–H7)**
|
|
65
|
+
Independently evaluates AST skeleton, identifier vocabulary, positional/order (g_POS), constants (g_CONST), and vocabulary context (g_FREQ).
|
|
66
|
+
- **v0_mask compatibility**
|
|
67
|
+
The legacy 4-bit v0_mask is preserved and regression-tested.
|
|
68
|
+
- **Strict Cluster Safety Invariant**
|
|
69
|
+
H4 is promoted to 1 only when the cluster size is at least 3 **and** there is direct similarity evidence (H2∨H3). Indirect "telephone game" chains are never mixed into direct judgments.
|
|
70
|
+
- **Short-Circuit Optimization**
|
|
71
|
+
Pairs with no structural or vocabulary similarity (H2=0 ∧ H3=0) are immediately returned as `1000-000`, skipping expensive hash computations.
|
|
72
|
+
- **Zero Dependencies & Deterministic**
|
|
73
|
+
Implemented using only the Python standard library. No external packages, no API costs, no probabilistic elements.
|
|
74
|
+
|
|
75
|
+
---
|
|
76
|
+
|
|
77
|
+
## 📐 7-bit Observation Space
|
|
78
|
+
|
|
79
|
+
The evaluation function `f_v1.3(C1, C2)` projects a code pair into seven boolean hypotheses `(H1, H2, H3, H4, H5, H6, H7)`.
|
|
80
|
+
|
|
81
|
+
| Hypothesis | Name | What it measures | Criterion / Threshold |
|
|
82
|
+
| :--- | :--- | :--- | :--- |
|
|
83
|
+
| **H1** | Parseability | Can both be parsed as Python syntax? | Success/failure of AST construction |
|
|
84
|
+
| **H2** | AST Skeleton | Do the AST node type sequences match exactly? | Exact match of skeleton strings |
|
|
85
|
+
| **H3** | Identifier Similarity | Jaccard + sequence similarity of identifiers | Score `> 0.50` |
|
|
86
|
+
| **H4** | Cluster Safety | Direct similarity + membership in a valid cluster (size ≥3) | Invariant condition satisfied |
|
|
87
|
+
| **H5** | g_POS | SHA-256 hash of recursive AST field representation | Exact hash match |
|
|
88
|
+
| **H6** | g_CONST | Constants / literals set match | Sorted constant list exact match |
|
|
89
|
+
| **H7** | g_FREQ | Weighted identifier bi-gram Dice coefficient | Score `>= 0.60` |
|
|
90
|
+
|
|
91
|
+
Mask notation is `v0_mask (4-bit) - extension (3-bit)`.
|
|
92
|
+
Example: `1100-011` → H1=1, H2=1, H3=0, H4=0 / H5=0, H6=1, H7=1
|
|
93
|
+
|
|
94
|
+
---
|
|
95
|
+
|
|
96
|
+
## 📊 Representative LUT Patterns
|
|
97
|
+
|
|
98
|
+
| v0_mask | Extended Example | Judgment Label | Description |
|
|
99
|
+
|:---:|:---:|:---|:---|
|
|
100
|
+
| `1110` | `1110-111` | `EXACT_CLONE` | Observation-space exact match |
|
|
101
|
+
| `1100` | `1100-110` | `VARIABLE_LAUNDERING` | Logic matches but surface differs |
|
|
102
|
+
| `1010` | `1010-011` | `COINCIDENTAL_FRAMEWORK_MATCH` | Logic differs but surface matches |
|
|
103
|
+
| `1000` | `1000-000` | `INDEPENDENT_LOGIC` | No direct similarity (short-circuit) |
|
|
104
|
+
| `1110` | `1110-101` | `CONSTANT_MODIFIED_CLONE` | Only constants differ |
|
|
105
|
+
| `1110` | `1110-011` | `PERMUTATED_CLONE` | Non-commutative order reversed |
|
|
106
|
+
|
|
107
|
+
---
|
|
108
|
+
|
|
109
|
+
## 💻 Quick Start
|
|
110
|
+
|
|
111
|
+
```python
|
|
112
|
+
from sieve_scope import SieveScopeEngineV1_3, SieveClusterAnalyzerV1_3
|
|
113
|
+
|
|
114
|
+
engine = SieveScopeEngineV1_3(jaccard_threshold=0.50, freq_dice_threshold=0.60)
|
|
115
|
+
|
|
116
|
+
code_a = "def calc_sum(a, b):\n return a + b"
|
|
117
|
+
code_b = "def calc_sum(x, y):\n return x + y"
|
|
118
|
+
|
|
119
|
+
result = engine.evaluate_pair(code_a, code_b)
|
|
120
|
+
|
|
121
|
+
print(result["v0_mask"]) # e.g., 1100
|
|
122
|
+
print(result["mask"]) # e.g., 1100-110
|
|
123
|
+
|
|
124
|
+
---
|
|
125
|
+
|
|
126
|
+
### Configuration / Thresholds
|
|
127
|
+
|
|
128
|
+
- `jaccard_threshold` (default: `0.50`): Threshold for H3 Multiset Jaccard + sequence similarity.
|
|
129
|
+
- `freq_dice_threshold` (default: `0.60`): Threshold for H7 Weighted identifier bi-gram Dice coefficient.
|
|
130
|
+
|
|
131
|
+
> **Note on Calibration & Defaults (v1.3)**:
|
|
132
|
+
> Exhaustive grid search experiments on synthetic benchmark datasets demonstrate optimal class separation ($F1 = 1.0000$) across a wide threshold range of `0.35` to `0.75`. However, the default threshold parameters are strictly maintained at **`0.50` / `0.60`** in order to preserve backwards compatibility with v0, maintain regression test stability, and prevent potential false positives caused by shared domain vocabulary in production codebases.
|
|
133
|
+
|
|
134
|
+
---
|
|
135
|
+
|
|
136
|
+
## 🔬 Testing & Verification
|
|
137
|
+
Cross-Python Validation Summary
|
|
138
|
+
24 regression cases (test_v1_3_full_suite.py): PASSED
|
|
139
|
+
|
|
140
|
+
5 compatibility tests (test_v1_3_regression.py): PASSED
|
|
141
|
+
|
|
142
|
+
6 edge-case & parallel determinism tests (test_v1_3_edge_cases.py): PASSED
|
|
143
|
+
|
|
144
|
+
81 synthetic threshold configurations (threshold_tuning.py): PASSED
|
|
145
|
+
|
|
146
|
+
All test suites and synthetic experiments passed completely without errors across Python 3.9, 3.10, 3.11, and 3.12.
|
|
147
|
+
|
|
148
|
+
Threshold Calibration & Synthetic Validation
|
|
149
|
+
The threshold parameters (H3 Multiset Jaccard: 0.50, H7 Weighted Bi-gram Dice: 0.60) were designed and calibrated using a synthetic validation pair set (Positive 6 pairs / Negative 3 pairs).
|
|
150
|
+
The engine's 1110-111 indicates an exact match in the current 7-dimensional observation space (Observation Clones), and does not guarantee complete semantic equivalence (Semantic Clones).
|
|
151
|
+
|
|
152
|
+
---
|
|
153
|
+
|
|
154
|
+
## 📚 Documentation
|
|
155
|
+
|
|
156
|
+
- 🏛️ Architecture Specification
|
|
157
|
+
|
|
158
|
+
- 🔌 API & Integration Guide
|
|
159
|
+
|
|
160
|
+
- 🚀 Deployment Guide
|
|
161
|
+
|
|
162
|
+
- 🔐 CI/CD & Security Guide
|
|
163
|
+
|
|
164
|
+
## 📄 License
|
|
165
|
+
MIT License. See LICENSE for details.
|
|
166
|
+
|
|
167
|
+
## 👤 Author
|
|
168
|
+
Kai IWASAKI
|
|
@@ -0,0 +1,143 @@
|
|
|
1
|
+
# Sieve Scope v1.3
|
|
2
|
+
|
|
3
|
+
**English** | [日本語](README.ja.md)
|
|
4
|
+
|
|
5
|
+
> **"See through the formatting, and look into the pure logic of the algorithm."**
|
|
6
|
+
> A fully local, zero-dependency, deterministic (100% reproducible) code plagiarism and structural similarity detection engine.
|
|
7
|
+
> Extends [Sieve-Core](https://github.com/neguseatama/sieve-core)'s deterministic similarity engine and [Sieve-Referee](https://github.com/neguseatama/sieve-referee)'s multi-hypothesis LUT judgment philosophy to the **source code domain**.
|
|
8
|
+
|
|
9
|
+
[](https://github.com/neguseatama/sieve-scope/actions/workflows/test.yml)
|
|
10
|
+
[](https://opensource.org/licenses/MIT)
|
|
11
|
+
[](https://www.python.org/)
|
|
12
|
+
|
|
13
|
+
---
|
|
14
|
+
|
|
15
|
+
## 💡 Concept & Philosophy
|
|
16
|
+
|
|
17
|
+
The starting point of this project is **Sieve-Core**, a core engine that applies the "sieve of set theory" design philosophy of **Sieve-AI**—inspired by the Sieve of Eratosthenes—to the more general domain of text and data processing.
|
|
18
|
+
|
|
19
|
+
Next, **Sieve Referee**, which adds a "sieve of combinatorics" to Sieve-Core, is a zero-dependency Python library that extracts reliable information from noise based on corroboration from multiple independent sources.
|
|
20
|
+
|
|
21
|
+
Then, **Sieve Scope** further adds a two-axis evaluation and redesigns the approach, making it an explainable code plagiarism detection engine that observes the **surface format** (variable names, comments, whitespace) and the **essential logic** (algorithm structure) separately.
|
|
22
|
+
|
|
23
|
+
Traditional string comparison and simple similarity measures struggle to distinguish between:
|
|
24
|
+
- Plagiarism by merely renaming variables (**variable laundering**)
|
|
25
|
+
- Coincidental matches due to shared templates (**boilerplate**)
|
|
26
|
+
|
|
27
|
+
`Sieve Scope` observes two axes independently:
|
|
28
|
+
- **AST (Abstract Syntax Tree)** — extracting the "logic skeleton" with identifiers removed
|
|
29
|
+
- **tokenize** — extracting "identifier vocabulary and order"
|
|
30
|
+
|
|
31
|
+
By inheriting the hypothesis mask (H1–H7) and LUT from Sieve-Referee, it fully explains why a judgment was made.
|
|
32
|
+
|
|
33
|
+
> The name "Sieve Scope" comes from the design philosophy of seeing through the surface of code (format) and comparing only the pure logic, like a microscope.
|
|
34
|
+
|
|
35
|
+
---
|
|
36
|
+
|
|
37
|
+
## 🔥 Key Features
|
|
38
|
+
|
|
39
|
+
- **7-bit Observation Space (H1–H7)**
|
|
40
|
+
Independently evaluates AST skeleton, identifier vocabulary, positional/order (g_POS), constants (g_CONST), and vocabulary context (g_FREQ).
|
|
41
|
+
- **v0_mask compatibility**
|
|
42
|
+
The legacy 4-bit v0_mask is preserved and regression-tested.
|
|
43
|
+
- **Strict Cluster Safety Invariant**
|
|
44
|
+
H4 is promoted to 1 only when the cluster size is at least 3 **and** there is direct similarity evidence (H2∨H3). Indirect "telephone game" chains are never mixed into direct judgments.
|
|
45
|
+
- **Short-Circuit Optimization**
|
|
46
|
+
Pairs with no structural or vocabulary similarity (H2=0 ∧ H3=0) are immediately returned as `1000-000`, skipping expensive hash computations.
|
|
47
|
+
- **Zero Dependencies & Deterministic**
|
|
48
|
+
Implemented using only the Python standard library. No external packages, no API costs, no probabilistic elements.
|
|
49
|
+
|
|
50
|
+
---
|
|
51
|
+
|
|
52
|
+
## 📐 7-bit Observation Space
|
|
53
|
+
|
|
54
|
+
The evaluation function `f_v1.3(C1, C2)` projects a code pair into seven boolean hypotheses `(H1, H2, H3, H4, H5, H6, H7)`.
|
|
55
|
+
|
|
56
|
+
| Hypothesis | Name | What it measures | Criterion / Threshold |
|
|
57
|
+
| :--- | :--- | :--- | :--- |
|
|
58
|
+
| **H1** | Parseability | Can both be parsed as Python syntax? | Success/failure of AST construction |
|
|
59
|
+
| **H2** | AST Skeleton | Do the AST node type sequences match exactly? | Exact match of skeleton strings |
|
|
60
|
+
| **H3** | Identifier Similarity | Jaccard + sequence similarity of identifiers | Score `> 0.50` |
|
|
61
|
+
| **H4** | Cluster Safety | Direct similarity + membership in a valid cluster (size ≥3) | Invariant condition satisfied |
|
|
62
|
+
| **H5** | g_POS | SHA-256 hash of recursive AST field representation | Exact hash match |
|
|
63
|
+
| **H6** | g_CONST | Constants / literals set match | Sorted constant list exact match |
|
|
64
|
+
| **H7** | g_FREQ | Weighted identifier bi-gram Dice coefficient | Score `>= 0.60` |
|
|
65
|
+
|
|
66
|
+
Mask notation is `v0_mask (4-bit) - extension (3-bit)`.
|
|
67
|
+
Example: `1100-011` → H1=1, H2=1, H3=0, H4=0 / H5=0, H6=1, H7=1
|
|
68
|
+
|
|
69
|
+
---
|
|
70
|
+
|
|
71
|
+
## 📊 Representative LUT Patterns
|
|
72
|
+
|
|
73
|
+
| v0_mask | Extended Example | Judgment Label | Description |
|
|
74
|
+
|:---:|:---:|:---|:---|
|
|
75
|
+
| `1110` | `1110-111` | `EXACT_CLONE` | Observation-space exact match |
|
|
76
|
+
| `1100` | `1100-110` | `VARIABLE_LAUNDERING` | Logic matches but surface differs |
|
|
77
|
+
| `1010` | `1010-011` | `COINCIDENTAL_FRAMEWORK_MATCH` | Logic differs but surface matches |
|
|
78
|
+
| `1000` | `1000-000` | `INDEPENDENT_LOGIC` | No direct similarity (short-circuit) |
|
|
79
|
+
| `1110` | `1110-101` | `CONSTANT_MODIFIED_CLONE` | Only constants differ |
|
|
80
|
+
| `1110` | `1110-011` | `PERMUTATED_CLONE` | Non-commutative order reversed |
|
|
81
|
+
|
|
82
|
+
---
|
|
83
|
+
|
|
84
|
+
## 💻 Quick Start
|
|
85
|
+
|
|
86
|
+
```python
|
|
87
|
+
from sieve_scope import SieveScopeEngineV1_3, SieveClusterAnalyzerV1_3
|
|
88
|
+
|
|
89
|
+
engine = SieveScopeEngineV1_3(jaccard_threshold=0.50, freq_dice_threshold=0.60)
|
|
90
|
+
|
|
91
|
+
code_a = "def calc_sum(a, b):\n return a + b"
|
|
92
|
+
code_b = "def calc_sum(x, y):\n return x + y"
|
|
93
|
+
|
|
94
|
+
result = engine.evaluate_pair(code_a, code_b)
|
|
95
|
+
|
|
96
|
+
print(result["v0_mask"]) # e.g., 1100
|
|
97
|
+
print(result["mask"]) # e.g., 1100-110
|
|
98
|
+
|
|
99
|
+
---
|
|
100
|
+
|
|
101
|
+
### Configuration / Thresholds
|
|
102
|
+
|
|
103
|
+
- `jaccard_threshold` (default: `0.50`): Threshold for H3 Multiset Jaccard + sequence similarity.
|
|
104
|
+
- `freq_dice_threshold` (default: `0.60`): Threshold for H7 Weighted identifier bi-gram Dice coefficient.
|
|
105
|
+
|
|
106
|
+
> **Note on Calibration & Defaults (v1.3)**:
|
|
107
|
+
> Exhaustive grid search experiments on synthetic benchmark datasets demonstrate optimal class separation ($F1 = 1.0000$) across a wide threshold range of `0.35` to `0.75`. However, the default threshold parameters are strictly maintained at **`0.50` / `0.60`** in order to preserve backwards compatibility with v0, maintain regression test stability, and prevent potential false positives caused by shared domain vocabulary in production codebases.
|
|
108
|
+
|
|
109
|
+
---
|
|
110
|
+
|
|
111
|
+
## 🔬 Testing & Verification
|
|
112
|
+
Cross-Python Validation Summary
|
|
113
|
+
24 regression cases (test_v1_3_full_suite.py): PASSED
|
|
114
|
+
|
|
115
|
+
5 compatibility tests (test_v1_3_regression.py): PASSED
|
|
116
|
+
|
|
117
|
+
6 edge-case & parallel determinism tests (test_v1_3_edge_cases.py): PASSED
|
|
118
|
+
|
|
119
|
+
81 synthetic threshold configurations (threshold_tuning.py): PASSED
|
|
120
|
+
|
|
121
|
+
All test suites and synthetic experiments passed completely without errors across Python 3.9, 3.10, 3.11, and 3.12.
|
|
122
|
+
|
|
123
|
+
Threshold Calibration & Synthetic Validation
|
|
124
|
+
The threshold parameters (H3 Multiset Jaccard: 0.50, H7 Weighted Bi-gram Dice: 0.60) were designed and calibrated using a synthetic validation pair set (Positive 6 pairs / Negative 3 pairs).
|
|
125
|
+
The engine's 1110-111 indicates an exact match in the current 7-dimensional observation space (Observation Clones), and does not guarantee complete semantic equivalence (Semantic Clones).
|
|
126
|
+
|
|
127
|
+
---
|
|
128
|
+
|
|
129
|
+
## 📚 Documentation
|
|
130
|
+
|
|
131
|
+
- 🏛️ Architecture Specification
|
|
132
|
+
|
|
133
|
+
- 🔌 API & Integration Guide
|
|
134
|
+
|
|
135
|
+
- 🚀 Deployment Guide
|
|
136
|
+
|
|
137
|
+
- 🔐 CI/CD & Security Guide
|
|
138
|
+
|
|
139
|
+
## 📄 License
|
|
140
|
+
MIT License. See LICENSE for details.
|
|
141
|
+
|
|
142
|
+
## 👤 Author
|
|
143
|
+
Kai IWASAKI
|
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
[build-system]
|
|
2
|
+
requires = ["setuptools>=61.0"]
|
|
3
|
+
build-backend = "setuptools.build_meta"
|
|
4
|
+
|
|
5
|
+
[project]
|
|
6
|
+
name = "sieve-scope"
|
|
7
|
+
version = "1.3.0"
|
|
8
|
+
description = "Deterministic and Explainable Code Plagiarism Detection Engine with 7-bit Observation Space"
|
|
9
|
+
readme = "README.md"
|
|
10
|
+
authors = [
|
|
11
|
+
{ name = "Kai IWASAKI" }
|
|
12
|
+
]
|
|
13
|
+
license = { text = "MIT" }
|
|
14
|
+
classifiers = [
|
|
15
|
+
"Development Status :: 5 - Production/Stable",
|
|
16
|
+
"Intended Audience :: Developers",
|
|
17
|
+
"Intended Audience :: Education",
|
|
18
|
+
"License :: OSI Approved :: MIT License",
|
|
19
|
+
"Programming Language :: Python :: 3",
|
|
20
|
+
"Programming Language :: Python :: 3.9",
|
|
21
|
+
"Programming Language :: Python :: 3.10",
|
|
22
|
+
"Programming Language :: Python :: 3.11",
|
|
23
|
+
"Programming Language :: Python :: 3.12",
|
|
24
|
+
"Topic :: Software Development :: Libraries :: Python Modules",
|
|
25
|
+
"Topic :: Text Processing :: Linguistic"
|
|
26
|
+
]
|
|
27
|
+
requires-python = ">=3.9"
|
|
28
|
+
dependencies = []
|
|
29
|
+
|
|
30
|
+
[project.urls]
|
|
31
|
+
Homepage = "https://github.com/neguseatama/sieve-scope"
|
|
32
|
+
Repository = "https://github.com/neguseatama/sieve-scope.git"
|
|
33
|
+
"Bug Tracker" = "https://github.com/neguseatama/sieve-scope/issues"
|
|
34
|
+
|
|
35
|
+
[tool.setuptools]
|
|
36
|
+
py-modules = ["sieve_scope"]
|
|
@@ -0,0 +1,168 @@
|
|
|
1
|
+
Metadata-Version: 2.4
|
|
2
|
+
Name: sieve-scope
|
|
3
|
+
Version: 1.3.0
|
|
4
|
+
Summary: Deterministic and Explainable Code Plagiarism Detection Engine with 7-bit Observation Space
|
|
5
|
+
Author: Kai IWASAKI
|
|
6
|
+
License: MIT
|
|
7
|
+
Project-URL: Homepage, https://github.com/neguseatama/sieve-scope
|
|
8
|
+
Project-URL: Repository, https://github.com/neguseatama/sieve-scope.git
|
|
9
|
+
Project-URL: Bug Tracker, https://github.com/neguseatama/sieve-scope/issues
|
|
10
|
+
Classifier: Development Status :: 5 - Production/Stable
|
|
11
|
+
Classifier: Intended Audience :: Developers
|
|
12
|
+
Classifier: Intended Audience :: Education
|
|
13
|
+
Classifier: License :: OSI Approved :: MIT License
|
|
14
|
+
Classifier: Programming Language :: Python :: 3
|
|
15
|
+
Classifier: Programming Language :: Python :: 3.9
|
|
16
|
+
Classifier: Programming Language :: Python :: 3.10
|
|
17
|
+
Classifier: Programming Language :: Python :: 3.11
|
|
18
|
+
Classifier: Programming Language :: Python :: 3.12
|
|
19
|
+
Classifier: Topic :: Software Development :: Libraries :: Python Modules
|
|
20
|
+
Classifier: Topic :: Text Processing :: Linguistic
|
|
21
|
+
Requires-Python: >=3.9
|
|
22
|
+
Description-Content-Type: text/markdown
|
|
23
|
+
License-File: LICENSE
|
|
24
|
+
Dynamic: license-file
|
|
25
|
+
|
|
26
|
+
# Sieve Scope v1.3
|
|
27
|
+
|
|
28
|
+
**English** | [日本語](README.ja.md)
|
|
29
|
+
|
|
30
|
+
> **"See through the formatting, and look into the pure logic of the algorithm."**
|
|
31
|
+
> A fully local, zero-dependency, deterministic (100% reproducible) code plagiarism and structural similarity detection engine.
|
|
32
|
+
> Extends [Sieve-Core](https://github.com/neguseatama/sieve-core)'s deterministic similarity engine and [Sieve-Referee](https://github.com/neguseatama/sieve-referee)'s multi-hypothesis LUT judgment philosophy to the **source code domain**.
|
|
33
|
+
|
|
34
|
+
[](https://github.com/neguseatama/sieve-scope/actions/workflows/test.yml)
|
|
35
|
+
[](https://opensource.org/licenses/MIT)
|
|
36
|
+
[](https://www.python.org/)
|
|
37
|
+
|
|
38
|
+
---
|
|
39
|
+
|
|
40
|
+
## 💡 Concept & Philosophy
|
|
41
|
+
|
|
42
|
+
The starting point of this project is **Sieve-Core**, a core engine that applies the "sieve of set theory" design philosophy of **Sieve-AI**—inspired by the Sieve of Eratosthenes—to the more general domain of text and data processing.
|
|
43
|
+
|
|
44
|
+
Next, **Sieve Referee**, which adds a "sieve of combinatorics" to Sieve-Core, is a zero-dependency Python library that extracts reliable information from noise based on corroboration from multiple independent sources.
|
|
45
|
+
|
|
46
|
+
Then, **Sieve Scope** further adds a two-axis evaluation and redesigns the approach, making it an explainable code plagiarism detection engine that observes the **surface format** (variable names, comments, whitespace) and the **essential logic** (algorithm structure) separately.
|
|
47
|
+
|
|
48
|
+
Traditional string comparison and simple similarity measures struggle to distinguish between:
|
|
49
|
+
- Plagiarism by merely renaming variables (**variable laundering**)
|
|
50
|
+
- Coincidental matches due to shared templates (**boilerplate**)
|
|
51
|
+
|
|
52
|
+
`Sieve Scope` observes two axes independently:
|
|
53
|
+
- **AST (Abstract Syntax Tree)** — extracting the "logic skeleton" with identifiers removed
|
|
54
|
+
- **tokenize** — extracting "identifier vocabulary and order"
|
|
55
|
+
|
|
56
|
+
By inheriting the hypothesis mask (H1–H7) and LUT from Sieve-Referee, it fully explains why a judgment was made.
|
|
57
|
+
|
|
58
|
+
> The name "Sieve Scope" comes from the design philosophy of seeing through the surface of code (format) and comparing only the pure logic, like a microscope.
|
|
59
|
+
|
|
60
|
+
---
|
|
61
|
+
|
|
62
|
+
## 🔥 Key Features
|
|
63
|
+
|
|
64
|
+
- **7-bit Observation Space (H1–H7)**
|
|
65
|
+
Independently evaluates AST skeleton, identifier vocabulary, positional/order (g_POS), constants (g_CONST), and vocabulary context (g_FREQ).
|
|
66
|
+
- **v0_mask compatibility**
|
|
67
|
+
The legacy 4-bit v0_mask is preserved and regression-tested.
|
|
68
|
+
- **Strict Cluster Safety Invariant**
|
|
69
|
+
H4 is promoted to 1 only when the cluster size is at least 3 **and** there is direct similarity evidence (H2∨H3). Indirect "telephone game" chains are never mixed into direct judgments.
|
|
70
|
+
- **Short-Circuit Optimization**
|
|
71
|
+
Pairs with no structural or vocabulary similarity (H2=0 ∧ H3=0) are immediately returned as `1000-000`, skipping expensive hash computations.
|
|
72
|
+
- **Zero Dependencies & Deterministic**
|
|
73
|
+
Implemented using only the Python standard library. No external packages, no API costs, no probabilistic elements.
|
|
74
|
+
|
|
75
|
+
---
|
|
76
|
+
|
|
77
|
+
## 📐 7-bit Observation Space
|
|
78
|
+
|
|
79
|
+
The evaluation function `f_v1.3(C1, C2)` projects a code pair into seven boolean hypotheses `(H1, H2, H3, H4, H5, H6, H7)`.
|
|
80
|
+
|
|
81
|
+
| Hypothesis | Name | What it measures | Criterion / Threshold |
|
|
82
|
+
| :--- | :--- | :--- | :--- |
|
|
83
|
+
| **H1** | Parseability | Can both be parsed as Python syntax? | Success/failure of AST construction |
|
|
84
|
+
| **H2** | AST Skeleton | Do the AST node type sequences match exactly? | Exact match of skeleton strings |
|
|
85
|
+
| **H3** | Identifier Similarity | Jaccard + sequence similarity of identifiers | Score `> 0.50` |
|
|
86
|
+
| **H4** | Cluster Safety | Direct similarity + membership in a valid cluster (size ≥3) | Invariant condition satisfied |
|
|
87
|
+
| **H5** | g_POS | SHA-256 hash of recursive AST field representation | Exact hash match |
|
|
88
|
+
| **H6** | g_CONST | Constants / literals set match | Sorted constant list exact match |
|
|
89
|
+
| **H7** | g_FREQ | Weighted identifier bi-gram Dice coefficient | Score `>= 0.60` |
|
|
90
|
+
|
|
91
|
+
Mask notation is `v0_mask (4-bit) - extension (3-bit)`.
|
|
92
|
+
Example: `1100-011` → H1=1, H2=1, H3=0, H4=0 / H5=0, H6=1, H7=1
|
|
93
|
+
|
|
94
|
+
---
|
|
95
|
+
|
|
96
|
+
## 📊 Representative LUT Patterns
|
|
97
|
+
|
|
98
|
+
| v0_mask | Extended Example | Judgment Label | Description |
|
|
99
|
+
|:---:|:---:|:---|:---|
|
|
100
|
+
| `1110` | `1110-111` | `EXACT_CLONE` | Observation-space exact match |
|
|
101
|
+
| `1100` | `1100-110` | `VARIABLE_LAUNDERING` | Logic matches but surface differs |
|
|
102
|
+
| `1010` | `1010-011` | `COINCIDENTAL_FRAMEWORK_MATCH` | Logic differs but surface matches |
|
|
103
|
+
| `1000` | `1000-000` | `INDEPENDENT_LOGIC` | No direct similarity (short-circuit) |
|
|
104
|
+
| `1110` | `1110-101` | `CONSTANT_MODIFIED_CLONE` | Only constants differ |
|
|
105
|
+
| `1110` | `1110-011` | `PERMUTATED_CLONE` | Non-commutative order reversed |
|
|
106
|
+
|
|
107
|
+
---
|
|
108
|
+
|
|
109
|
+
## 💻 Quick Start
|
|
110
|
+
|
|
111
|
+
```python
|
|
112
|
+
from sieve_scope import SieveScopeEngineV1_3, SieveClusterAnalyzerV1_3
|
|
113
|
+
|
|
114
|
+
engine = SieveScopeEngineV1_3(jaccard_threshold=0.50, freq_dice_threshold=0.60)
|
|
115
|
+
|
|
116
|
+
code_a = "def calc_sum(a, b):\n return a + b"
|
|
117
|
+
code_b = "def calc_sum(x, y):\n return x + y"
|
|
118
|
+
|
|
119
|
+
result = engine.evaluate_pair(code_a, code_b)
|
|
120
|
+
|
|
121
|
+
print(result["v0_mask"]) # e.g., 1100
|
|
122
|
+
print(result["mask"]) # e.g., 1100-110
|
|
123
|
+
|
|
124
|
+
---
|
|
125
|
+
|
|
126
|
+
### Configuration / Thresholds
|
|
127
|
+
|
|
128
|
+
- `jaccard_threshold` (default: `0.50`): Threshold for H3 Multiset Jaccard + sequence similarity.
|
|
129
|
+
- `freq_dice_threshold` (default: `0.60`): Threshold for H7 Weighted identifier bi-gram Dice coefficient.
|
|
130
|
+
|
|
131
|
+
> **Note on Calibration & Defaults (v1.3)**:
|
|
132
|
+
> Exhaustive grid search experiments on synthetic benchmark datasets demonstrate optimal class separation ($F1 = 1.0000$) across a wide threshold range of `0.35` to `0.75`. However, the default threshold parameters are strictly maintained at **`0.50` / `0.60`** in order to preserve backwards compatibility with v0, maintain regression test stability, and prevent potential false positives caused by shared domain vocabulary in production codebases.
|
|
133
|
+
|
|
134
|
+
---
|
|
135
|
+
|
|
136
|
+
## 🔬 Testing & Verification
|
|
137
|
+
Cross-Python Validation Summary
|
|
138
|
+
24 regression cases (test_v1_3_full_suite.py): PASSED
|
|
139
|
+
|
|
140
|
+
5 compatibility tests (test_v1_3_regression.py): PASSED
|
|
141
|
+
|
|
142
|
+
6 edge-case & parallel determinism tests (test_v1_3_edge_cases.py): PASSED
|
|
143
|
+
|
|
144
|
+
81 synthetic threshold configurations (threshold_tuning.py): PASSED
|
|
145
|
+
|
|
146
|
+
All test suites and synthetic experiments passed completely without errors across Python 3.9, 3.10, 3.11, and 3.12.
|
|
147
|
+
|
|
148
|
+
Threshold Calibration & Synthetic Validation
|
|
149
|
+
The threshold parameters (H3 Multiset Jaccard: 0.50, H7 Weighted Bi-gram Dice: 0.60) were designed and calibrated using a synthetic validation pair set (Positive 6 pairs / Negative 3 pairs).
|
|
150
|
+
The engine's 1110-111 indicates an exact match in the current 7-dimensional observation space (Observation Clones), and does not guarantee complete semantic equivalence (Semantic Clones).
|
|
151
|
+
|
|
152
|
+
---
|
|
153
|
+
|
|
154
|
+
## 📚 Documentation
|
|
155
|
+
|
|
156
|
+
- 🏛️ Architecture Specification
|
|
157
|
+
|
|
158
|
+
- 🔌 API & Integration Guide
|
|
159
|
+
|
|
160
|
+
- 🚀 Deployment Guide
|
|
161
|
+
|
|
162
|
+
- 🔐 CI/CD & Security Guide
|
|
163
|
+
|
|
164
|
+
## 📄 License
|
|
165
|
+
MIT License. See LICENSE for details.
|
|
166
|
+
|
|
167
|
+
## 👤 Author
|
|
168
|
+
Kai IWASAKI
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
LICENSE
|
|
2
|
+
README.md
|
|
3
|
+
pyproject.toml
|
|
4
|
+
sieve_scope.py
|
|
5
|
+
sieve_scope.egg-info/PKG-INFO
|
|
6
|
+
sieve_scope.egg-info/SOURCES.txt
|
|
7
|
+
sieve_scope.egg-info/dependency_links.txt
|
|
8
|
+
sieve_scope.egg-info/top_level.txt
|
|
9
|
+
tests/test_v1_3_edge_cases.py
|
|
10
|
+
tests/test_v1_3_full_suite.py
|
|
11
|
+
tests/test_v1_3_regression.py
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
sieve_scope
|