research-diff 0.1.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.
- research_diff-0.1.0/.gitattributes +2 -0
- research_diff-0.1.0/.github/workflows/ci.yml +37 -0
- research_diff-0.1.0/.github/workflows/release.yml +41 -0
- research_diff-0.1.0/.gitignore +15 -0
- research_diff-0.1.0/LICENSE +21 -0
- research_diff-0.1.0/PKG-INFO +111 -0
- research_diff-0.1.0/README.md +88 -0
- research_diff-0.1.0/docs/research.svg +78 -0
- research_diff-0.1.0/examples/batch-size/configs/e1.yaml +10 -0
- research_diff-0.1.0/examples/batch-size/notes/ideas.md +15 -0
- research_diff-0.1.0/examples/batch-size/notes/results.md +7 -0
- research_diff-0.1.0/examples/batch-size/out/e1.json +1 -0
- research_diff-0.1.0/examples/batch-size/paper/main.tex +7 -0
- research_diff-0.1.0/pyproject.toml +40 -0
- research_diff-0.1.0/research-diff.toml +8 -0
- research_diff-0.1.0/src/research_diff/__init__.py +2 -0
- research_diff-0.1.0/src/research_diff/__main__.py +5 -0
- research_diff-0.1.0/src/research_diff/agent.py +141 -0
- research_diff-0.1.0/src/research_diff/cli.py +153 -0
- research_diff-0.1.0/src/research_diff/compare.py +76 -0
- research_diff-0.1.0/src/research_diff/config.py +61 -0
- research_diff-0.1.0/src/research_diff/diff.py +106 -0
- research_diff-0.1.0/src/research_diff/extract.py +327 -0
- research_diff-0.1.0/src/research_diff/graph.py +94 -0
- research_diff-0.1.0/src/research_diff/mcp_server.py +112 -0
- research_diff-0.1.0/src/research_diff/readme.py +38 -0
- research_diff-0.1.0/src/research_diff/suggest.py +154 -0
- research_diff-0.1.0/src/research_diff/trackers.py +103 -0
- research_diff-0.1.0/src/research_diff/watch.py +69 -0
- research_diff-0.1.0/tests/conftest.py +46 -0
- research_diff-0.1.0/tests/test_research_diff.py +153 -0
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
name: ci
|
|
2
|
+
|
|
3
|
+
on:
|
|
4
|
+
push:
|
|
5
|
+
branches: [main]
|
|
6
|
+
pull_request:
|
|
7
|
+
|
|
8
|
+
permissions:
|
|
9
|
+
contents: read
|
|
10
|
+
|
|
11
|
+
jobs:
|
|
12
|
+
test:
|
|
13
|
+
strategy:
|
|
14
|
+
fail-fast: false
|
|
15
|
+
matrix:
|
|
16
|
+
os: [ubuntu-latest, windows-latest]
|
|
17
|
+
python: ["3.11", "3.12", "3.13"]
|
|
18
|
+
runs-on: ${{ matrix.os }}
|
|
19
|
+
steps:
|
|
20
|
+
- uses: actions/checkout@v4
|
|
21
|
+
- uses: actions/setup-python@v5
|
|
22
|
+
with:
|
|
23
|
+
python-version: ${{ matrix.python }}
|
|
24
|
+
- run: python -m pip install -e ".[dev]"
|
|
25
|
+
- run: python -m pytest -q
|
|
26
|
+
|
|
27
|
+
map:
|
|
28
|
+
# The README's research map is drawn from examples/: it must be current.
|
|
29
|
+
runs-on: ubuntu-latest
|
|
30
|
+
steps:
|
|
31
|
+
- uses: actions/checkout@v4
|
|
32
|
+
- uses: actions/setup-python@v5
|
|
33
|
+
with:
|
|
34
|
+
python-version: "3.12"
|
|
35
|
+
- run: python -m pip install -e .
|
|
36
|
+
- name: The research map is current (if not, run research-diff readme and commit)
|
|
37
|
+
run: research-diff readme --check
|
|
@@ -0,0 +1,41 @@
|
|
|
1
|
+
name: release
|
|
2
|
+
|
|
3
|
+
# A tag vX.Y.Z publishes that version to PyPI through trusted publishing: no token is stored anywhere. PyPI accepts the
|
|
4
|
+
# upload only from this workflow, in this repository, in the `pypi` environment.
|
|
5
|
+
on:
|
|
6
|
+
push:
|
|
7
|
+
tags: ["v*"]
|
|
8
|
+
|
|
9
|
+
permissions:
|
|
10
|
+
contents: read
|
|
11
|
+
|
|
12
|
+
jobs:
|
|
13
|
+
build:
|
|
14
|
+
runs-on: ubuntu-latest
|
|
15
|
+
steps:
|
|
16
|
+
- uses: actions/checkout@v4
|
|
17
|
+
- uses: actions/setup-python@v5
|
|
18
|
+
with:
|
|
19
|
+
python-version: "3.12"
|
|
20
|
+
- name: The tag is the version in pyproject.toml
|
|
21
|
+
run: |
|
|
22
|
+
v=$(python -c "import tomllib; print(tomllib.load(open('pyproject.toml', 'rb'))['project']['version'])")
|
|
23
|
+
[ "v$v" = "$GITHUB_REF_NAME" ] || { echo "tag $GITHUB_REF_NAME, but pyproject.toml says $v"; exit 1; }
|
|
24
|
+
- run: python -m pip install build && python -m build
|
|
25
|
+
- uses: actions/upload-artifact@v4
|
|
26
|
+
with:
|
|
27
|
+
name: dist
|
|
28
|
+
path: dist
|
|
29
|
+
|
|
30
|
+
publish:
|
|
31
|
+
needs: build
|
|
32
|
+
runs-on: ubuntu-latest
|
|
33
|
+
environment: pypi
|
|
34
|
+
permissions:
|
|
35
|
+
id-token: write
|
|
36
|
+
steps:
|
|
37
|
+
- uses: actions/download-artifact@v4
|
|
38
|
+
with:
|
|
39
|
+
name: dist
|
|
40
|
+
path: dist
|
|
41
|
+
- uses: pypa/gh-action-pypi-publish@release/v1
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2026 simplifiedmachine
|
|
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,111 @@
|
|
|
1
|
+
Metadata-Version: 2.5
|
|
2
|
+
Name: research-diff
|
|
3
|
+
Version: 0.1.0
|
|
4
|
+
Summary: Maps your research from its notes, experiment configs, results and paper (questions, hypotheses, experiments, results, claims) and shows what each iteration changed. Built for exploring ideas with AI coding agents.
|
|
5
|
+
Project-URL: Homepage, https://github.com/simplifiedmachine/research-diff
|
|
6
|
+
Project-URL: Documentation, https://github.com/simplifiedmachine/research-diff/wiki
|
|
7
|
+
Author: simplifiedmachine
|
|
8
|
+
License-Expression: MIT
|
|
9
|
+
License-File: LICENSE
|
|
10
|
+
Keywords: ai-agents,claude-code,experiment-tracking,hypotheses,mcp,reproducibility,research
|
|
11
|
+
Classifier: Development Status :: 3 - Alpha
|
|
12
|
+
Classifier: Intended Audience :: Science/Research
|
|
13
|
+
Classifier: Programming Language :: Python :: 3 :: Only
|
|
14
|
+
Classifier: Topic :: Scientific/Engineering
|
|
15
|
+
Requires-Python: >=3.11
|
|
16
|
+
Requires-Dist: system-diff==0.1.0
|
|
17
|
+
Provides-Extra: dev
|
|
18
|
+
Requires-Dist: mcp>=1.10; extra == 'dev'
|
|
19
|
+
Requires-Dist: pytest>=8; extra == 'dev'
|
|
20
|
+
Provides-Extra: mcp
|
|
21
|
+
Requires-Dist: mcp>=1.10; extra == 'mcp'
|
|
22
|
+
Description-Content-Type: text/markdown
|
|
23
|
+
|
|
24
|
+
# research-diff
|
|
25
|
+
|
|
26
|
+
Maps your research from its notes, experiment configs, results and paper (questions, hypotheses, experiments,
|
|
27
|
+
results, claims) and shows what each iteration changed. Built for exploring ideas with AI coding agents.
|
|
28
|
+
|
|
29
|
+
<!-- research-map:begin -->
|
|
30
|
+

