Skip to content

Commit 4733a03

Browse files
thisiscamclaude
andcommitted
README: replace copula example for effective_order with a generic one
The motivating workload no longer references a specific application. Reframe as: "the order varies across calls or across vmap-batched elements, and you don't want to recompile or pay full-K cost per call." Example uses jnp.exp(jnp.sin(x)) at varying truncation orders plus a vmap demonstration with per-element orders. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
1 parent 4246857 commit 4733a03

1 file changed

Lines changed: 30 additions & 29 deletions

File tree

‎README.md‎

Lines changed: 30 additions & 29 deletions
Original file line numberDiff line numberDiff line change
@@ -183,18 +183,20 @@ is fixed.
183183

184184
### When you want this
185185

186-
A motivating workload: nested-Archimedean copula likelihoods with
187-
per-observation censoring. Each observation needs a Bell-polynomial
188-
expansion whose effective order equals its number of *uncensored* leaves,
189-
which varies across the batch. Without `effective_order`, you face two
190-
bad options:
186+
The expansion order `K` is part of the input shape, so a function
187+
`jet`'d at one `K` re-traces and re-compiles for any other `K`. If the
188+
order you actually need varies across calls — different time steps in
189+
an integrator, different inputs in a batch, different convergence
190+
checks in an iterative method — you would otherwise face two bad
191+
options:
191192

192-
- Pad to the maximum possible order for every observation — wasted work
193-
on always-zero coefficients.
194-
- Re-trace and re-compile per observation — fatal under high cardinality.
193+
- Pad every call to the maximum possible order. Wastes compute on
194+
coefficients you don't use.
195+
- Re-trace per order. Fatal whenever the order changes more often than
196+
the cost of compilation.
195197

196-
`effective_order` lets you compile once at `K = max possible order` and
197-
pay per-observation work proportional to that observation's actual order.
198+
`effective_order` resolves both: compile once at `K = max possible
199+
order` and pay per-call work proportional to that call's actual order.
198200

199201
### Example
200202

@@ -205,30 +207,29 @@ from jet_array import jet
205207

206208
K_MAX = 16 # static array size
207209

208-
def slow_chain(x):
209-
# A composition that uses several primitives whose rules respect
210-
# effective_order — exp/log/logistic are good candidates.
211-
y = jnp.exp(x)
212-
y = jnp.log1p(y)
213-
y = jnp.tanh(y)
214-
return y
215-
216210
@jax.jit
217211
def taylor(x, k_dyn):
212+
"""Taylor series of exp(sin(x)) at x, computed up to order k_dyn,
213+
with a fixed array size of K_MAX so a single XLA program handles
214+
every order."""
218215
series_in = jnp.zeros(K_MAX).at[0].set(1.0)
219-
return jet(slow_chain, (x,), (series_in,), effective_order=k_dyn)
220-
221-
# Both calls use the same compiled XLA program.
222-
# The second runs more work — it computes 12 coefficients instead of 4.
223-
p1, s1 = taylor(jnp.asarray(0.5), jnp.array(4))
224-
p2, s2 = taylor(jnp.asarray(0.5), jnp.array(12))
225-
# s1[:4] is the answer you can use; s1[4:] is unspecified.
226-
# s2[:12] is the answer; s2[12:] is unspecified.
216+
return jet(lambda x: jnp.exp(jnp.sin(x)), (x,), (series_in,),
217+
effective_order=k_dyn)
218+
219+
# Both calls hit the same compiled program; the second does more work.
220+
p1, s1 = taylor(jnp.asarray(0.5), jnp.array(4)) # uses s1[:4]
221+
p2, s2 = taylor(jnp.asarray(0.5), jnp.array(12)) # uses s2[:12]
227222
```
228223

229-
For workloads where the dynamic order varies per element of a
230-
`vmap`-batched dimension, pass an array of `effective_order` values and
231-
combine with `jax.vmap`.
224+
For batches where each element wants its own order, pass an array of
225+
`effective_order` values and combine with `jax.vmap`:
226+
227+
```python
228+
xs = jnp.linspace(0.0, 1.0, 100)
229+
ks = jnp.array([3, 5, 8, 12] * 25) # one per batch element
230+
batched = jax.vmap(taylor)(xs, ks)
231+
# batched.series[i, :ks[i]] is the answer for element i.
232+
```
232233

233234
### Caveats
234235

0 commit comments

Comments
 (0)