Skip to content
GIST-DSLabPublic

Latest commit

 

History

161 Commits

Folders and files

Repository files navigation

SOLAR(Synthesized Offline Learning data for Abstraction and Reasoning)

Executable ARC solutions. Every task in this repository ships a grid_maker.py that samples fresh input grids and emits the ARCLE operation sequence that solves them — so rolling one out yields a replayable trajectory (select → recolor → move → paste → submit), not just an input/output pair.

License Python ARCLE

one episode, action by action

400 makers, one per task of the ARC-AGI-1 training split. Inputs come from each task's RE-ARC generator, so any maker can be rolled out for as many fresh instances as you want — the published dataset is one draw of them, not their limit (see Download).


Setup

Python 3.11, developed and verified on 3.11.15.

git clone https://github.com/GIST-DSLab/SOLAR-V2.git solar-traj
cd solar-traj
pip install -r requirements.txt

No build step and no package install. Every entry point is a script under pipeline/ or viz/, run from the repository root. requirements.txt pins arcle == 0.2.5; the recording format depends on that version's observation dict.

Rollouts do not live in the repository — a full draw is tens of gigabytes. The scripts that read or write them take a directory and default to ./solar-data:

export SOLAR_DATA_ROOT=/somewhere/with/space          # or pass --data_folder

Some things are optional, and only some scripts want them:

ARC-AGI-1 data pipeline/probe_originals.py only. A clone of fchollet/ARC-AGI; point at it with $SOLAR_ARC_DIR or --arc_dir
claude CLI The two LLM scripts only (pipeline/gen_rearc_makers_llm.py, pipeline/critique_makers_llm.py). They shell out to Claude Code, so there is no separate API key

--data_root, --out, --arc_dir and --data_folder each override their environment variable.

Quick Start

Step 1: Generate trajectories

# one task, 10 episodes — CPU only, no LLM calls, seconds
python pipeline/gen_rearc_trajectories_v2.py \
    --subfolder arc-agi-1 \
    --tasks 05f2a901 \
    --num_samples 10 \
    --rand_seed 0 \
    --max_grid_dim 30 30 \
    --data_folder solar-data/draw0

One JSON per episode, under a directory named for the task and the day:

solar-data/draw0/whole/test.05f2a901.s30.26.08.18/05f2a901-rearc-llm_1.json

Drop --tasks and all 400 makers roll out.

Step 2: Visualize a trajectory

# a still figure: the worked examples, then the episode step by step
python viz/visualize_trajectory.py \
    --root solar-data/draw0/whole \
    --task 05f2a901 \
    --out figure/mine.png

# the same episode as a GIF
python viz/visualize_trajectory_gif.py \
    --root solar-data/draw0/whole \
    --task 05f2a901 \
    --out figure/mine.gif

Layout

.
├── docs/                             the GitHub Pages viewer; carries no data of its own
│   ├── .nojekyll
│   ├── arcle_reference.md
│   ├── hero.png
│   └── index.html
├── figure/                           teaser.png and teaser.gif
│   ├── teaser.gif
│   └── teaser.png
├── maker/                            keep at the root — makers assume it
│   ├── arc-agi-1/                    400  ARC-AGI-1 training tasks, LLM-written
│   │   └── … 400 task directories
│   ├── handcraft/                     10  hand-written, kept as a control
│   │   └── … 10 maker directories
│   ├── __init__.py
│   ├── base_grid_maker.py
│   └── sel_helpers.py
├── pipeline/                         GENERATE / CHECK / REFINE, plus rollout and export
│   ├── README.md                     every script and flag, and the loop in full
│   ├── build_preview.py
│   ├── critique_makers_llm.py
│   ├── critique_to_feedback.py
│   ├── export_release.py
│   ├── gen_rearc_makers_llm.py
│   ├── gen_rearc_trajectories_v2.py
│   ├── probe_originals.py
│   ├── utils.py
│   └── verify_grid_makers.py
├── re-arc/                           vendored RE-ARC generators, verifiers, DSL (Apache-2.0)
│   ├── NOTICE
│   ├── dsl.py
│   ├── generators.py
│   ├── utils.py
│   └── verifiers.py
├── viz/                              figures, GIF, and the gallery pages
│   ├── README.md
│   ├── build_handcraft_gallery.py
│   ├── build_hero_bg.py
│   ├── visualize_trajectory.py
│   └── visualize_trajectory_gif.py
├── .gitignore
├── LICENSE
├── README.md
└── requirements.txt

maker/ and re-arc/ cannot be moved. Every generated grid_maker.py resolves the repo root as its own parents[3] and puts <root>/re-arc on sys.path itself, so relocating either breaks 410 files that are outputs, not sources. Everything else is ours and moves freely.

Generating a dataset

Two commands. The first rolls makers out into trajectories, the second packs those into parquet shards.

