cbfpy 0.0.1__tar.gz → 0.0.4__tar.gz

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (38) hide show
  1. {cbfpy-0.0.1 → cbfpy-0.0.4}/PKG-INFO +24 -17
  2. {cbfpy-0.0.1 → cbfpy-0.0.4}/README.md +15 -10
  3. {cbfpy-0.0.1 → cbfpy-0.0.4}/cbfpy/cbfs/cbf.py +46 -70
  4. {cbfpy-0.0.1 → cbfpy-0.0.4}/cbfpy/cbfs/clf_cbf.py +81 -86
  5. {cbfpy-0.0.1 → cbfpy-0.0.4}/cbfpy/config/cbf_config.py +106 -56
  6. {cbfpy-0.0.1 → cbfpy-0.0.4}/cbfpy/config/clf_cbf_config.py +79 -29
  7. {cbfpy-0.0.1 → cbfpy-0.0.4}/cbfpy/envs/base_env.py +3 -3
  8. {cbfpy-0.0.1 → cbfpy-0.0.4}/cbfpy/envs/drone_env.py +1 -1
  9. {cbfpy-0.0.1 → cbfpy-0.0.4}/cbfpy/examples/adaptive_cruise_control_demo.py +5 -4
  10. {cbfpy-0.0.1 → cbfpy-0.0.4}/cbfpy/examples/drone_demo.py +8 -6
  11. {cbfpy-0.0.1 → cbfpy-0.0.4}/cbfpy/examples/joint_limits_demo.py +1 -1
  12. {cbfpy-0.0.1 → cbfpy-0.0.4}/cbfpy/examples/point_robot_obstacle_demo.py +7 -7
  13. {cbfpy-0.0.1 → cbfpy-0.0.4}/cbfpy.egg-info/PKG-INFO +24 -17
  14. {cbfpy-0.0.1 → cbfpy-0.0.4}/cbfpy.egg-info/SOURCES.txt +0 -1
  15. {cbfpy-0.0.1 → cbfpy-0.0.4}/cbfpy.egg-info/requires.txt +7 -5
  16. {cbfpy-0.0.1 → cbfpy-0.0.4}/cbfpy.egg-info/top_level.txt +1 -0
  17. {cbfpy-0.0.1 → cbfpy-0.0.4}/pyproject.toml +11 -9
  18. {cbfpy-0.0.1 → cbfpy-0.0.4}/test/test_speed.py +2 -2
  19. cbfpy-0.0.1/cbfpy/temp/test_import.py +0 -3
  20. {cbfpy-0.0.1 → cbfpy-0.0.4}/LICENSE +0 -0
  21. {cbfpy-0.0.1 → cbfpy-0.0.4}/cbfpy/__init__.py +0 -0
  22. {cbfpy-0.0.1 → cbfpy-0.0.4}/cbfpy/cbfs/__init__.py +0 -0
  23. {cbfpy-0.0.1 → cbfpy-0.0.4}/cbfpy/config/__init__.py +0 -0
  24. {cbfpy-0.0.1 → cbfpy-0.0.4}/cbfpy/envs/__init__.py +0 -0
  25. {cbfpy-0.0.1 → cbfpy-0.0.4}/cbfpy/envs/arm_envs.py +0 -0
  26. {cbfpy-0.0.1 → cbfpy-0.0.4}/cbfpy/envs/car_env.py +0 -0
  27. {cbfpy-0.0.1 → cbfpy-0.0.4}/cbfpy/envs/point_robot_envs.py +0 -0
  28. {cbfpy-0.0.1 → cbfpy-0.0.4}/cbfpy/examples/__init__.py +0 -0
  29. {cbfpy-0.0.1 → cbfpy-0.0.4}/cbfpy/examples/point_robot_demo.py +0 -0
  30. {cbfpy-0.0.1 → cbfpy-0.0.4}/cbfpy/utils/__init__.py +0 -0
  31. {cbfpy-0.0.1 → cbfpy-0.0.4}/cbfpy/utils/general_utils.py +0 -0
  32. {cbfpy-0.0.1 → cbfpy-0.0.4}/cbfpy/utils/jax_utils.py +0 -0
  33. {cbfpy-0.0.1 → cbfpy-0.0.4}/cbfpy/utils/math_utils.py +0 -0
  34. {cbfpy-0.0.1 → cbfpy-0.0.4}/cbfpy/utils/visualization.py +0 -0
  35. {cbfpy-0.0.1 → cbfpy-0.0.4}/cbfpy.egg-info/dependency_links.txt +0 -0
  36. {cbfpy-0.0.1 → cbfpy-0.0.4}/setup.cfg +0 -0
  37. {cbfpy-0.0.1 → cbfpy-0.0.4}/test/__init__.py +0 -0
  38. {cbfpy-0.0.1 → cbfpy-0.0.4}/test/test_utils.py +0 -0
