Skip to main content

CBFJAX — Control Barrier Functions in JAX

Python 3.9+ JAX License: MIT PyPI version

CBFJAX is a high-performance JAX implementation of Control Barrier Functions (CBFs) for safety-critical control. It provides a clean, functional, JIT-compatible API for building safe controllers — from simple closed-form filters up to Backup-CBFs and NMPC with barrier constraints — and runs efficiently on CPU and GPU.

This project is the JAX successor to the CBFTorch framework.


Features

  • Pure JAX, end-to-end JIT — barriers, dynamics, and safety filters are all equinox modules with functional semantics; trajectory rollouts use diffrax.
  • Higher-Order CBFs (HOCBFs) with automatic differentiation for arbitrary relative degree.
  • Predicted-Flow CBFs (P-CBFs) — barriers that are functionals of a predicted flow under a parametrized control plan, certifying safety over the whole prediction horizon in a single QP:
    • FlowBarrier + ParametricFlowSafeControl
    • FlowBarrier2 + ParametricFlowSafeControl2
  • A toolbox of controllers and safe-control backends:
    • Closed-form min-intervention safe control (MinIntervCFSafeControl)
    • QP-based safe control with slack variables (MinIntervQPSafeControl)
    • Input-constrained QP (MinIntervInputConstQPSafeControl)
    • Backup-CBF with forward invariance (MinIntervBackupSafeControl)
    • Predicted-flow safe control (ParametricFlowSafeControl, …Control2)
    • MPPI with barrier-aware cost (MPPIControl)
    • NMPC with barrier constraints (acados / do-mpc — optional)
    • Constrained iLQR with barrier-aware cost (trajax — optional)
  • Pluggable QP backends behind one interface (params['qp_solver']): qpax (default), jaxopt_osqp (warm-started), mpax, and cvxopt.
  • Composable barrier algebra: MultiBarriers, SoftCompositionBarrier, HardCompositionBarrier, BackupBarrier, FlowBarrier, FlowBarrier2.
  • Config-driven construction (cbfjax.from_config): a named barrier namespace — define barriers by name, reference them by name, wire one into the filter; unused entries stay available for plotting/analysis.
  • Built-in dynamics: unicycle, single/double integrator, kinematic bicycle, inverted pendulum, reduced-order unicycle — plus a generic AffineInControlDynamics base and a CustomDynamics escape hatch.
  • 64-bit precision by default for the numerical stability that CBF methods require.

Installation

From PyPI

pip install cbfjax

The install pulls in JAX, Equinox, Diffrax, qpax, jaxopt, mpax, matplotlib, NumPy, and SciPy — enough to run every safety filter and every example.

Development install

pip install cbfjax[dev]

Adds the optional solver backends (cvxopt, CasADi + do-mpc for NMPC) and the development tooling (pytest, build, twine, ruff, black, mypy, …).

From source

git clone https://github.com/amirsaeid254/cbfjax.git
cd cbfjax
pip install -e .[dev,examples]

Quick Start

Everything is built from one config dict — named barriers, referenced by name, and one controller consuming the barrier it names:

dynamics ──► barriers {name: spec, ...} ──► filter ──► safe action u(x)
                                              ▲
                       desired_control (goal controller / iLQR / MPPI planner)

Minimal example — QP safety filter on a unicycle

import jax.numpy as jnp
import cbfjax

goal = jnp.array([5.0, 5.0])

system = cbfjax.from_config({
    # 1. Dynamics — state [x, y, v, theta], control [a, omega]
    'dynamics': 'unicycle',

    # 2. Barriers — every barrier gets a name
    'barriers': {
        # stay outside the unit disk at the origin (relative degree 2)
        'disk': {'type': 'func',
                 'h': lambda x: jnp.linalg.norm(x[:2]) - 1.0,
                 'rel_deg': 2, 'alphas': (10.0,)},
    },

    # 3. QP-based min-intervention safety filter consuming 'disk'
    'filter': {
        'type': 'min_interv_qp',
        'barrier': 'disk',
        'action_dim': 2,
        'alpha': lambda h: 1.0 * h,
        'params': {'slack_gain': 200.0, 'slacked': True, 'qp_solver': 'qpax'},
        'desired_control': lambda x: 0.5 * jnp.array([goal[0] - x[0],
                                                      goal[1] - x[1]]),
    },
})

