|
4 | 4 | MLC-Python
|
5 | 5 | </h1>
|
6 | 6 |
|
7 |
| -* [:key: Key features](#keykey-features) |
8 |
| -* [:inbox_tray: Installation](#inbox_trayinstallation) |
9 |
| - + [:package: Install From PyPI](#packageinstall-from-pypi) |
10 |
| - + [:gear: Build from Source](#gearbuild-from-source) |
11 |
| - + [:ferris_wheel: Create MLC-Python Wheels](#ferris_wheel-create-mlc-python-wheels) |
| 7 | +* [:inbox_tray: Installation](#inbox_tray-installation) |
| 8 | +* [:key: Key Features](#key-key-features) |
| 9 | + + [:building_construction: MLC Dataclass](#building_construction-mlc-dataclass) |
| 10 | + + [:dart: Structure-Aware Tooling](#dart-structure-aware-tooling) |
| 11 | + + [:snake: Text Formats in Python AST](#snake-text-formats-in-python-ast) |
| 12 | + + [:zap: Zero-Copy Interoperability with C++ Plugins](#zap-zero-copy-interoperability-with-c-plugins) |
| 13 | +* [:fuelpump: Development](#fuelpump-development) |
| 14 | + + [:gear: Editable Build](#gear-editable-build) |
| 15 | + + [:ferris_wheel: Create Wheels](#ferris_wheel-create-wheels) |
12 | 16 |
|
13 |
| -MLC is a Python-first toolkit that makes it more ergonomic to build AI compilers, runtimes, and compound AI systems. It provides Pythonic dataclasses with rich tooling infra, which includes: |
14 | 17 |
|
15 |
| -- Structure-aware equality and hashing methods; |
16 |
| -- Serialization in JSON / pickle; |
17 |
| -- Text format printing and parsing in Python syntax. |
| 18 | +MLC is a Python-first toolkit that makes it more ergonomic to build AI compilers, runtimes, and compound AI systems with Pythonic dataclass, rich tooling infra and zero-copy interoperability with C++ plugins. |
18 | 19 |
|
19 |
| -Additionally, MLC language bindings support: |
| 20 | +## :inbox_tray: Installation |
20 | 21 |
|
21 |
| -- Zero-copy bidirectional functioning calling for all MLC dataclasses. |
| 22 | +```bash |
| 23 | +pip install -U mlc-python |
| 24 | +``` |
22 | 25 |
|
23 |
| -## :key: Key features |
| 26 | +## :key: Key Features |
24 | 27 |
|
25 |
| -TBD |
| 28 | +### :building_construction: MLC Dataclass |
26 | 29 |
|
27 |
| -## :inbox_tray: Installation |
| 30 | +MLC dataclass is similar to Python’s native dataclass: |
28 | 31 |
|
29 |
| -### :package: Install From PyPI |
| 32 | +```python |
| 33 | +import mlc.dataclasses as mlcd |
30 | 34 |
|
31 |
| -```bash |
32 |
| -pip install -U mlc-python |
| 35 | +@mlcd.py_class("demo.MyClass") |
| 36 | +class MyClass(mlcd.PyClass): |
| 37 | + a: int |
| 38 | + b: str |
| 39 | + c: float | None |
| 40 | + |
| 41 | +instance = MyClass(12, "test", c=None) |
| 42 | +``` |
| 43 | + |
| 44 | +**Type safety**. MLC dataclass checks type strictly in Cython and C++. |
| 45 | + |
| 46 | +```python |
| 47 | +>>> instance.c = 10; print(instance) |
| 48 | +demo.MyClass(a=12, b='test', c=10.0) |
| 49 | + |
| 50 | +>>> instance.c = "wrong type" |
| 51 | +TypeError: must be real number, not str |
| 52 | + |
| 53 | +>>> instance.non_exist = 1 |
| 54 | +AttributeError: 'MyClass' object has no attribute 'non_exist' and no __dict__ for setting new attributes |
| 55 | +``` |
| 56 | + |
| 57 | +**Serialization**. MLC dataclasses are picklable and JSON-serializable. |
| 58 | + |
| 59 | +```python |
| 60 | +>>> MyClass.from_json(instance.json()) |
| 61 | +demo.MyClass(a=12, b='test', c=None) |
| 62 | + |
| 63 | +>>> import pickle; pickle.loads(pickle.dumps(instance)) |
| 64 | +demo.MyClass(a=12, b='test', c=None) |
33 | 65 | ```
|
34 | 66 |
|
35 |
| -### :gear: Build from Source |
| 67 | +### :dart: Structure-Aware Tooling |
| 68 | + |
| 69 | +An extra `structure` field are used to specify a dataclass's structure, indicating def site and scoping in an IR. |
| 70 | + |
| 71 | +```python |
| 72 | +import mlc.dataclasses as mlcd |
| 73 | + |
| 74 | +@mlcd.py_class |
| 75 | +class Expr(mlcd.PyClass): |
| 76 | + def __add__(self, other): |
| 77 | + return Add(a=self, b=other) |
| 78 | + |
| 79 | +@mlcd.py_class(structure="nobind") |
| 80 | +class Add(Expr): |
| 81 | + a: Expr |
| 82 | + b: Expr |
| 83 | + |
| 84 | +@mlcd.py_class(structure="var") |
| 85 | +class Var(Expr): |
| 86 | + name: str = mlcd.field(structure=None) # excludes `name` from defined structure |
| 87 | + |
| 88 | +@mlcd.py_class(structure="bind") |
| 89 | +class Let(Expr): |
| 90 | + rhs: Expr |
| 91 | + lhs: Var = mlcd.field(structure="bind") # `Let.lhs` is the def-site |
| 92 | + body: Expr |
| 93 | +``` |
| 94 | + |
| 95 | +**Structural equality**. Method eq_s is ready to use to compare the structural equality (alpha equivalence) of two IRs. |
| 96 | + |
| 97 | +```python |
| 98 | +""" |
| 99 | +L1: let z = x + y; z |
| 100 | +L2: let x = y + z; x |
| 101 | +L3: let z = x + x; z |
| 102 | +""" |
| 103 | +>>> x, y, z = Var("x"), Var("y"), Var("z") |
| 104 | +>>> L1 = Let(rhs=x + y, lhs=z, body=z) |
| 105 | +>>> L2 = Let(rhs=y + z, lhs=x, body=x) |
| 106 | +>>> L3 = Let(rhs=x + x, lhs=z, body=z) |
| 107 | +>>> L1.eq_s(L2) |
| 108 | +True |
| 109 | +>>> L1.eq_s(L3, assert_mode=True) |
| 110 | +ValueError: Structural equality check failed at {root}.rhs.b: Inconsistent binding. RHS has been bound to a different node while LHS is not bound |
| 111 | +``` |
| 112 | + |
| 113 | +**Structural hashing**. TBD |
| 114 | + |
| 115 | +### :snake: Text Formats in Python AST |
| 116 | + |
| 117 | +TBD |
| 118 | + |
| 119 | +### :zap: Zero-Copy Interoperability with C++ Plugins |
| 120 | + |
| 121 | +TBD |
| 122 | + |
| 123 | +## :fuelpump: Development |
| 124 | + |
| 125 | +### :gear: Editable Build |
36 | 126 |
|
37 | 127 | ```bash
|
38 |
| -python -m venv .venv |
39 |
| -source .venv/bin/activate |
40 |
| -python -m pip install --verbose --editable ".[dev]" |
| 128 | +pip install --verbose --editable ".[dev]" |
41 | 129 | pre-commit install
|
42 | 130 | ```
|
43 | 131 |
|
44 |
| -### :ferris_wheel: Create MLC-Python Wheels |
| 132 | +### :ferris_wheel: Create Wheels |
45 | 133 |
|
46 | 134 | This project uses `cibuildwheel` to build cross-platform wheels. See `.github/workflows/wheels.ym` for more details.
|
47 | 135 |
|
|
0 commit comments