|
|
31
|
+
|
|
32
|
+
<details><summary>1 open warning</summary>
|
|
33
|
+
|
|
34
|
+
- H2 is open and no experiment tests it
|
|
35
|
+
|
|
36
|
+
</details>
|
|
37
|
+
<!-- research-map:end -->
|
|
38
|
+
|
|
39
|
+
The map above is this repository's own example (`examples/batch-size`), regenerated from its files on every change.
|
|
40
|
+
|
|
41
|
+
## What it reads
|
|
42
|
+
|
|
43
|
+
Markers in your own files, in one grammar: an id (`Q` question, `H` hypothesis, `E` experiment, `R` result,
|
|
44
|
+
`C` claim, and a number) and a title, then links and a status on the lines after it.
|
|
45
|
+
|
|
46
|
+
```markdown
|
|
47
|
+
## H2: Learning-rate warm-up removes the gap <- notes (Markdown): a heading or a list item
|
|
48
|
+
answers: Q1
|
|
49
|
+
status: open <- open | supported | refuted | anything you like
|
|
50
|
+
```
|
|
51
|
+
|
|
52
|
+
| Where | How |
|
|
53
|
+
|---|---|
|
|
54
|
+
| Notes (`.md`) | definitions as above; `tests:`, `of:`, `supports:`, `weakens:`, `relies on:`, `metrics: acc=0.91` |
|
|
55
|
+
| Experiment configs (YAML, JSON, TOML) | a `research:` block: `id`, `title`, `tests`, `status`, and `results: out/e1.json`, whose numbers become the result `E1.results` |
|
|
56
|
+
| Scripts and notebooks | a comment: `# research-diff: E2 tests H2` |
|
|
57
|
+
| The paper (LaTeX) | a comment: `% C1: Small batches win` and `% relies on: H1, R1`; the paragraph's `\cite{…}` become its sources; `% expects: E1.results acc.batch32 > 0.85` warns when a result stops meeting it |
|
|
58
|
+
|
|
59
|
+
The map is built from markers only, so the same files always give the same map. It warns when a claim relies on
|
|
60
|
+
nothing or on a refuted hypothesis, when a number no longer meets what a claim `expects:`, when an open hypothesis has no experiment, and when a link points at nothing.
|
|
61
|
+
|
|
62
|
+
## Use
|
|
63
|
+
|
|
64
|
+
```sh
|
|
65
|
+
pipx install research-diff
|
|
66
|
+
research-diff map --out docs # research.svg and research.json
|
|
67
|
+
research-diff diff --base HEAD # what your uncommitted iteration did
|
|
68
|
+
research-diff sync # MLflow / W&B runs into research/runs.json
|
|
69
|
+
research-diff checkpoint # mark what you have understood
|
|
70
|
+
research-diff diff # only what came after that
|
|
71
|
+
```
|
|
72
|
+
|
|
73
|
+
A diff reads like: *Adds 1 hypothesis (H3); H1: open → refuted; E1.results acc.b32: 0.874 → 0.881 (+0.8%); 1 new
|
|
74
|
+
link; 2 new warnings (C1 relies on H1, which is refuted…).* It comes with the exact list (`plan.txt`) and a picture of
|
|
75
|
+
only what changed (`diff.svg`).
|
|
76
|
+
|
|
77
|
+
## With AI coding agents
|
|
78
|
+
|
|
79
|
+
```sh
|
|
80
|
+
pipx inject research-diff mcp
|
|
81
|
+
research-diff setup claude # a Stop hook, a skill and the MCP server (--scope project, --undo)
|
|
82
|
+
research-diff watch # http://127.0.0.1:8766/ : the research diff since your checkpoint, live
|
|
83
|
+
```
|
|
84
|
+
|
|
85
|
+
After every Claude Code turn one line says what changed in the research. The agent's tools: `research_diff`,
|
|
86
|
+
`research_map`, `log_result` (records a run's metrics and what it supports or weakens in `research/log.md`, so it is
|
|
87
|
+
on the map and in git) and `checkpoint`. The pictures, snapshots and live page are
|
|
88
|
+
[system-diff](https://github.com/simplifiedmachine/system-diff)'s.
|
|
89
|
+
|
|
90
|
+
## Experiment trackers
|
|
91
|
+
|
|
92
|
+
Runs logged to MLflow (its local `mlruns/` store) or W&B (its local `wandb/` folders) become results of the experiment
|
|
93
|
+
they are tagged with: `research-diff.experiment` (or `research_id`) as an MLflow tag or param, `research_id` in the W&B
|
|
94
|
+
config. Tracker folders are usually git-ignored, so `research-diff sync` copies their runs into `research/runs.json`,
|
|
95
|
+
which is tracked: the runs are then on the map, in git and in the next diff. The hook, the live page and the MCP tools
|
|
96
|
+
sync on their own.
|
|
97
|
+
|
|
98
|
+
## Markers suggested by your LLM
|
|
99
|
+
|
|
100
|
+
```sh
|
|
101
|
+
research-diff suggest # notes and paper files with no marker yet, or name the files
|
|
102
|
+
git apply .git/research-diff/suggest.patch
|
|
103
|
+
```
|
|
104
|
+
|
|
105
|
+
Your LLM (the one your Claude Code uses) proposes markers for what the text already says. Each proposal is checked
|
|
106
|
+
before it reaches the patch: a real line of a file it was shown, a marker in that file's own form, and no id that is
|
|
107
|
+
already used. Nothing is written until you apply the patch.
|
|
108
|
+
|
|
109
|
+
## License
|
|
110
|
+
|
|
111
|
+
MIT
|
|
@@ -0,0 +1,88 @@
|
|
|
1
|
+
# research-diff
|
|
2
|
+
|
|
3
|
+
Maps your research from its notes, experiment configs, results and paper (questions, hypotheses, experiments,
|
|
4
|
+
results, claims) and shows what each iteration changed. Built for exploring ideas with AI coding agents.
|
|
5
|
+
|
|
6
|
+
<!-- research-map:begin -->
|
|
7
|
+

|
|
8
|
+
|
|
9
|
+
<details><summary>1 open warning</summary>
|
|
10
|
+
|
|
11
|
+
- H2 is open and no experiment tests it
|
|
12
|
+
|
|
13
|
+
</details>
|
|
14
|
+
<!-- research-map:end -->
|
|
15
|
+
|
|
16
|
+
The map above is this repository's own example (`examples/batch-size`), regenerated from its files on every change.
|
|
17
|
+
|
|
18
|
+
## What it reads
|
|
19
|
+
|
|
20
|
+
Markers in your own files, in one grammar: an id (`Q` question, `H` hypothesis, `E` experiment, `R` result,
|
|
21
|
+
`C` claim, and a number) and a title, then links and a status on the lines after it.
|
|
22
|
+
|
|
23
|
+
```markdown
|
|
24
|
+
## H2: Learning-rate warm-up removes the gap <- notes (Markdown): a heading or a list item
|
|
25
|
+
answers: Q1
|
|
26
|
+
status: open <- open | supported | refuted | anything you like
|
|
27
|
+
```
|
|
28
|
+
|
|
29
|
+
| Where | How |
|
|
30
|
+
|---|---|
|
|
31
|
+
| Notes (`.md`) | definitions as above; `tests:`, `of:`, `supports:`, `weakens:`, `relies on:`, `metrics: acc=0.91` |
|
|
32
|
+
| Experiment configs (YAML, JSON, TOML) | a `research:` block: `id`, `title`, `tests`, `status`, and `results: out/e1.json`, whose numbers become the result `E1.results` |
|
|
33
|
+
| Scripts and notebooks | a comment: `# research-diff: E2 tests H2` |
|
|
34
|
+
| The paper (LaTeX) | a comment: `% C1: Small batches win` and `% relies on: H1, R1`; the paragraph's `\cite{…}` become its sources; `% expects: E1.results acc.batch32 > 0.85` warns when a result stops meeting it |
|
|
35
|
+
|
|
36
|
+
The map is built from markers only, so the same files always give the same map. It warns when a claim relies on
|
|
37
|
+
nothing or on a refuted hypothesis, when a number no longer meets what a claim `expects:`, when an open hypothesis has no experiment, and when a link points at nothing.
|
|
38
|
+
|
|
39
|
+
## Use
|
|
40
|
+
|
|
41
|
+
```sh
|
|
42
|
+
pipx install research-diff
|
|
43
|
+
research-diff map --out docs # research.svg and research.json
|
|
44
|
+
research-diff diff --base HEAD # what your uncommitted iteration did
|
|
45
|
+
research-diff sync # MLflow / W&B runs into research/runs.json
|
|
46
|
+
research-diff checkpoint # mark what you have understood
|
|
47
|
+
research-diff diff # only what came after that
|
|
48
|
+
```
|
|
49
|
+
|
|
50
|
+
A diff reads like: *Adds 1 hypothesis (H3); H1: open → refuted; E1.results acc.b32: 0.874 → 0.881 (+0.8%); 1 new
|
|
51
|
+
link; 2 new warnings (C1 relies on H1, which is refuted…).* It comes with the exact list (`plan.txt`) and a picture of
|
|
52
|
+
only what changed (`diff.svg`).
|
|
53
|
+
|
|
54
|
+
## With AI coding agents
|
|
55
|
+
|
|
56
|
+
```sh
|
|
57
|
+
pipx inject research-diff mcp
|
|
58
|
+
research-diff setup claude # a Stop hook, a skill and the MCP server (--scope project, --undo)
|
|
59
|
+
research-diff watch # http://127.0.0.1:8766/ : the research diff since your checkpoint, live
|
|
60
|
+
```
|
|
61
|
+
|
|
62
|
+
After every Claude Code turn one line says what changed in the research. The agent's tools: `research_diff`,
|
|
63
|
+
`research_map`, `log_result` (records a run's metrics and what it supports or weakens in `research/log.md`, so it is
|
|
64
|
+
on the map and in git) and `checkpoint`. The pictures, snapshots and live page are
|
|
65
|
+
[system-diff](https://github.com/simplifiedmachine/system-diff)'s.
|
|
66
|
+
|
|
67
|
+
## Experiment trackers
|
|
68
|
+
|
|
69
|
+
Runs logged to MLflow (its local `mlruns/` store) or W&B (its local `wandb/` folders) become results of the experiment
|
|
70
|
+
they are tagged with: `research-diff.experiment` (or `research_id`) as an MLflow tag or param, `research_id` in the W&B
|
|
71
|
+
config. Tracker folders are usually git-ignored, so `research-diff sync` copies their runs into `research/runs.json`,
|
|
72
|
+
which is tracked: the runs are then on the map, in git and in the next diff. The hook, the live page and the MCP tools
|
|
73
|
+
sync on their own.
|
|
74
|
+
|
|
75
|
+
## Markers suggested by your LLM
|
|
76
|
+
|
|
77
|
+
```sh
|
|
78
|
+
research-diff suggest # notes and paper files with no marker yet, or name the files
|
|
79
|
+
git apply .git/research-diff/suggest.patch
|
|
80
|
+
```
|
|
81
|
+
|
|
82
|
+
Your LLM (the one your Claude Code uses) proposes markers for what the text already says. Each proposal is checked
|
|
83
|
+
before it reaches the patch: a real line of a file it was shown, a marker in that file's own form, and no id that is
|
|
84
|
+
already used. Nothing is written until you apply the patch.
|
|
85
|
+
|
|
86
|
+
## License
|
|
87
|
+
|
|
88
|
+
MIT
|
|
@@ -0,0 +1,78 @@
|
|
|
1
|
+
<svg xmlns="http://www.w3.org/2000/svg" width="1284" height="296" viewBox="0 0 1284 296" role="img" aria-label="Research map">
|
|
2
|
+
<style>
|
|
3
|
+
text { font-family: 'Segoe UI', FreeSans, 'Helvetica Neue', Arial, sans-serif; }
|
|
4
|
+
.bg { fill: #f8f9fb; stroke: #e1e5eb; }
|
|
5
|
+
.col { font-size: 11px; font-weight: 600; letter-spacing: .05em; fill: #667385; }
|
|
6
|
+
.bn .box { fill: #ffffff; stroke: #e1e5eb; stroke-width: 1.2; }
|
|
7
|
+
.bn.t-store .box { fill: #e8f0fc; }
|
|
8
|
+
.bn.legacy .box { fill: #f8f9fb; stroke: #c3cad4; stroke-dasharray: 5 4; }
|
|
9
|
+
.bn.legacy .bn-t { fill: #3b4655; }
|
|
10
|
+
.bn .band { fill: #1f5fbf; }
|
|
11
|
+
.bn.undeclared .band { fill: #9a5600; }
|
|
12
|
+
.bn.s-added .box { stroke: #157347; stroke-width: 1.8; } .bn.s-added .band { fill: #157347; }
|
|
13
|
+
.bn.s-changed .box { stroke: #9a5600; stroke-width: 1.8; } .bn.s-changed .band { fill: #9a5600; }
|
|
14
|
+
.bn.s-removed .box { stroke: #c4321c; stroke-dasharray: 5 4; fill: #fdecea; } .bn.s-removed .band { fill: #c4321c; }
|
|
15
|
+
.bn-t { font-size: 13px; font-weight: 600; fill: #161c24; }
|
|
16
|
+
.bn-s { font-size: 11.5px; fill: #667385; }
|
|
17
|
+
.bn-p { font-size: 11.5px; fill: #3b4655; } .bn-p.code { font-family: Consolas, Inconsolata, 'DejaVu Sans Mono', monospace; } .bn-p.more { fill: #667385; }
|
|
18
|
+
.bn-p.s-added { fill: #157347; font-weight: 600; } .bn-p.s-changed { fill: #9a5600; font-weight: 600; }
|
|
19
|
+
.bn-p.s-removed { fill: #c4321c; text-decoration: line-through; }
|
|
20
|
+
.be { fill: none; stroke: #667385; stroke-width: 1.4; opacity: .75; }
|
|
21
|
+
.be.k-data { stroke: #1f5fbf; } .be.k-network { stroke: #9a5600; stroke-dasharray: 6 4; }
|
|
22
|
+
.be.s-added { stroke: #157347; stroke-width: 2.2; opacity: 1; }
|
|
23
|
+
.be.s-removed { stroke: #c4321c; stroke-dasharray: 5 4; opacity: 1; }
|
|
24
|
+
.ar { fill: #667385; } .ar.k-data { fill: #1f5fbf; } .ar.k-network { fill: #9a5600; }
|
|
25
|
+
.ar.s-added { fill: #157347; } .ar.s-removed { fill: #c4321c; } .ar.k-person { fill: #1f5fbf; }
|
|
26
|
+
.halo { paint-order: stroke; stroke: #f8f9fb; stroke-width: 4px; stroke-linejoin: round; }
|
|
27
|
+
.lg { font-size: 11.5px; fill: #667385; }
|
|
28
|
+
.lg.s-added { fill: #157347; font-weight: 600; } .lg.s-changed { fill: #9a5600; font-weight: 600; }
|
|
29
|
+
.lg.s-removed { fill: #c4321c; font-weight: 600; }
|
|
30
|
+
.foot { font-size: 11.5px; fill: #3b4655; }
|
|
31
|
+
.st .box { fill: #ffffff; stroke: #e1e5eb; stroke-width: 1.4; }
|
|
32
|
+
.st.hi .box { fill: #e8f0fc; stroke: #1f5fbf; }
|
|
33
|
+
.st-w { font-size: 13px; font-weight: 600; fill: #161c24; }
|
|
34
|
+
.fl { fill: none; stroke: #667385; stroke-width: 1.4; } .fl.loop { stroke-dasharray: 4 4; }
|
|
35
|
+
.fl.gate { stroke: #1f5fbf; stroke-dasharray: 2 4; opacity: .7; }
|
|
36
|
+
.fl-note { font-size: 11.5px; fill: #667385; }
|
|
37
|
+
.gate .box { fill: #e8f0fc; stroke: #1f5fbf; } .gate text { font-size: 12.5px; font-weight: 600; fill: #1f5fbf; }
|
|
38
|
+
.exit { font-size: 12.5px; font-weight: 600; fill: #161c24; }
|
|
39
|
+
.lane .box { fill: #ffffff; stroke: #e1e5eb; stroke-width: 1.2; }
|
|
40
|
+
.lane.person .box { fill: #e8f0fc; stroke: #1f5fbf; }
|
|
41
|
+
.life { stroke: #c9d0da; stroke-width: 1.2; stroke-dasharray: 3 4; }
|
|
42
|
+
.msg { fill: none; stroke: #667385; stroke-width: 1.4; }
|
|
43
|
+
.msg.frame { stroke: #1f5fbf; stroke-dasharray: 5 4; } .msg.person { stroke: #1f5fbf; stroke-width: 2; }
|
|
44
|
+
.msg-t { font-size: 11.5px; fill: #3b4655; } .msg-t.frame { fill: #1f5fbf; } .msg-t.person { fill: #1f5fbf; font-weight: 600; }
|
|
45
|
+
.num circle { fill: #667385; } .num.person circle { fill: #1f5fbf; }
|
|
46
|
+
.num text { fill: #ffffff; font-size: 10px; font-weight: 700; }
|
|
47
|
+
.note .box { fill: #fff3dd; stroke: #e9c98f; } .note text { font-size: 11.5px; fill: #9a5600; }
|
|
48
|
+
</style>
|
|
49
|
+
<defs><marker id="ar-call-same" class="ar k-call s-same" viewBox="0 0 10 10" refX="9" refY="5" markerWidth="7" markerHeight="7" orient="auto-start-reverse"><path d="M0,0 L10,5 L0,10 z"/></marker><marker id="ar-data-same" class="ar k-data s-same" viewBox="0 0 10 10" refX="9" refY="5" markerWidth="7" markerHeight="7" orient="auto-start-reverse"><path d="M0,0 L10,5 L0,10 z"/></marker></defs>
|
|
50
|
+
<rect class="bg" x="0.5" y="0.5" width="1283" height="295" rx="10"/>
|
|
51
|
+
<text class="col" x="14" y="18">QUESTIONS</text>
|
|
52
|
+
<text class="col" x="278" y="18">HYPOTHESES</text>
|
|
53
|
+
<text class="col" x="542" y="18">EXPERIMENTS</text>
|
|
54
|
+
<text class="col" x="806" y="18">RESULTS</text>
|
|
55
|
+
<text class="col" x="1070" y="18">CLAIMS</text>
|
|
56
|
+
<path class="be k-call s-same" d="M1070,52 C1038,52 1038,128 1006,128 L806,128 C774,128 774,102 742,102 L542,102 C513,102 513,52 484,52" marker-end="url(#ar-call-same)"><title>C1 → H1</title></path>
|
|
57
|
+
<path class="be k-call s-same" d="M1070,52 C1041,52 1041,157 1012,157" marker-end="url(#ar-call-same)"><title>C1 → R1</title></path>
|
|
58
|
+
<path class="be k-call s-same" d="M542,52 C513,52 513,52 484,52" marker-end="url(#ar-call-same)"><title>E1 → H1</title></path>
|
|
59
|
+
<path class="be k-call s-same" d="M806,52 C777,52 777,52 748,52" marker-end="url(#ar-call-same)"><title>E1.results → E1</title></path>
|
|
60
|
+
<path class="be k-call s-same" d="M278,52 C249,52 249,52 220,52" marker-end="url(#ar-call-same)"><title>H1 → Q1</title></path>
|
|
61
|
+
<path class="be k-call s-same" d="M278,128 C249,128 249,52 220,52" marker-end="url(#ar-call-same)"><title>H2 → Q1</title></path>
|
|
62
|
+
<path class="be k-call s-same" d="M806,157 C777,157 777,52 748,52" marker-end="url(#ar-call-same)"><title>R1 → E1</title></path>
|
|
63
|
+
<path class="be k-data s-same" d="M806,157 C774,157 774,104.5 742,104.5 L542,104.5 C513,104.5 513,52 484,52" marker-end="url(#ar-data-same)"><title>R1 → H1</title></path>
|
|
64
|
+
<g class="bn t-component s-same" transform="translate(14,30)"><rect class="box" width="200" height="62" rx="8"/><text x="12" y="19" class="bn-t">Q1 How does batch size</text><text x="12" y="35" class="bn-t">change accuracy when th…</text><text x="12" y="51" class="bn-s">examples/batch-size/notes/ideas…</text><title>Q1 How does batch size change accuracy when there are under 10k examples?</title></g>
|
|
65
|
+
<g class="bn t-component s-same new" transform="translate(278,30)"><rect class="box" width="200" height="62" rx="8"/><rect class="band" width="5" height="62" rx="2"/><text x="12" y="19" class="bn-t">H1 Smaller batches</text><text x="12" y="35" class="bn-t">generalise better on sm…</text><text x="12" y="51" class="bn-s">supported</text><title>H1 Smaller batches generalise better on small datasets</title></g>
|
|
66
|
+
<g class="bn t-component s-same" transform="translate(278,106)"><rect class="box" width="200" height="62" rx="8"/><text x="12" y="19" class="bn-t">H2 Learning-rate warm-up</text><text x="12" y="35" class="bn-t">removes the gap</text><text x="12" y="51" class="bn-s">open</text><title>H2 Learning-rate warm-up removes the gap</title></g>
|
|
67
|
+
<g class="bn t-component s-same" transform="translate(542,30)"><rect class="box" width="200" height="62" rx="8"/><text x="12" y="19" class="bn-t">E1 Batch 32 vs 512 on</text><text x="12" y="35" class="bn-t">small-8k</text><text x="12" y="51" class="bn-s">examples/batch-size/configs/e1.…</text><title>E1 Batch 32 vs 512 on small-8k</title></g>
|
|
68
|
+
<g class="bn t-store s-same" transform="translate(806,30)"><rect class="box" width="200" height="91" rx="8"/><text x="12" y="19" class="bn-t">E1.results</text><text x="12" y="35" class="bn-s">examples/batch-size/out/e1.json</text><text x="14" y="53" class="bn-p s-same code">· acc.batch32 = 0.874</text><text x="14" y="68" class="bn-p s-same code">· acc.batch512 = 0.842</text><text x="14" y="83" class="bn-p s-same code">· epochs = 30</text><title>E1.results</title></g>
|
|
69
|
+
<g class="bn t-store s-same" transform="translate(806,135)"><rect class="box" width="200" height="77" rx="8"/><text x="12" y="19" class="bn-t">R1 Batch 32 beats 512 by</text><text x="12" y="35" class="bn-t">3.2 points</text><text x="12" y="51" class="bn-s">examples/batch-size/notes/resul…</text><text x="14" y="69" class="bn-p s-same code">· gap = 0.032</text><title>R1 Batch 32 beats 512 by 3.2 points</title></g>
|
|
70
|
+
<g class="bn t-component s-same" transform="translate(1070,30)"><rect class="box" width="200" height="62" rx="8"/><text x="12" y="19" class="bn-t">C1 Small batches give</text><text x="12" y="35" class="bn-t">better accuracy on smal…</text><text x="12" y="51" class="bn-s">2 sources</text><title>C1 Small batches give better accuracy on small datasets</title></g>
|
|
71
|
+
<rect x="16" y="246" width="14" height="12" rx="2" fill="#ffffff" stroke="#e1e5eb"/><rect x="16" y="246" width="4" height="12" rx="1" fill="#1f5fbf"/>
|
|
72
|
+
<text x="36" y="256" class="lg">supported</text>
|
|
73
|
+
<path class="be k-call" d="M109.9,252 L129.9,252" style="opacity:1"/>
|
|
74
|
+
<text x="135.9" y="256" class="lg">links</text>
|
|
75
|
+
<path class="be k-data" d="M184.9,252 L204.9,252" style="opacity:1"/>
|
|
76
|
+
<text x="210.9" y="256" class="lg">supports</text>
|
|
77
|
+
<text class="foot" x="16" y="282">1 warning: H2 is open and no experiment tests it</text>
|
|
78
|
+
</svg>
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
# Does batch size matter on small datasets?
|
|
2
|
+
|
|
3
|
+
## Q1: How does batch size change accuracy when there are under 10k examples?
|
|
4
|
+
|
|
5
|
+
## H1: Smaller batches generalise better on small datasets
|
|
6
|
+
|
|
7
|
+
answers: Q1
|
|
8
|
+
status: supported
|
|
9
|
+
|
|
10
|
+
## H2: Learning-rate warm-up removes the gap
|
|
11
|
+
|
|
12
|
+
answers: Q1
|
|
13
|
+
status: open
|
|
14
|
+
|
|
15
|
+
The idea: the gap may be an optimisation artefact rather than a generalisation one.
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"acc": {"batch32": 0.874, "batch512": 0.842}, "epochs": 30}
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
\section{Results}
|
|
2
|
+
|
|
3
|
+
% C1: Small batches give better accuracy on small datasets
|
|
4
|
+
% relies on: H1, R1
|
|
5
|
+
% expects: E1.results acc.batch32 > 0.85
|
|
6
|
+
On the 8k split, batch 32 reaches 87.4\% against 84.2\% for batch 512, in line with
|
|
7
|
+
earlier work \cite{keskar2017large,masters2018revisiting}.
|
|
@@ -0,0 +1,40 @@
|
|
|
1
|
+
[build-system]
|
|
2
|
+
requires = ["hatchling>=1.24"]
|
|
3
|
+
build-backend = "hatchling.build"
|
|
4
|
+
|
|
5
|
+
[project]
|
|
6
|
+
name = "research-diff"
|
|
7
|
+
version = "0.1.0"
|
|
8
|
+
description = "Maps your research from its notes, experiment configs, results and paper (questions, hypotheses, experiments, results, claims) and shows what each iteration changed. Built for exploring ideas with AI coding agents."
|
|
9
|
+
readme = "README.md"
|
|
10
|
+
license = "MIT"
|
|
11
|
+
license-files = ["LICENSE"]
|
|
12
|
+
requires-python = ">=3.11"
|
|
13
|
+
authors = [{ name = "simplifiedmachine" }]
|
|
14
|
+
keywords = ["research", "experiment-tracking", "hypotheses", "reproducibility", "ai-agents", "claude-code", "mcp"]
|
|
15
|
+
classifiers = [
|
|
16
|
+
"Development Status :: 3 - Alpha",
|
|
17
|
+
"Intended Audience :: Science/Research",
|
|
18
|
+
"Programming Language :: Python :: 3 :: Only",
|
|
19
|
+
"Topic :: Scientific/Engineering",
|
|
20
|
+
]
|
|
21
|
+
# Its pictures, snapshots and live page are system-diff's (same author, no dependencies of its own), pinned.
|
|
22
|
+
dependencies = ["system-diff==0.1.0"]
|
|
23
|
+
|
|
24
|
+
[project.optional-dependencies]
|
|
25
|
+
mcp = ["mcp>=1.10"]
|
|
26
|
+
dev = ["pytest>=8", "mcp>=1.10"]
|
|
27
|
+
|
|
28
|
+
[project.urls]
|
|
29
|
+
Homepage = "https://github.com/simplifiedmachine/research-diff"
|
|
30
|
+
Documentation = "https://github.com/simplifiedmachine/research-diff/wiki"
|
|
31
|
+
|
|
32
|
+
[project.scripts]
|
|
33
|
+
research-diff = "research_diff.cli:main"
|
|
34
|
+
resdiff = "research_diff.cli:main"
|
|
35
|
+
|
|
36
|
+
[tool.hatch.build.targets.wheel]
|
|
37
|
+
packages = ["src/research_diff"]
|
|
38
|
+
|
|
39
|
+
[tool.pytest.ini_options]
|
|
40
|
+
testpaths = ["tests"]
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
# research-diff on its own example project: the README's map is drawn from examples/.
|
|
2
|
+
notes = ["examples/**/*.md"]
|
|
3
|
+
configs = ["examples/**/*.yaml", "examples/**/*.json"]
|
|
4
|
+
scripts = ["examples/**/*.py"]
|
|
5
|
+
paper = ["examples/**/*.tex"]
|
|
6
|
+
|
|
7
|
+
[readme]
|
|
8
|
+
image = "https://raw.githubusercontent.com/simplifiedmachine/research-diff/main/docs/research.svg" # shows on PyPI too
|