Skip to content

Commit c1fe3b3

Browse files
Removed AuxLinearOperator.
This operator was originally introduced as a hack for Optimistix. It's now been unused for a while.
1 parent 09a31b3 commit c1fe3b3

3 files changed

Lines changed: 20 additions & 79 deletions

File tree

lineax/__init__.py

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -18,7 +18,6 @@
1818
from ._operator import (
1919
AbstractLinearOperator as AbstractLinearOperator,
2020
AddLinearOperator as AddLinearOperator,
21-
AuxLinearOperator as AuxLinearOperator,
2221
ComposedLinearOperator as ComposedLinearOperator,
2322
conj as conj,
2423
diagonal as diagonal,

lineax/_misc.py

Lines changed: 0 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,6 @@
1212
# See the License for the specific language governing permissions and
1313
# limitations under the License.
1414

15-
from collections.abc import Callable
1615

1716
import equinox as eqx
1817
import jax
@@ -39,13 +38,6 @@ def resolve_rcond(rcond, n, m, dtype):
3938
return jnp.where(rcond < 0, jnp.finfo(dtype).eps, rcond)
4039

4140

42-
class NoneAux(eqx.Module):
43-
fn: Callable
44-
45-
def __call__(self, *args, **kwargs):
46-
return self.fn(*args, **kwargs), None
47-
48-
4941
def jacobian(fn, in_size, out_size, holomorphic=False, has_aux=False, jac=None):
5042
if jac is None:
5143
# Heuristic for which is better in each case

lineax/_operator.py

Lines changed: 20 additions & 70 deletions
Original file line numberDiff line numberDiff line change
@@ -43,7 +43,6 @@
4343
default_floating_dtype,
4444
inexact_asarray,
4545
jacobian,
46-
NoneAux,
4746
strip_weak_dtype,
4847
)
4948
from ._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-
535526
class _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)
13471309
def _(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

15171477
def _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)
18831847
def _(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)
19471906
def _(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
19921947
for check in (
@@ -2272,8 +2227,3 @@ def _(operator):
22722227
@conj.register(ComposedLinearOperator)
22732228
def _(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

Comments
 (0)