import numpy as np
# Example 1: (2, 2, 3) @ (2, 3, 2) → (2, 2, 2)
a = np.array([1,2,3,4,5,6,7,8,9,10,11,12], dtype=np.float32).reshape(2, 2, 3, order='F')
b = np.array([1,2,3,4,5,6,7,8,9,10,11,12], dtype=np.float32).reshape(2, 3, 2, order='F')
result1 = np.matmul(a, b)
print("Example 1 Shape:", result1.shape)
print(result1.flatten(order='F'))
# Example 2: Broadcasting (3, 1, 2, 3) @ (1, 4, 3, 2) → (3, 4, 2, 2)
c = np.array([1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18],
dtype=np.float32).reshape(3,1,2,3, order='F')
d = np.array([1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24],
dtype=np.float32).reshape(1, 4, 3, 2, order='F')
result2 = np.matmul(c, d)
print("Example 2 Shape:", result2.shape)
print(result2.flatten(order='F'))
# data = np.arange(1, 25, dtype=np.float32)
# # reshape using order='F' to match column-major layout
# mat = np.reshape(data, (2, 3, 4), order='F')
# vec = np.array([1., 2., 3.], dtype=np.float32)
# # perform matmul (NumPy handles broadcasting automatically)
# result = np.matmul(vec, mat) # equivalent to Tensor::matmul(vec, mat)
# print("mat shape:", mat.shape)
# print("vec shape:", vec.shape)
# print("result shape:", result.shape)
# print(result)
# vec2 = np.array([1., 2., 3., 4.], dtype=np.float32)
# mat2 = np.reshape(np.arange(1, 25, dtype=np.float32), (2, 3, 4), order='F')
# result = np.matmul(mat2, vec2)
# print(result.shape) # (2, 3)
# print(result)
aW1wb3J0IG51bXB5IGFzIG5wCgojIEV4YW1wbGUgMTogKDIsIDIsIDMpIEAgKDIsIDMsIDIpIOKGkiAoMiwgMiwgMikKYSA9IG5wLmFycmF5KFsxLDIsMyw0LDUsNiw3LDgsOSwxMCwxMSwxMl0sIGR0eXBlPW5wLmZsb2F0MzIpLnJlc2hhcGUoMiwgMiwgMywgb3JkZXI9J0YnKQpiID0gbnAuYXJyYXkoWzEsMiwzLDQsNSw2LDcsOCw5LDEwLDExLDEyXSwgZHR5cGU9bnAuZmxvYXQzMikucmVzaGFwZSgyLCAzLCAyLCBvcmRlcj0nRicpCgpyZXN1bHQxID0gbnAubWF0bXVsKGEsIGIpCnByaW50KCJFeGFtcGxlIDEgU2hhcGU6IiwgcmVzdWx0MS5zaGFwZSkKcHJpbnQocmVzdWx0MS5mbGF0dGVuKG9yZGVyPSdGJykpCgojIEV4YW1wbGUgMjogQnJvYWRjYXN0aW5nICgzLCAxLCAyLCAzKSBAICgxLCA0LCAzLCAyKSDihpIgKDMsIDQsIDIsIDIpCmMgPSBucC5hcnJheShbMSwgMiwgMywgNCwgNSwgNiwgNywgOCwgOSwgMTAsIDExLCAxMiwgMTMsIDE0LCAxNSwgMTYsIDE3LCAxOF0sIAogICAgICAgICAgICAgZHR5cGU9bnAuZmxvYXQzMikucmVzaGFwZSgzLDEsMiwzLCBvcmRlcj0nRicpCmQgPSBucC5hcnJheShbMSwgMiwgMywgNCwgNSwgNiwgNywgOCwgOSwgMTAsIDExLCAxMiwgMTMsIDE0LCAxNSwgMTYsIDE3LCAxOCwgMTksIDIwLCAyMSwgMjIsIDIzLCAyNF0sIAogICAgICAgICAgICAgZHR5cGU9bnAuZmxvYXQzMikucmVzaGFwZSgxLCA0LCAzLCAyLCBvcmRlcj0nRicpCgpyZXN1bHQyID0gbnAubWF0bXVsKGMsIGQpCnByaW50KCJFeGFtcGxlIDIgU2hhcGU6IiwgcmVzdWx0Mi5zaGFwZSkKcHJpbnQocmVzdWx0Mi5mbGF0dGVuKG9yZGVyPSdGJykpCgoKCiMgZGF0YSA9IG5wLmFyYW5nZSgxLCAyNSwgZHR5cGU9bnAuZmxvYXQzMikKCiMgIyByZXNoYXBlIHVzaW5nIG9yZGVyPSdGJyB0byBtYXRjaCBjb2x1bW4tbWFqb3IgbGF5b3V0CiMgbWF0ID0gbnAucmVzaGFwZShkYXRhLCAoMiwgMywgNCksIG9yZGVyPSdGJykKIyB2ZWMgPSBucC5hcnJheShbMS4sIDIuLCAzLl0sIGR0eXBlPW5wLmZsb2F0MzIpCgojICMgcGVyZm9ybSBtYXRtdWwgKE51bVB5IGhhbmRsZXMgYnJvYWRjYXN0aW5nIGF1dG9tYXRpY2FsbHkpCiMgcmVzdWx0ID0gbnAubWF0bXVsKHZlYywgbWF0KSAgICAjIGVxdWl2YWxlbnQgdG8gVGVuc29yOjptYXRtdWwodmVjLCBtYXQpCgojIHByaW50KCJtYXQgc2hhcGU6IiwgbWF0LnNoYXBlKQojIHByaW50KCJ2ZWMgc2hhcGU6IiwgdmVjLnNoYXBlKQojIHByaW50KCJyZXN1bHQgc2hhcGU6IiwgcmVzdWx0LnNoYXBlKQojIHByaW50KHJlc3VsdCkKCgojIHZlYzIgPSBucC5hcnJheShbMS4sIDIuLCAzLiwgNC5dLCBkdHlwZT1ucC5mbG9hdDMyKQojIG1hdDIgPSBucC5yZXNoYXBlKG5wLmFyYW5nZSgxLCAyNSwgZHR5cGU9bnAuZmxvYXQzMiksICgyLCAzLCA0KSwgb3JkZXI9J0YnKQojIHJlc3VsdCA9IG5wLm1hdG11bChtYXQyLCB2ZWMyKQoKIyBwcmludChyZXN1bHQuc2hhcGUpICAjICgyLCAzKQojIHByaW50KHJlc3VsdCkKCg==