@@ -1,6 +1,6 @@
1
- Metadata-Version: 2.1
1
+ Metadata-Version: 2.4
2
2
  Name: cbfpy
3
- Version: 0.0.1
3
+ Version: 0.0.4
4
4
  Summary: Control Barrier Functions in Python
5
5
  Author-email: Daniel Morton <danielpmorton@gmail.com>
6
6
  Project-URL: Documentation, https://danielpmorton.github.io/cbfpy/
@@ -8,15 +8,14 @@ Project-URL: Repository, https://github.com/danielpmorton/cbfpy/
8
8
  Keywords: control,barrier,function,CBF,Jax
9
9
  Classifier: Programming Language :: Python :: 3
10
10
  Classifier: License :: OSI Approved :: MIT License
11
- Classifier: Operating System :: OS Independent
12
11
  Description-Content-Type: text/markdown
13
12
  License-File: LICENSE
14
- Requires-Dist: numpy<2
13
+ Requires-Dist: numpy
15
14
  Requires-Dist: jax
16
15
  Requires-Dist: jaxlib
17
16
  Requires-Dist: qpax
18
17
  Provides-Extra: examples
19
- Requires-Dist: pybullet; extra == "examples"
18
+ Requires-Dist: pybullet>=3.2.7; extra == "examples"
20
19
  Requires-Dist: pygame; extra == "examples"
21
20
  Requires-Dist: wheel; extra == "examples"
22
21
  Requires-Dist: matplotlib; extra == "examples"
@@ -26,12 +25,19 @@ Requires-Dist: mkdocstrings[python]; extra == "dev"
26
25
  Requires-Dist: pylint; extra == "dev"
27
26
  Requires-Dist: black; extra == "dev"
28
27
  Provides-Extra: all
29
- Requires-Dist: pylint; extra == "all"
30
- Requires-Dist: black; extra == "all"
31
- Requires-Dist: pybullet; extra == "all"
28
+ Requires-Dist: pybullet>=3.2.7; extra == "all"
32
29
  Requires-Dist: pygame; extra == "all"
30
+ Requires-Dist: wheel; extra == "all"
31
+ Requires-Dist: matplotlib; extra == "all"
33
32
  Requires-Dist: mkdocs-material; extra == "all"
34
33
  Requires-Dist: mkdocstrings[python]; extra == "all"
34
+ Requires-Dist: pylint; extra == "all"
35
+ Requires-Dist: black; extra == "all"
36
+ Dynamic: license-file
37
+
38
+ <div align="center">
39
+ <img src="https://github.com/user-attachments/assets/0304752c-cb75-4d53-b45f-b6b1a0912d9c" alt="logo"></img>
40
+ </div>
35
41
 
36
42
  # CBFpy: Control Barrier Functions in Python and Jax
37
43
 
@@ -43,20 +49,21 @@ CBFpy is an easy-to-use and high-performance framework for constructing and solv
43
49
 