# 400 tasks x 25 draws: CPU only, no LLM calls, ~30 min
python pipeline/gen_rearc_trajectories_v2.py --subfolder arc-agi-1 \
    --num_samples 25 --rand_seed 0 --max_grid_dim 30 30 \
    --rearc_generate --verify_filter \
    --data_folder $SOLAR_DATA_ROOT/ARC_rearc_draw1

# pack it, round-trip checking 40 rows against the source JSON
python pipeline/export_release.py --subsets arc_agi1 --verify 40

--rearc_generate draws every instance from the task's own RE-ARC generator rather than from the maker's generate(), resampling until it fits --max_grid_dim; --verify_filter keeps only the instances verify_<task> reproduces. That is how the published draw is made, and it leaves the maker responsible for one thing: the operations. Drop both flags and the maker's own generate() supplies the instances instead.

--subfolder names the maker set. arc-agi-1 is the 400 makers this release was rolled out from; pipeline/README.md covers the rest of the flags, and what the other set in maker/ needs.

The generators are unbounded, so the published dataset is one draw rather than a ceiling: a different --rand_seed gives a disjoint one, and --num_samples sets how deep the draw goes.

A sample reaches disk only if its final grid matches the target, so a rollout drops what it cannot solve rather than repairing it. The released draw asked for 25 per task and 9,981 of 9,998 attempts landed, the thinnest task keeping 19. The exporter then packs a fixed 10 episodes per task, which is where the 4,000 rows come from; raise that in export_release.py to publish a deeper draw.

Every recorded tensor is padded to --max_grid_dim with fill value 10 (colours occupy 0-9); the true extent lives in grid_dim, clip_dim, ex_in_grid_dim and ex_out_grid_dim.

The checks that produced these makers, and every flag of every script, are in pipeline/README.md. The figure and gallery tools are in viz/README.md.

How the makers were written

An LLM writes one maker per task — generate(), sample_colors() and derive_operations() — from that task's RE-ARC generator and verifier plus its original ARC pairs. What comes back is checked five ways:

check what it asks where
simulation do the ops turn I into O; does the grid revisit a state; is any op removable with O still reached inside the generating conversation, so a rejection is re-prompted at once, up to 3 tries
samples do N fresh instances, drawn under several seeds, all reach the target — not just the ones it was written on pipeline/verify_grid_makers.py
rule do the instances its generate() produces obey the rule the task's RE-ARC generator implements pipeline/probe_generator.py
generator instances does derive_operations solve what the generator itself produces, not only the slice its own generate() samples pipeline/probe_rearc.py
critic replaying an episode, does the route match the solver's concept pipeline/critique_makers_llm.py
originals does the same solution replay on the task's own original ARC pairs. The generator is the reference, so where its rule and an original pair part ways that pair is excluded rather than blamed on the maker pipeline/probe_originals.py

A maker that fails a check is written again, and what the check found goes with it: the instance it failed, and what its ops produced instead. Naming the cause is the model's job. Rounds run until the maker passes, and each task keeps its best one.

Most tasks took more than one round: 321 of the 400 were regenerated at least once from a check's finding. Every maker here reaches its target on fresh instances and on the generator's own; the route checks are judgement calls and not every maker satisfies all of them.

The checks were built at different times and ran in different combinations from round to round, so this is a set of filters rather than a fixed sequence. That is also what makes it portable: the parts that do the work are a route written as code, replay deciding whether it survives, and a rejection carrying evidence into the next attempt. Which checks you can run is what a corpus changes — real ARC-AGI-2 tasks have no generator, so nothing there can ask for fresh instances, and those makers went through the loop without that check. pipeline/README.md has all of it in full.

Writing your own

A maker subclasses BaseGridMaker and implements parse(**kwargs), returning (ex_in, ex_out, pr_in, pr_out, desc) per sample, where desc carries operations and selections. Start from any file under maker/arc-agi-1/, then run the two checks that need no LLM:

python pipeline/probe_originals.py    --subfolder <your_set>   # solves the original pairs?
python pipeline/verify_grid_makers.py --subfolder <your_set>   # fresh samples reach the target?

Run probe_originals.py first — it is the one that catches a generate() that has drifted away from the task. docs/arcle_reference.md is the operation reference makers are written against, and what the generator prompt is built from.

Download

The rolled-out trajectories are published as a separate dataset in parquet, with the loader and schema documented there: dbsgh797210/SOLAR.

from datasets import load_dataset
ds = load_dataset("dbsgh797210/SOLAR", "arc_agi1", split="train")

Nothing here depends on it. pipeline/gen_rearc_trajectories_v2.py regenerates trajectories from the makers on CPU in a few minutes.

License

Apache-2.0 (see LICENSE). Built on, and would not exist without:

  • RE-ARC (Michael Hodel, Apache-2.0) — the input generators and verifiers vendored in re-arc/ (see re-arc/NOTICE)
  • ARC-AGI-1 (Apache-2.0) — the tasks
  • ARCLE — the environment these trajectories are written in

Releases

Packages

Contributors

Languages