Use case
Kinematics chains every hyperelastic model starts from: J = det(F), ∂J/∂F = J F⁻ᵀ, F⁻ᵀ written either as inv(trans(F)) or trans(inv(F)).
What happens today (probed on main)
diff(det(F), F) -> det(F)*inv(trans(F)):I{4}
inner_product(A,{1,2},I4,{1,2}) -> A:I{4} (not A)
inner_product(I4,{3,4},A,{1,2}) -> I{4}:A (not A)
*inv(trans(F)) == *trans(inv(F)) -> false (two spellings of F⁻ᵀ)
A*I2 and I2*A do fold to A, so the rank-2 identity is handled; the rank-4 identity I{4} (δ_ik δ_jl) contracted on a full index pair is not, although it is exactly the identity map on rank-2 tensors. The determinant derivative — the most common derivative in finite-strain mechanics — therefore always carries a dead contraction into generated code.
Proposal
inner_product(A, {1,2}, I4, {1,2}) → A and inner_product(I4, {3,4}, A, {1,2}) → A for the rank-4 minor identity (and the analogous full-pair contractions at rank 4: C4 : I4 → C4), as construction-time rules beside the existing A*I2 → A.
- Canonicalize
trans(inv(A)) → inv(trans(A)) (or the reverse — one spelling) so equality, like-term merging and codegen see one node. Optional: an inv_trans accessor/printer form so a backend can emit tmech::invT style calls directly.
- Tests:
diff(det(F), F) prints det(F)*inv(trans(F)); the two spellings compare equal; numeric check unchanged.
Scope
Small. Rules live in tensor_functions.h (inner_product factory) and tensor/simplifier/; the identity node already self-classifies at construction (#258).
Signed-off-by: petlenz [email protected]
Use case
Kinematics chains every hyperelastic model starts from:
J = det(F),∂J/∂F = J F⁻ᵀ,F⁻ᵀwritten either asinv(trans(F))ortrans(inv(F)).What happens today (probed on main)
A*I2andI2*Ado fold toA, so the rank-2 identity is handled; the rank-4 identityI{4}(δ_ik δ_jl) contracted on a full index pair is not, although it is exactly the identity map on rank-2 tensors. The determinant derivative — the most common derivative in finite-strain mechanics — therefore always carries a dead contraction into generated code.Proposal
inner_product(A, {1,2}, I4, {1,2}) → Aandinner_product(I4, {3,4}, A, {1,2}) → Afor the rank-4 minor identity (and the analogous full-pair contractions at rank 4:C4 : I4 → C4), as construction-time rules beside the existingA*I2 → A.trans(inv(A)) → inv(trans(A))(or the reverse — one spelling) so equality, like-term merging and codegen see one node. Optional: aninv_transaccessor/printer form so a backend can emittmech::invTstyle calls directly.diff(det(F), F)printsdet(F)*inv(trans(F)); the two spellings compare equal; numeric check unchanged.Scope
Small. Rules live in
tensor_functions.h(inner_productfactory) andtensor/simplifier/; the identity node already self-classifies at construction (#258).Signed-off-by: petlenz [email protected]