4343 default_floating_dtype ,
4444 inexact_asarray ,
4545 jacobian ,
46- NoneAux ,
4746 strip_weak_dtype ,
4847)
4948from ._tags import (
@@ -524,14 +523,6 @@ def __call__(self, x):
524523 return self .fn (x , self .args )
525524
526525
527- class _NoAuxOut (eqx .Module ):
528- fn : Callable
529-
530- def __call__ (self , x ):
531- f , _ = self .fn (x )
532- return f
533-
534-
535526class _Unwrap (eqx .Module ):
536527 fn : Callable
537528
@@ -573,16 +564,15 @@ class JacobianLinearOperator(AbstractLinearOperator):
573564 tags : frozenset [object ] = eqx .field (static = True )
574565 jac : Literal ["fwd" , "bwd" ] | None
575566
576- @eqxi .doc_remove_args ("closure_convert" , "_has_aux" )
567+ @eqxi .doc_remove_args ("closure_convert" )
577568 def __init__ (
578569 self ,
579570 fn : Callable ,
580571 x : PyTree [ArrayLike ],
581572 args : PyTree [Any ] = None ,
582573 tags : object | Iterable [object ] = (),
583- closure_convert : bool = True ,
584- _has_aux : bool = False , # TODO(kidger): remove, no longer used
585574 jac : Literal ["fwd" , "bwd" ] | None = None ,
575+ closure_convert : bool = True ,
586576 ):
587577 """**Arguments:**
588578
@@ -606,8 +596,6 @@ def __init__(
606596 "`jac` argument of `JacobianLinearOperator` should be either "
607597 "`'fwd'`, `'bwd'`, or `None`."
608598 )
609- if not _has_aux :
610- fn = NoneAux (fn )
611599 # Flush out any closed-over values, so that we can safely pass `self`
612600 # across API boundaries. (In particular, across `linear_solve_p`.)
613601 # We don't use `jax.closure_convert` as that only flushes autodiffable
@@ -625,7 +613,7 @@ def __init__(
625613 self .jac = jac
626614
627615 def mv (self , vector ):
628- fn = _NoAuxOut ( _NoAuxIn (self .fn , self .args ) )
616+ fn = _NoAuxIn (self .fn , self .args )
629617 if self .jac == "fwd" or self .jac is None :
630618 _ , out = jax .jvp (fn , (self .x ,), (vector ,))
631619 elif self .jac == "bwd" :
@@ -651,7 +639,7 @@ def as_matrix(self):
651639 def transpose (self ):
652640 if is_symmetric (self ):
653641 return self
654- fn = _NoAuxOut ( _NoAuxIn (self .fn , self .args ) )
642+ fn = _NoAuxIn (self .fn , self .args )
655643 # Works because vjpfn is a PyTree
656644 _ , vjpfn = jax .vjp (fn , self .x )
657645 vjpfn = _Unwrap (vjpfn )
@@ -663,7 +651,7 @@ def in_structure(self):
663651 return strip_weak_dtype (jax .eval_shape (lambda : self .x ))
664652
665653 def out_structure (self ):
666- fn = _NoAuxOut ( _NoAuxIn (self .fn , self .args ) )
654+ fn = _NoAuxIn (self .fn , self .args )
667655 return strip_weak_dtype (eqxi .cached_filter_eval_shape (fn , self .x ))
668656
669657
@@ -1168,30 +1156,6 @@ def out_structure(self):
11681156 return self .operator1 .out_structure ()
11691157
11701158
1171- class AuxLinearOperator (AbstractLinearOperator ):
1172- """Internal to lineax. Used to represent a linear operator with additional
1173- metadata attached.
1174- """
1175-
1176- operator : AbstractLinearOperator
1177- aux : PyTree [Array ]
1178-
1179- def mv (self , vector ):
1180- return self .operator .mv (vector )
1181-
1182- def as_matrix (self ):
1183- return self .operator .as_matrix ()
1184-
1185- def transpose (self ):
1186- return self .operator .transpose ()
1187-
1188- def in_structure (self ):
1189- return self .operator .in_structure ()
1190-
1191- def out_structure (self ):
1192- return self .operator .out_structure ()
1193-
1194-
11951159#
11961160# Operations on `AbstractLinearOperator`s.
11971161# These are done through `singledispatch` rather than as methods.
@@ -1260,7 +1224,7 @@ def _(operator):
12601224 if operator .jac == "bwd" :
12611225 # For backward mode, use VJP + linear_transpose.
12621226 # This works even with custom_vjp functions that don't support forward-mode AD.
1263- _ , vjp_fn , aux = jax .vjp (fn , operator .x , has_aux = True )
1227+ _ , vjp_fn = jax .vjp (fn , operator .x )
12641228 if is_symmetric (operator ):
12651229 # For symmetric: J = J.T, so vjp directly gives J @ v
12661230 lin = _Unwrap (vjp_fn )
@@ -1270,10 +1234,8 @@ def _(operator):
12701234 jax .linear_transpose (lambda g : vjp_fn (g )[0 ], operator .out_structure ())
12711235 )
12721236 else : # "fwd" or None
1273- (_ , aux ), lin = jax .linearize (fn , operator .x )
1274- lin = _NoAuxOut (lin )
1275- out = FunctionLinearOperator (lin , operator .in_structure (), operator .tags )
1276- return AuxLinearOperator (out , aux )
1237+ _ , lin = jax .linearize (fn , operator .x )
1238+ return FunctionLinearOperator (lin , operator .in_structure (), operator .tags )
12771239
12781240
12791241# materialise
@@ -1346,16 +1308,14 @@ def _(operator):
13461308@materialise .register (JacobianLinearOperator )
13471309def _ (operator ):
13481310 fn = _NoAuxIn (operator .fn , operator .args )
1349- jac , aux = jacobian (
1311+ jac = jacobian (
13501312 fn ,
13511313 operator .in_size (),
13521314 operator .out_size (),
13531315 holomorphic = any (jnp .iscomplexobj (xi ) for xi in jtu .tree_leaves (operator .x )),
1354- has_aux = True ,
13551316 jac = operator .jac ,
13561317 )(operator .x )
1357- out = PyTreeLinearOperator (jac , operator .out_structure (), operator .tags )
1358- return AuxLinearOperator (out , aux )
1318+ return PyTreeLinearOperator (jac , operator .out_structure (), operator .tags )
13591319
13601320
13611321@materialise .register (FunctionLinearOperator )
@@ -1516,8 +1476,16 @@ def is_symmetric(operator: AbstractLinearOperator) -> bool:
15161476
15171477def _has_real_dtype (operator ) -> bool :
15181478 """Check if all dtypes in an operator's structure are real (not complex)."""
1519- leaves = jtu .tree_leaves (operator .in_structure ())
1520- return all (jnp .issubdtype (leaf .dtype , jnp .floating ) for leaf in leaves )
1479+ leaves = jtu .tree_leaves ((operator .in_structure (), operator .out_structure ()))
1480+ dtype = jnp .result_type (* leaves )
1481+ if jnp .issubdtype (dtype , jnp .complexfloating ):
1482+ return False
1483+ elif jnp .issubdtype (dtype , jnp .floating ):
1484+ return True
1485+ else :
1486+ assert False , (
1487+ "Only `jnp.floating` and `jnp.complexfloating` dtypes are understood."
1488+ )
15211489
15221490
15231491@is_symmetric .register (MatrixLinearOperator )
@@ -1874,10 +1842,6 @@ def _(operator, transform=transform):
18741842 def _ (operator , transform = transform ):
18751843 return transform (operator .operator ) / operator .scalar
18761844
1877- @transform .register (AuxLinearOperator ) # pyright: ignore
1878- def _ (operator , transform = transform ):
1879- return transform (operator .operator )
1880-
18811845
18821846@linearise .register (TangentLinearOperator )
18831847def _ (operator ):
@@ -1938,11 +1902,6 @@ def _(operator):
19381902 return (diag / operator .scalar , lower / operator .scalar , upper / operator .scalar )
19391903
19401904
1941- @tridiagonal .register (AuxLinearOperator )
1942- def _ (operator ):
1943- return tridiagonal (operator .operator )
1944-
1945-
19461905@linearise .register (ComposedLinearOperator )
19471906def _ (operator ):
19481907 return linearise (operator .operator1 ) @ linearise (operator .operator2 )
@@ -1983,10 +1942,6 @@ def _(operator):
19831942 def _ (operator , check = check ):
19841943 return check (operator .primal )
19851944
1986- @check .register (AuxLinearOperator )
1987- def _ (operator , check = check ):
1988- return check (operator .operator )
1989-
19901945
19911946# Scaling/negating preserves these structural properties
19921947for check in (
@@ -2272,8 +2227,3 @@ def _(operator):
22722227@conj .register (ComposedLinearOperator )
22732228def _ (operator ):
22742229 return conj (operator .operator1 ) @ conj (operator .operator2 )
2275-
2276-
2277- @conj .register (AuxLinearOperator )
2278- def _ (operator ):
2279- return conj (operator .operator )
0 commit comments