I made a C++ operator overloading implementation of Ricci calculus once upon a time. That way you could define your tensors and then write statements like:
T = (rho + p)*u("^a")u("^b") + p * g("^a^b");
traceT = T("^a_a");
Anyways, I find the domain specific language of this particular numpy function to be a bit abhorrent. Why not write "ik,kj->ij" as "M_ij = A_ik * B_kj" and make it much more obvious what is happening instead of requiring this understanding. Heck, if you used kwargs, you could even avoid passing the same argument multiple times like in the quadratic form example: x = np.ricci_calculus("M_ij v^i v^j", M, v)
Here I am leaving out that "x = ..." prefix in the DSL since you can take an ordering convention and a scalar has no slots anyways.