44
50
  For API reference, see the following [documentation](https://danielpmorton.github.io/cbfpy)
45
51
 
46
- If you use CBFpy in your research, please use the following citation:
52
+ If you use CBFpy in your research, please cite the following [paper](https://arxiv.org/abs/2503.06736):
47
53
 
48
54
  ```
49
- @software{Morton_CBFpy_2024,
50
- author = {Morton, Daniel},
51
- license = {MIT},
52
- title = {{CBFpy: Control Barrier Functions in Python and Jax}},
53
- url = {https://github.com/danielpmorton/cbfpy},
54
- version = {0.0.1},
55
- month = Dec,
56
- year = {2024}
55
+ @inproceedings{morton2025oscbf,
56
+ author={Morton, Daniel and Pavone, Marco},
57
+ booktitle={2025 IEEE/RSJ International Conference on Intelligent Robots and Systems (IROS)},
58
+ title={Safe, Task-Consistent Manipulation with Operational Space Control Barrier Functions},
59
+ year={2025},
60
+ pages={187-194},
61
+ doi={10.1109/IROS60139.2025.11246389}
57
62
  }
58
63
  ```
59
64
 
65
+ [![Paper](http://img.shields.io/badge/arXiv-2503.06736-B31B1B.svg)](https://arxiv.org/abs/2503.06736)
66
+
60
67
  ## Installation
61
68
 
62
69
  ### From PyPI
@@ -1,3 +1,7 @@
1
+ <div align="center">
2
+ <img src="https://github.com/user-attachments/assets/0304752c-cb75-4d53-b45f-b6b1a0912d9c" alt="logo"></img>
3
+ </div>
4
+
1
5
  # CBFpy: Control Barrier Functions in Python and Jax
2
6
 
3
7
  CBFpy is an easy-to-use and high-performance framework for constructing and solving Control Barrier Functions (CBFs) and Control Lyapunov Functions (CLFs), using [Jax](https://github.com/google/jax) for:
@@ -8,20 +12,21 @@ CBFpy is an easy-to-use and high-performance framework for constructing and solv
8
12
 
9
13
  For API reference, see the following [documentation](https://danielpmorton.github.io/cbfpy)
10
14
 
11
- If you use CBFpy in your research, please use the following citation:
15
+ If you use CBFpy in your research, please cite the following [paper](https://arxiv.org/abs/2503.06736):
12
16
 
13
17
  ```
14
- @software{Morton_CBFpy_2024,
15
- author = {Morton, Daniel},
16
- license = {MIT},
17
- title = {{CBFpy: Control Barrier Functions in Python and Jax}},
18
- url = {https://github.com/danielpmorton/cbfpy},
19
- version = {0.0.1},
20
- month = Dec,
21
- year = {2024}
18
+ @inproceedings{morton2025oscbf,
19
+ author={Morton, Daniel and Pavone, Marco},
20
+ booktitle={2025 IEEE/RSJ International Conference on Intelligent Robots and Systems (IROS)},
21
+ title={Safe, Task-Consistent Manipulation with Operational Space Control Barrier Functions},
22
+ year={2025},
23
+ pages={187-194},
24
+ doi={10.1109/IROS60139.2025.11246389}
22
25
  }
23
26
  ```
24
27
 
28
+ [![Paper](http://img.shields.io/badge/arXiv-2503.06736-B31B1B.svg)](https://arxiv.org/abs/2503.06736)
29
+
25
30
  ## Installation
26
31
 
27
32
  ### From PyPI
@@ -188,4 +193,4 @@ Use a CBF to keep a drone inside a safe box, while avoiding a moving obstacle. T
188
193
 
189
194
  This is the same CBF which was used in the ["Drone Fencing" demo](https://danielpmorton.github.io/drone_fencing/) at the Stanford Robotics center.
190
195
 
191
- ![Image: Quadrotor avoiding an obstacle](https://raw.githubusercontent.com/danielpmorton/cbfpy/refs/heads/main/images/drone_demo.gif)
196
+ ![Image: Quadrotor avoiding an obstacle](https://raw.githubusercontent.com/danielpmorton/cbfpy/refs/heads/main/images/drone_demo.gif)
@@ -30,17 +30,12 @@ import jax
30
30
  import jax.numpy as jnp
31
31
  from jax import Array
32
32
  from jax.typing import ArrayLike
33
+ import numpy as np
33
34
  import qpax
34
35
 
35
36
  from cbfpy.config.cbf_config import CBFConfig
36
- from cbfpy.utils.jax_utils import conditional_jit
37
37
  from cbfpy.utils.general_utils import print_warning
38
38
 
39
- # Debugging flags to disable jit in specific sections of the code.
40
- # Note: If any higher-level jits exist, those must also be set to debug (disable jit)
41
- DEBUG_SAFETY_FILTER = False
42
- DEBUG_QP_DATA = False
43
-
44
39
 
45
40
  @jax.tree_util.register_static
46
41
  class CBF:
@@ -73,8 +68,8 @@ class CBF:
73
68
  u_min: Optional[tuple],
74
69
  u_max: Optional[tuple],
75
70
  control_constrained: bool,
76
- relax_cbf: bool,
77
- cbf_relaxation_penalty: float,
71
+ relax_qp: bool,
72
+ constraint_relaxation_penalties: tuple,
78
73
  h_1: Callable[[ArrayLike], Array],
79
74
  h_2: Callable[[ArrayLike], Array],
80
75
  f: Callable[[ArrayLike], Array],
@@ -91,8 +86,8 @@ class CBF:
91
86
  self.u_min = u_min
92
87
  self.u_max = u_max
93
88
  self.control_constrained = control_constrained
94
- self.relax_cbf = relax_cbf
95
- self.cbf_relaxation_penalty = cbf_relaxation_penalty
89
+ self.relax_qp = relax_qp
90
+ self.constraint_relaxation_penalties = constraint_relaxation_penalties
96
91
  self.h_1 = h_1
97
92
  self.h_2 = h_2
98
93
  self.f = f
@@ -102,10 +97,6 @@ class CBF:
102
97
  self.P_config = P
103
98
  self.q_config = q
104
99
  self.solver_tol = solver_tol
105
- if relax_cbf:
106
- self.qp_solver: Callable = jax.jit(qpax.solve_qp_elastic)
107
- else:
108
- self.qp_solver: Callable = jax.jit(qpax.solve_qp)
109
100
 
110
101
  @classmethod
111
102
  def from_config(cls, config: CBFConfig) -> "CBF":
@@ -124,8 +115,8 @@ class CBF:
124
115
  config.u_min,
125
116
  config.u_max,
126
117
  config.control_constrained,
127
- config.relax_cbf,
128
- config.cbf_relaxation_penalty,
118
+ config.relax_qp,
119
+ config.constraint_relaxation_penalties,
129
120
  config.h_1,
130
121
  config.h_2,
131
122
  config.f,
@@ -136,19 +127,16 @@ class CBF:
136
127
  config.q,
137
128
  config.solver_tol,
138
129
  )
139
- instance._validate_instance(*config.init_args)
130
+ instance._validate_instance(*config.init_args, **config.init_kwargs)
140
131
  return instance
141
132
 
142
- def _validate_instance(self, *h_args) -> None:
143
- """Checks that the CBF is valid; warns the user if not
133
+ def _validate_instance(self, *args, **kwargs) -> None:
134
+ """Checks that the CBF is valid; warns the user if not"""
144
135
 
145
- Args:
146
- *h_args: Optional additional arguments for the barrier function.
147
- """
148
136
  try:
149
137
  # TODO: Decide if this should be checked on a row-by-row basis or via the full matrix
150
- test_lgh = self.Lgh(jnp.ones(self.n), *h_args)
151
- if jnp.allclose(test_lgh, 0):
138
+ test_lgh = self.Lgh(np.ones(self.n), *args, **kwargs)
139
+ if np.allclose(test_lgh, 0):
152
140
  print_warning(
153
141
  "Lgh is zero. Consider increasing the relative degree or modifying the barrier function."
154
142
  )
@@ -158,30 +146,29 @@ class CBF:
158
146
  + "Please provide an initial seed for these args in the config's init_args input"
159
147
  )
160
148
 
161
- @conditional_jit(not DEBUG_SAFETY_FILTER)
162
- def safety_filter(self, z: Array, u_des: Array, *h_args) -> Array:
149
+ @jax.jit
150
+ def safety_filter(self, z: Array, u_des: Array, *args, **kwargs) -> Array:
163
151
  """Apply the CBF safety filter to a nominal control
164
152
 
165
153
  Args:
166
154
  z (Array): State, shape (n,)
167
155
  u_des (Array): Desired control input, shape (m,)
168
- *h_args: Optional additional arguments for the barrier function.
169
156
 
170
157
  Returns:
171
158
  Array: Safe control input, shape (m,)
172
159
  """
173
- P, q, A, b, G, h = self.qp_data(z, u_des, *h_args)
174
- if self.relax_cbf:
175
- x_qp, t_qp, s1_qp, s2_qp, z1_qp, z2_qp, converged, iters = self.qp_solver(
160
+ P, q, A, b, G, h = self.qp_data(z, u_des, *args, **kwargs)
161
+ if self.relax_qp:
162
+ x_qp = qpax.solve_qp_elastic_primal(
176
163
  P,
177
164
  q,
178
165
  G,
179
166
  h,
180
- self.cbf_relaxation_penalty,
167
+ penalty=jnp.asarray(self.constraint_relaxation_penalties),
181
168
  solver_tol=self.solver_tol,
182
169
  )
183
170
  else:
184
- x_qp, s_qp, z_qp, y_qp, converged, iters = self.qp_solver(
171
+ x_qp, s_qp, z_qp, y_qp, converged, iters = qpax.solve_qp(
185
172
  P,
186
173
  q,
187
174
  A,
@@ -190,18 +177,13 @@ class CBF:
190
177
  h,
191
178
  solver_tol=self.solver_tol,
192
179
  )
193
- if DEBUG_SAFETY_FILTER:
194
- print(
195
- f"{'Converged' if converged else 'Did not converge'}. Iterations: {iters}"
196
- )
197
180
  return x_qp[: self.m]
198
181
 
199
- def h(self, z: ArrayLike, *h_args) -> Array:
182
+ def h(self, z: ArrayLike, *args, **kwargs) -> Array:
200
183
  """Barrier function(s)
201
184
 
202
185
  Args:
203
186
  z (ArrayLike): State, shape (n,)
204
- *h_args: Optional additional arguments for the barrier function.
205
187
 
206
188
  Returns:
207
189
  Array: Barrier function evaluation, shape (num_barr,)
@@ -209,16 +191,16 @@ class CBF:
209
191
 
210
192
  # Take any relative-degree-2 barrier functions and convert them to relative-degree-1
211
193
  def _h_2(state):
212
- return self.h_2(state, *h_args)
194
+ return self.h_2(state, *args, **kwargs)
213
195
 
214
- h_2, dh_2_dt = jax.jvp(_h_2, (z,), (self.f(z),))
215
- h_2_as_rd1 = dh_2_dt + self.alpha_2(h_2)
196
+ h_2, dh_2_dt = jax.jvp(_h_2, (z,), (self.f(z, *args, **kwargs),))
197
+ h_2_as_rd1 = dh_2_dt + self.alpha_2(h_2, *args, **kwargs)
216
198
 
217
199
  # Merge the relative-degree-1 and relative-degree-2 barrier functions
218
- return jnp.concatenate([self.h_1(z, *h_args), h_2_as_rd1])
200
+ return jnp.concatenate([self.h_1(z, *args, **kwargs), h_2_as_rd1])
219
201
 
220
202
  def h_and_Lfh( # pylint: disable=invalid-name
221
- self, z: ArrayLike, *h_args
203
+ self, z: ArrayLike, *args, **kwargs
222
204
  ) -> Tuple[Array, Array]:
223
205
  """Lie derivative of the barrier function(s) wrt the autonomous dynamics `f(z)`
224
206
 
@@ -226,7 +208,6 @@ class CBF:
226
208
 
227
209
  Args:
228
210
  z (ArrayLike): State, shape (n,)
229
- *h_args: Optional additional arguments for the barrier function.
230
211
 
231
212
  Returns:
232
213
  h (Array): Barrier function evaluation, shape (num_barr,)
@@ -236,16 +217,17 @@ class CBF:
236
217
  # with the bonus benefit of also evaluating the barrier function
237
218
 
238
219
  def _h(state):
239
- return self.h(state, *h_args)
220
+ return self.h(state, *args, **kwargs)
240
221
 
241
- return jax.jvp(_h, (z,), (self.f(z),))
222
+ return jax.jvp(_h, (z,), (self.f(z, *args, **kwargs),))
242
223
 
243
- def Lgh(self, z: ArrayLike, *h_args) -> Array: # pylint: disable=invalid-name
224
+ def Lgh(
225
+ self, z: ArrayLike, *args, **kwargs
226
+ ) -> Array: # pylint: disable=invalid-name
244
227
  """Lie derivative of the barrier function(s) wrt the control dynamics `g(z)u`
245
228
 
246
229
  Args:
247
230
  z (ArrayLike): State, shape (n,)
248
- *h_args: Optional additional arguments for the barrier function.
249
231
 
250
232
  Returns:
251
233
  Array: Lgh, shape (num_barr, m)
@@ -253,47 +235,45 @@ class CBF:
253
235
  # Note: the below code is just a more efficient way of stating `Lgh = jax.jacobian(self.h)(z) @ self.g(z)`
254
236
 
255
237
  def _h(state):
256
- return self.h(state, *h_args)
238
+ return self.h(state, *args, **kwargs)
257
239
 
258
240
  def _jvp(g_column):
259
241
  return jax.jvp(_h, (z,), (g_column,))[1]
260
242
 
261
- return jax.vmap(_jvp, in_axes=1, out_axes=1)(self.g(z))
243
+ return jax.vmap(_jvp, in_axes=1, out_axes=1)(self.g(z, *args, **kwargs))
262
244
 
263
245
  ## QP Matrices ##
264
246
 
265
247
  def P_qp( # pylint: disable=invalid-name
266
- self, z: Array, u_des: Array, *h_args
248
+ self, z: Array, u_des: Array, *args, **kwargs
267
249
  ) -> Array:
268
250
  """Quadratic term in the QP objective (`minimize 0.5 * x^T P x + q^T x`)
269
251
 
270
252
  Args:
271
253
  z (Array): State, shape (n,)
272
254
  u_des (Array): Desired control input, shape (m,)
273
- *h_args: Optional additional arguments for the barrier function.
274
255
 
275
256
  Returns:
276
257
  Array: P matrix, shape (m, m)
277
258
  """
278
259
  # This is user-modifiable in the config, but defaults to 2 * I for the standard min-norm CBF objective
279
- return self.P_config(z, u_des, *h_args)
260
+ return self.P_config(z, u_des, *args, **kwargs)
280
261
 
281
- def q_qp(self, z: Array, u_des: Array, *h_args) -> Array:
262
+ def q_qp(self, z: Array, u_des: Array, *args, **kwargs) -> Array:
282
263
  """Linear term in the QP objective (`minimize 0.5 * x^T P x + q^T x`)
283
264
 
284
265
  Args:
285
266
  z (Array): State, shape (n,)
286
267
  u_des (Array): Desired control input, shape (m,)
287
- *h_args: Optional additional arguments for the barrier function.
288
268
 
289
269
  Returns:
290
270
  Array: q vector, shape (m,)
291
271
  """
292
272
  # This is user-modifiable in the config, but defaults to -2 * u_des for the standard min-norm CBF objective
293
- return self.q_config(z, u_des, *h_args)
273
+ return self.q_config(z, u_des, *args, **kwargs)
294
274
 
295
275
  def G_qp( # pylint: disable=invalid-name
296
- self, z: Array, u_des: Array, *h_args
276
+ self, z: Array, u_des: Array, *args, **kwargs
297
277
  ) -> Array:
298
278
  """Inequality constraint matrix for the QP (`Gx <= h`)
299
279
 
@@ -305,18 +285,17 @@ class CBF:
305
285
  Args:
306
286
  z (Array): State, shape (n,)
307
287
  u_des (Array): Desired control input, shape (m,)
308
- *h_args: Optional additional arguments for the barrier function.
309
288
 
310
289
  Returns:
311
290
  Array: G matrix, shape (num_constraints, m)
312
291
  """
313
- G = -self.Lgh(z, *h_args)
292
+ G = -self.Lgh(z, *args, **kwargs)
314
293
  if self.control_constrained:
315
294
  return jnp.block([[G], [jnp.eye(self.m)], [-jnp.eye(self.m)]])
316
295
  else:
317
296
  return G
318
297
 
319
- def h_qp(self, z: Array, u_des: Array, *h_args) -> Array:
298
+ def h_qp(self, z: Array, u_des: Array, *args, **kwargs) -> Array:
320
299
  """Upper bound on constraints for the QP (`Gx <= h`)
321
300
 
322
301
  Note:
@@ -327,13 +306,12 @@ class CBF:
327
306
  Args:
328
307
  z (Array): State, shape (n,)
329
308
  u_des (Array): Desired control input, shape (m,)
330
- *h_args: Optional additional arguments for the barrier function.
331
309
 
332
310
  Returns:
333
311
  Array: h vector, shape (num_constraints,)
334
312
  """
335
- hz, lfh = self.h_and_Lfh(z, *h_args)
336
- h = self.alpha(hz) + lfh
313
+ hz, lfh = self.h_and_Lfh(z, *args, **kwargs)
314
+ h = self.alpha(hz, *args, **kwargs) + lfh
337
315
  if self.control_constrained:
338
316
  return jnp.concatenate(
339
317
  [h, jnp.asarray(self.u_max), -jnp.asarray(self.u_min)]
@@ -341,9 +319,8 @@ class CBF:
341
319
  else:
342
320
  return h
343
321
 
344
- @conditional_jit(not DEBUG_QP_DATA)
345
322
  def qp_data(
346
- self, z: Array, u_des: Array, *h_args
323
+ self, z: Array, u_des: Array, *args, **kwargs
347
324
  ) -> Tuple[Array, Array, Array, Array, Array, Array]:
348
325
  """Constructs the QP matrices based on the current state and desired control
349
326
 
@@ -364,7 +341,6 @@ class CBF:
364
341
  Args:
365
342
  z (Array): State, shape (n,)
366
343
  u_des (Array): Desired control input, shape (m,)
367
- *h_args: Optional additional arguments for the barrier function.
368
344
 
369
345
  Returns:
370
346
  P (Array): Quadratic term in the QP objective, shape (m, m)
@@ -375,10 +351,10 @@ class CBF:
375
351
  h (Array): Upper bound on constraints, shape (num_constraints,)
376
352
  """
377
353
  return (
378
- self.P_qp(z, u_des, *h_args),
379
- self.q_qp(z, u_des, *h_args),
354
+ self.P_qp(z, u_des, *args, **kwargs),
355
+ self.q_qp(z, u_des, *args, **kwargs),
380
356
  jnp.zeros((0, self.m)), # Equality matrix (not used for CBF)
381
357
  jnp.zeros(0), # Equality vector (not used for CBF)
382
- self.G_qp(z, u_des, *h_args),
383
- self.h_qp(z, u_des, *h_args),
358
+ self.G_qp(z, u_des, *args, **kwargs),
359
+ self.h_qp(z, u_des, *args, **kwargs),
384
360
  )