bimm-contracts
Overview
This is a no_std inline contract programming library for tensor geometry
for the burn tensor framework.
Contract programming, or Design by Contract, is a programming paradigm that specifies the rights and obligations of software components.
The goal of this library is to make in-line geometry contracts:
- Easy to Read, Write, and Use,
- Performant at Runtime (so they can always be enabled),
- Verbose and Helpful in their error messages.
Recent Changes
- 0.19.0
- Switched to
burntracking versioning. - Dropped explicit support for
tch.
- Switched to
- 0.4.2
- Add
#[track_caller]support for better error messages.
- Add
- 0.4.0
- Decouple versioning from
bimm.
- Decouple versioning from
- 0.3.0
- Modularized framework features, made
features=["burn"]non-default. - Renamed
run_every_nth!torun_periodically!. - Added utility macros:
assert_shape_contract!,assert_shape_contract_periodically!,unpack_shape_contract!
- Modularized framework features, made
- 0.2.5
- full support for
"dim_label" = EXPRpatterns in contracts.
- full support for
- 0.2.4
- no_std support.
Features
burn: Shape support for burn types:&Tensor,&Shape,Shape.
ToDo
I'm particularly interested in PRs which provide:
- Potential combined static-def + runtime call
unpack_shape!andassert_shape!macros. - Explore
ShapeArgumentinterface to build an abstract reference-based index type; to avoid a stackVec<usize>allocation. - Add framework support for additional tensor types.
- Potential re-work of
shape_contract!'s macro parser's:- For grammar issues,
- For error reporting,
- To firm up case testing.
- Speed tuning of the solver's fast-path.
It would be nice if the short-path unpack keys worked with labels; requiring a test for "the keys are derivable from the expression contract, so they are all single params, ellipsis, ignored, or labeled.":
let = unpack_shape_contract!;
API
Users will primarily use the macros:
- [
unpack_shape_contract], - [
assert_shape_contract], and - [
assert_shape_contract_periodically].
For example:
use unpack_shape_contract;
let shape = ;
// In release builds, this has a benchmark of ~160ns:
let = unpack_shape_contract!;
assert_eq!;
assert_eq!;
assert_eq!;
assert_eq!;
In turn, these macros wrap the layer 2 api:
- [
shape_contract] - a macro for defining shape contracts from expressions. - [
define_shape_contract] - a macro for defining a static contract. - [
ShapeContract] - the constructed contract type.- [
ShapeContract::assert_shape] - assert a contract. - [
ShapeContract::unpack_shape] - assert a contract, and unpack geometry components.
- [
- [
run_periodically] - a macro for running code on an incrementally lengthening schedule.
ShapeArgument Support
The shape methods take a [ShapeArgument] parameter; with implementations for:
&[usize],&[usize; D],&[u32],&[u32; D],&[i32],&[i32; D],&Vec<usize>,&Vec<u32>,&Vec<i32>
With features = ["burn"]:
burn::prelude::Shape,&burn::prelude::Shape,&burn::prelude::Tensor
Speed and Stack Design
Contracts are only useful when they are fast enough to be always enabled.
As a result, this library is designed to be fast at runtime,
focusing on static contracts and using stack over heap wherever possible.
Benchmarks on release builds are available under cargo bench -p bimm-contracts:
Running benches/contracts.rs (target/release/deps/contracts-86950340ff3748c1)
unpack_shape time: [176.03 ns 177.39 ns 178.81 ns]
Found 2 outliers among 100 measurements (2.00%)
1 (1.00%) high mild
1 (1.00%) high severe
assert_shape time: [166.57 ns 168.00 ns 169.60 ns]
Found 2 outliers among 100 measurements (2.00%)
1 (1.00%) high mild
1 (1.00%) high severe
assert_shape_every_nth/assert_shape_every_nth
time: [4.4057 ns 4.4769 ns 4.5726 ns]
Found 14 outliers among 100 measurements (14.00%)
6 (6.00%) high mild
8 (8.00%) high severe
shape_contract! macro
The shape_contract! macro is a compile-time macro that parses a shape contract
from a shape contract pattern:
use ;
static CONTRACT: ShapeContract = shape_contract!;
A shape pattern is made of one or more dimension matcher terms:
_: for any shape; ignores the size, but requires the dimension to exist.,...: for ellipsis; matches any number of dimensions, only one ellipsis is allowed,- a dim expression.
ShapeContract => <LabeledExpr> { ',' <LabeledExpr> }* ','?
LabeledExpr => {Param "="}? <Expr>
Expr => <Term> { <AddOp> <Term> }
Term => <Power> { <MulOp> <Power> }
Power => <Factor> [ ^ <usize> ]
Factor => <Param> | ( '(' <Expression> ')' ) | NegOp <Factor>
Param => '"' <identifier> '"'
identifier => { <alpha> | "_" } { <alphanumeric> | "_" }*
NegOp => '+' | '-'
AddOp => '+' | '-'
MulOp => '*'
Usage Example
use ;
use BasicOps;
use ;
/// Window Partition
///
/// ## Parameters
///
/// - `tensor`: Input tensor of shape (B, h_wins * window_size, w_wins * window_size, C).
/// - `window_size`: Window size.
///
/// ## Returns
///
/// Output tensor of shape (B * h_windows * w_windows, window_size, window_size, C).
///
/// ## Panics
///
/// Panics if the input tensor does not have 4 dimensions.
Error Messages
Error messages are verbose and helpful.
use ;
use indoc;