# 4. Query the safe action (single state in, single action out)
x0 = jnp.array([-2.0, -2.0, 0.0, 0.0])
u_safe, _ = system.filter.optimal_control(x0, system.filter.get_init_state())
print(u_safe)

Maps and compositions

A map entry turns a geometric world description into member barriers, and compositions reduce them: soft_composition (scalar softmin — what closed-form filters need), hard_composition (scalar exact min), or multi_barrier (one QP constraint per member). Entries nobody consumes are still built — handy for plotting and analysis.

cfg = {
    'dynamics': 'unicycle',
    'barriers': {
        'map': {'type': 'map',
                'geoms': (
                    ('cylinder', {'center': (2.0, 2.0), 'radius': 0.5}),
                    ('norm_box', {'center': (-1.0, 3.0), 'size': (1.0, 1.0)}),
                    ('norm_boundary', {'center': (0.0, 0.0), 'size': (10.0, 10.0)}),
                ),
                'velocity': (2, (-2.0, 2.0)),
                'cfg': {'softmin_rho': 20, 'pos_barrier_rel_deg': 2,
                        'vel_barrier_rel_deg': 1, 'obstacle_alpha': (10.0,),
                        'boundary_alpha': (10.0,), 'velocity_alpha': ()}},
        'rows': {'type': 'multi_barrier', 'barriers': ['map']},
    },
    'filter': {'type': 'min_interv_input_const_qp', 'barrier': 'rows', ...},
}
system = cbfjax.from_config(cfg)
system.barriers['map']     # the Map instance — plotting, member access
system.barriers['rows']    # the MultiBarriers the filter consumes

Closed-loop simulation

trajs = system.filter.get_optimal_trajs(
    x0=x0[None],           # (batch, state_dim)
    sim_time=10.0,
    timestep=0.01,
    method='euler',
)
print(trajs.shape)  # (T, batch, state_dim)

More end-to-end scripts live under examples/unicycle/ (closed-form, QP, input-constrained QP, NMPC, iLQR, hierarchical) and examples/unicycle/backup/ (Backup-CBF).

cd examples/unicycle
python 03_unicycle_qp.py

Architecture

cbfjax/
├── barriers/                       # CBF & HOCBF
│   ├── barrier.py                  #  Single barrier
│   ├── multi_barrier.py            #  Multiple barriers
│   ├── composite_barrier.py        #  Soft / hard composition
│   ├── backup_barrier.py           #  Backup-CBF
│   ├── parametric_flow_barrier.py  #  Predicted-flow CBF
│   └── parametric_flow_barrier2.py
├── dynamics/                       # Affine-in-control system dynamics
│   ├── base_dynamic.py
│   ├── unicycle.py
│   ├── unicycle_reduced_order.py
│   ├── double_integrator.py
│   ├── single_integrator.py
│   ├── bicycle.py
│   └── inverted_pendulum.py
├── controls/                       # Nominal/optimal controllers
│   ├── base_control.py
│   ├── mppi_control.py             #  MPPI (GPU-parallel, vmap+scan)
│   ├── parametric_control.py       #  ZOH / FOH control plans u_p(τ; θ)
│   ├── ilqr_control.py             #  (optional: trajax)
│   ├── nmpc_control.py             #  (optional: casadi + acados/do-mpc)
│   └── control_types.py
├── safe_controls/                  # Safety filters
│   ├── base_safe_control.py
│   ├── closed_form_safe_control.py
│   ├── qp_safe_control.py
│   ├── backup_safe_control.py
│   ├── parametric_flow_safe_control.py   #  Predicted-flow safe control
│   ├── parametric_flow_safe_control2.py
│   ├── nmpc_safe_control.py        #  (optional)
│   └── ilqr_safe_control.py        #  (optional)
├── factory.py                      # from_config: named-barrier construction
├── utils/
│   ├── integration.py              #  Diffrax-based ODE rollouts
│   ├── qp.py                       #  QP backends (qpax, OSQP, mpax, cvxopt)
│   ├── make_map.py                 #  Map / barrier factory
│   ├── jax2casadi/                 #  JAX → CasADi conversion (used by NMPC)
│   ├── profile_utils.py
│   └── utils.py
└── config.py                       # JAX configuration helpers

