Skip to main content

Build and visualize orbit graphs for discrete iterations under guarded rules.

Project description

VisIter

See what a discrete iteration actually does — as a graph.

The simplest case

Integers 1–9. Case: divisible by 3 → divide by 3. Default (everything else) → add 2. Where does each value end up?

#!/usr/bin/env viter
(viter(range(1, 10))
 .case(lambda x: x % 3 == 0, lambda x: x // 3)
 .default(lambda x: x + 2)
 .render())

descent graph, range 1–9

Save as descent.vit, run with viter descent.vit > out.svg. The #!/usr/bin/env viter shebang also lets you chmod +x descent.vit and execute the file directly.

.render() is the shortcut terminal — it builds the graph, converts to Graphviz, and writes SVG to stdout in one call.

Install

pip install visiter

Graphviz must be available on PATH (brew install graphviz / apt install graphviz).

Optional extras: pip install "visiter[native]" adds the native engine (prebuilt wheel, no toolchain needed), [storage] the columnar .vitgraph format, [validate] the JSON-Schema validator, [analytics] the NetworkX bridge. See Performance & storage below.

Going further

.render() is convenient for the common case. For anything more — cropping, custom colors, side-effects, filters — materialize the Graph explicitly via .build() and keep chaining:

#!/usr/bin/env viter
(viter(range(1, 10))
 .case(lambda x: x % 3 == 0, lambda x: x // 3)
 .default(lambda x: x + 2)
 .build()
 .to_dot(anchor=1, radius=8, direction="backward")
 .render())

Save intermediate results with .tap():

(viter(...).case(...).default(...).build()
 .tap(write(file="graph.json"))
 .to_dot()
 .render(file="out.svg"))

Use NetworkX for graph analysis via .filter():

import networkx as nx
(viter(...).case(...).default(...).build()
 .filter(NxFilter(nx.condensation))
 .to_dot()
 .render())

If-elif-else semantics (first matching case wins) via match=Match.FIRST:

(viter(range(1, 17), match=Match.FIRST)
 .case(lambda x: x % 2 == 0, lambda x: x // 2)
 .case(lambda x: x % 3 == 0, lambda x: x // 3)
 .default(lambda x: x * 5 + 7)
 .render())

Use the Python API directly (outside .vit files):

from visiter import viter

graph = (viter(range(1, 10))
         .case(lambda x: x % 3 == 0, lambda x: x // 3)
         .default(lambda x: x + 2)
         .build())
graph.to_dot().render(file="descent.svg")

Per-call edge labels via OpResult — for when the static label= is not enough and each step's edge should carry its own annotation:

from visiter import OpResult, viter

def odd_step(x):
    increased = 3 * x + 1
    div = (increased & -increased).bit_length() - 1
    return OpResult(increased >> div, label=f"3x+1, ÷2×{div}")

(viter([27])
 .case(lambda x: x % 2 == 0, lambda x: x // 2, label="÷2")
 .default(odd_step, label="3x+1")
 .render())

Performance & storage (optional)

Pure Python with JSON is the default and needs no toolchain. For large state spaces, three optional, additive features kick in — all producing the same graph, byte-for-byte:

  • Native engine (engine="auto", the default once present). pip install "visiter[native]" pulls a prebuilt wheel that runs the BFS bookkeeping natively for unbounded builds while keeping your Python callbacks (or make native to build it locally). Falls back to pure Python when absent.

  • Inline Rust callbacks (lang="rust") — for when the callbacks are the bottleneck. .case() takes Rust expression strings (value bound to s), compiled on the fly with rustc and run natively:

    (viter(10, lang="rust")
     .case("s >= 1", "s - 1", label="take 1")
     .case("s >= 2", "s - 2", label="take 2")
     .render())
    
  • Columnar storage (pip install "visiter[storage]") — .vitgraph files (graph.to_vitgraph(...) / Graph.from_vitgraph(...)) are ~10–25× smaller than JSON and far faster to load for large graphs.

Details in the manual.

Why VisIter?

Free, scriptable, Graphviz-native orbit-graph rendering for discrete iterations under guarded rules — with cutoff boundaries (bounds, depth limits, render crops) as a first-class visual primitive, not silent truncation.

Full honest comparison against NetworkX, NestGraph (Mathematica), Maude, LoLA, and continuous-dynamics tooling: docs/comparison.md.

Documentation

  • docs/tutorial.md — gentle introduction: what problem the tool solves, smallest example, what each piece does, what the dashed arrows mean. Start here.
  • docs/manual.md — reference: every parameter, every data field, the rendering model in full, design decisions.
  • docs/comparison.md — how VisIter relates to other tools in the ecosystem, and when to pick something else.
  • demos/ — runnable .vit examples organized by topic (basics/, rendering/, integration/, applications/, rust/).

License

MIT

Project details


Download files

Download the file for your platform. If you're not sure which to choose, learn more about installing packages.

Source Distribution

visiter-0.16.0.tar.gz (496.2 kB view details)

Uploaded Source

Built Distribution

If you're not sure about the file name format, learn more about wheel file names.

visiter-0.16.0-py3-none-any.whl (46.9 kB view details)

Uploaded Python 3

File details

Details for the file visiter-0.16.0.tar.gz.

File metadata

  • Download URL: visiter-0.16.0.tar.gz
  • Upload date:
  • Size: 496.2 kB
  • Tags: Source
  • Uploaded using Trusted Publishing? No
  • Uploaded via: twine/6.2.0 CPython/3.12.12

File hashes

Hashes for visiter-0.16.0.tar.gz
Algorithm Hash digest
SHA256 586528806bd298d3bce042d3e296267b771839ef8ca5c385e5cb3400ed3d9b74
MD5 e6ebdd00f7c81b5d6f416425dddedf1a
BLAKE2b-256 5ca3bacc328bcffb07a9d7387fe14ed04e21524b47c1ad92cc5b2549ba8947de

See more details on using hashes here.

File details

Details for the file visiter-0.16.0-py3-none-any.whl.

File metadata

  • Download URL: visiter-0.16.0-py3-none-any.whl
  • Upload date:
  • Size: 46.9 kB
  • Tags: Python 3
  • Uploaded using Trusted Publishing? No
  • Uploaded via: twine/6.2.0 CPython/3.12.12

File hashes

Hashes for visiter-0.16.0-py3-none-any.whl
Algorithm Hash digest
SHA256 85b5eb5633559696d572b3b8c5a4899514e3e7920574ba1b81a801d3158ac576
MD5 a6d2ae03dcebc9b2ad4a16eebee2fc50
BLAKE2b-256 2ecce9231b23407fe37e87b8a3944e70cdfd25d5410fe13bf2ff405fdc98b2ae

See more details on using hashes here.

Supported by

AWS Cloud computing and Security Sponsor Datadog Monitoring Depot Continuous Integration Fastly CDN Google Download Analytics Pingdom Monitoring Sentry Error logging StatusPage Status page