I am looking for someone who can help us with the math underlying dynamic borrow checking for NumPy arrays. We are trying to make the rust-numpy
crate enforce aliasing discipline when creating Rust references into the interior of NumPy arrays. As NumPy supports multiple views into a single allocation and also wrapping foreign array types (we do this for example to wrap ndarray arrays), this leads to the following general problem which I would call a linear equation in a constrained integer domain:
Given an array A
with data pointer P_A
, dimensionality N_A
, dimensions D_{1,A}
, ..., D_{N_A,A}
(positive integers) and strides S_{1,A}
, ..., S_{N_A,A}
(non-zero integers) and an array B
with data pointer P_B
, dimensionality N_B
, dimensions D_{1,B}
, ..., D_{N_B,B}
and strides S_{1,B}
, ..., S_{N_B,B}
, does the equation
P_A + S_{1,A} * I_{1,A} + ... + S_{N_A,A} * I_{N_A,A} = P_B + S_{1,B} * I_{1,B} + ... S_{N_B,B} * I_{N_B,B}
have a solution in the domain defined by 0 <= I_{i,a} < D_{i,a}
for each i in {1,...,N_a}
and a in {A,B}
.
So basically, are there any two sets indices for A
and B
which will point to the same element in the underlying allocation.
(The main obstacle leading to this is that Rust's type system is not around when these views are created, in contrast to e.g. ndarray, so that we have to infer this post-facto via runtime checks instead of checking e.g. the indices that define the views themselves.)
I would be grateful if anybody had advice on how best tackle this? Or could point me to some literature which would help me to better understand where similar problems are addressed?
(I think there is an angle to consider this as an optimization problem by aiming to minimize the difference between the left-hand side and the right-side of the equation and then checking if it is actually zero. But IIRC integer linear programs with bounds often end up being NP? I also vaguely fear that this might end up being equivalent to satisfiability via a binary representation of the indices.)