Key concepts

Control Barrier Functions

For a control-affine system ẋ = f(x) + g(x) u and a safe set C = {x | h(x) ≥ 0}, a barrier function h ensures forward invariance of C whenever there exists u such that

L_f h(x) + L_g h(x) · u ≥ -α(h(x))

where α is a class-K function.

Higher-Order CBFs

For barriers of relative degree r > 1, CBFJAX automatically constructs the HOCBF series ψ_0, ψ_1, …, ψ_r from a user-provided list of class-K functions (via Barrier(barrier_func=h, rel_deg=r, alphas=[α_1, …, α_r], dynamics=dyn) or a {'type': 'func', 'h': h, 'rel_deg': r, 'alphas': [...]} config entry).


Citation

If you use CBFJAX in your research, please cite it as:

@article{safari2026predicted,
  title={Predicted-Flow Control Barrier Functions for Real-Time Safe Optimal Control},
  author={Safari, Amirsaeid and Hoagg, Jesse B},
  journal={arXiv preprint arXiv:2606.00297},
  year={2026}
}

Related work

  • CBFTorch — PyTorch implementation of CBFs.

Metadata

Release files for cbfjax 0.2.0

For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.

Source distribution (sdist)

Source distribution for cbfjax 0.2.0
File Size Uploaded Provenance Actions
cbfjax-0.2.0.tar.gz 131.3 kB Without provenance Details for cbfjax-0.2.0.tar.gz

Built distribution (wheel)

Table of built distributions (wheels) for cbfjax 0.2.0
File Interpreter ABI Platform Actions
cbfjax-0.2.0-py3-none-any.whl Python 3 none any Details for cbfjax-0.2.0-py3-none-any.whl

Total release size: 282.1 kB

Release files / cbfjax-0.2.0.tar.gz

Download URL cbfjax-0.2.0.tar.gz
Size 131.3 kB
Tags Source
SHA-256 checksum
How to use checksums
7f7a5f7e21a68009cecf80a8b0edb02b77d57c39a4ef530f1107f481de44f25c
BLAKE2b-256 checksum
How to use checksums
d22d62c591470bd2e2703726a8d4a124b92f15875e6746bd739959c97742f5fb
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
No
Uploaded via twine/6.2.0 CPython/3.10.18

Release files / cbfjax-0.2.0-py3-none-any.whl

Download URL cbfjax-0.2.0-py3-none-any.whl
Size 150.8 kB
Tags Python 3
SHA-256 checksum
How to use checksums
7efb2222412ba7596da88c1f5a5ddbdecf7a599b694a86491fe124d8de630584
BLAKE2b-256 checksum
How to use checksums
b3e78cd6c240a2edf6c6e8555766542d88283056efc575549f33118da7981e7d
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
No
Uploaded via twine/6.2.0 CPython/3.10.18

Security for cbfjax 0.2.0

Provenance

Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.

No provenance found

None of the files in this release were uploaded with provenance metadata.

A note on package security

PyPI is a repository for distributing packages, not a service for auditing them. While third-party security researchers and our staff do their best to detect and remove malicious packages, PyPI cannot guarantee the quality, security or suitability of any given package.

To learn more about protecting yourself from malicious actors, visit our package security documentation.

Release history Release notifications | RSS feed

This release

0.2.0 This release

2 release files No provenance

Anthropic, PBC Visionary sponsor Bloomberg Visionary sponsor Hudson River Trading Visionary sponsor Meta Visionary sponsor NVIDIA Visionary sponsor Microsoft Sustainability sponsor Depot Continuous Integration AWS Cloud computing and Security Sponsor Datadog Monitoring Fastly CDN Google Download Analytics Sentry Error logging StatusPage Status page