1use std::any::Any;
15use std::hash::Hasher;
16use std::marker::PhantomData;
17use std::sync::Arc;
18
19use tenferro_ops::ext_op::{ExtensionAliasDeclaration, ExtensionEffectDeclaration};
20use tenferro_runtime::extension::{ExtensionOp, ExtensionShapeContext, SymDim};
21use tenferro_runtime::{
22 CoreCapabilityKind, EngineId, ErasedExecutionContext, ErrorPhase, ExecutionContextIdentity,
23 ExtensionCacheStore, ExtensionEngine, ExtensionModule, ExtensionModuleId,
24 ExtensionModuleRegistrar, ExtensionPlanningConfig, ExtensionPrepareRequest, PrepareCapability,
25 PrepareError, PreparedOperation, PreparedOperationBinding, PreparedOperationExecutor,
26 PreparedOperationPlan, ProviderContractError, RuntimeConfigError, SpecializationProjection,
27};
28use tenferro_tensor::{DType, DynRank, Engine, Host, Tensor, TensorRead, TypedTensor};
29
30use crate::Bf16;
31
32pub const BF16_EINSUM_FAMILY: &str = "tenferro-bf16-proof.einsum.v1";
34
35pub const BF16_SCALAR_IDENTITY: &str = "tenferro-bf16-proof.bf16.v1";
37
38#[derive(Clone, Debug, PartialEq, Eq)]
53pub struct Bf16Einsum {
54 lhs: Vec<u32>,
55 rhs: Vec<u32>,
56 out: Vec<u32>,
57}
58
59impl Bf16Einsum {
60 pub fn new(lhs: &[u32], rhs: &[u32], out: &[u32]) -> tenferro_runtime::Result<Self> {
80 let invalid = |message: &str| {
81 tenferro_runtime::Error::from(tenferro_tensor::Error::invalid_argument(
82 "bf16_einsum",
83 "pattern",
84 message,
85 ))
86 };
87 if lhs.is_empty() || rhs.is_empty() {
88 return Err(invalid("an operand must carry at least one label"));
89 }
90 for labels in [lhs, rhs, out] {
93 let mut seen = labels.to_vec();
94 seen.sort_unstable();
95 seen.dedup();
96 if seen.len() != labels.len() {
97 return Err(invalid(
98 "a label repeats within one operand or the output, which this pairwise contraction does not support",
99 ));
100 }
101 }
102 for label in out {
103 if !lhs.contains(label) && !rhs.contains(label) {
104 return Err(invalid(
105 "an output label must appear in at least one operand",
106 ));
107 }
108 }
109 Ok(Self {
110 lhs: lhs.to_vec(),
111 rhs: rhs.to_vec(),
112 out: out.to_vec(),
113 })
114 }
115
116 #[must_use]
127 pub fn labels(&self) -> (&[u32], &[u32], &[u32]) {
128 (&self.lhs, &self.rhs, &self.out)
129 }
130}
131
132impl ExtensionOp for Bf16Einsum {
133 fn family_id(&self) -> &'static str {
134 BF16_EINSUM_FAMILY
135 }
136
137 fn payload_hash(&self, hasher: &mut dyn Hasher) {
138 for labels in [&self.lhs, &self.rhs, &self.out] {
139 hasher.write_usize(labels.len());
140 for label in labels {
141 hasher.write_u32(*label);
142 }
143 }
144 }
145
146 fn payload_eq(&self, other: &dyn ExtensionOp) -> bool {
147 other
148 .as_any()
149 .downcast_ref::<Self>()
150 .is_some_and(|other| other == self)
151 }
152
153 fn clone_arc(&self) -> Arc<dyn ExtensionOp> {
154 Arc::new(self.clone())
155 }
156
157 fn as_any(&self) -> &dyn Any {
158 self
159 }
160
161 fn input_count(&self) -> usize {
162 2
163 }
164
165 fn output_count(&self) -> usize {
166 1
167 }
168
169 fn semantic_effects(&self) -> ExtensionEffectDeclaration<'_> {
170 ExtensionEffectDeclaration::Declared(&[])
171 }
172
173 fn semantic_aliases(&self) -> ExtensionAliasDeclaration<'_> {
174 ExtensionAliasDeclaration::AllFresh
175 }
176
177 fn scalar_identity(&self) -> Option<&'static str> {
178 Some(BF16_SCALAR_IDENTITY)
179 }
180
181 fn infer_output_meta(
182 &self,
183 ctx: &mut ExtensionShapeContext<'_>,
184 ) -> tenferro_tensor::Result<Vec<(DType, Vec<SymDim>)>> {
185 let dtype = ctx.input_dtype(0)?;
186 if !matches!(dtype, DType::External(_)) {
187 return Err(tenferro_tensor::Error::unsupported_dtype(
188 "bf16_einsum",
189 dtype,
190 "bf16_einsum takes an externally defined scalar",
191 ));
192 }
193 if ctx.input_dtype(1)? != dtype {
194 return Err(tenferro_tensor::Error::invalid_argument(
195 "bf16_einsum",
196 "inputs",
197 "both operands must carry the same scalar",
198 ));
199 }
200 let lhs = ctx.input_shape(0)?;
201 let rhs = ctx.input_shape(1)?;
202 if lhs.len() != self.lhs.len() || rhs.len() != self.rhs.len() {
203 return Err(tenferro_tensor::Error::rank_mismatch(
204 "bf16_einsum",
205 self.lhs.len().max(self.rhs.len()),
206 lhs.len().min(rhs.len()),
207 ));
208 }
209 let mut out_shape = Vec::with_capacity(self.out.len());
210 for label in &self.out {
211 let extent = self
212 .lhs
213 .iter()
214 .position(|candidate| candidate == label)
215 .map(|axis| lhs[axis].clone())
216 .or_else(|| {
217 self.rhs
218 .iter()
219 .position(|candidate| candidate == label)
220 .map(|axis| rhs[axis].clone())
221 })
222 .ok_or_else(|| {
223 tenferro_tensor::Error::invalid_argument(
224 "bf16_einsum",
225 "pattern",
226 "an output label must appear in at least one operand",
227 )
228 })?;
229 out_shape.push(extent);
230 }
231 Ok(vec![(dtype, out_shape)])
232 }
233}
234
235fn element_count(shape: &[usize]) -> usize {
237 shape.iter().product()
238}
239
240fn advance(index: &mut [usize], shape: &[usize]) {
242 for axis in 0..shape.len() {
243 index[axis] += 1;
244 if index[axis] < shape[axis] {
245 return;
246 }
247 index[axis] = 0;
248 }
249}
250
251fn offset_for(
253 input_labels: &[u32],
254 input_shape: &[usize],
255 out_labels: &[u32],
256 out_index: &[usize],
257 summed_labels: &[u32],
258 summed_index: &[usize],
259) -> usize {
260 let mut offset = 0usize;
261 let mut stride = 1usize;
262 for (axis, label) in input_labels.iter().enumerate() {
263 let position = out_labels
264 .iter()
265 .position(|candidate| candidate == label)
266 .map(|index| out_index[index])
267 .or_else(|| {
268 summed_labels
269 .iter()
270 .position(|candidate| candidate == label)
271 .map(|index| summed_index[index])
272 })
273 .unwrap_or(0);
274 offset += position * stride;
275 stride *= input_shape[axis];
276 }
277 offset
278}
279
280fn values_of(op: &'static str, tensor: &Tensor) -> tenferro_runtime::Result<Vec<f32>> {
282 match tensor.external_payload() {
283 Some(payload) => payload
284 .downcast_ref::<Bf16>()
285 .map(|stored| {
286 stored
287 .as_slice()
288 .iter()
289 .map(|value| value.to_f32())
290 .collect()
291 })
292 .ok_or_else(|| {
293 tenferro_runtime::Error::from(tenferro_tensor::Error::invalid_argument(
294 op,
295 "input",
296 "the operand does not carry a bfloat16 payload",
297 ))
298 }),
299 None => Err(tenferro_runtime::Error::from(
300 tenferro_tensor::Error::unsupported_dtype(
301 op,
302 tensor.dtype(),
303 "bf16_einsum takes an externally defined bfloat16 scalar",
304 ),
305 )),
306 }
307}
308
309fn contract(op: &dyn ExtensionOp, inputs: &[&Tensor]) -> tenferro_runtime::Result<Vec<Tensor>> {
311 let name = "bf16_einsum";
312 let Some(contraction) = op.as_any().downcast_ref::<Bf16Einsum>() else {
313 return Err(tenferro_runtime::Error::from(
314 tenferro_tensor::Error::invalid_argument(
315 name,
316 "payload",
317 "the operation is not a bfloat16 contraction",
318 ),
319 ));
320 };
321 if inputs.len() != 2 {
322 return Err(tenferro_runtime::Error::from(
323 tenferro_tensor::Error::invalid_argument(
324 name,
325 "input",
326 "a bf16 contraction takes two operands",
327 ),
328 ));
329 }
330 let (lhs_labels, rhs_labels, out_labels) = contraction.labels();
331 let lhs_values = values_of(name, inputs[0])?;
332 let rhs_values = values_of(name, inputs[1])?;
333 let lhs_shape = inputs[0].shape().to_vec();
334 let rhs_shape = inputs[1].shape().to_vec();
335
336 let mut extents: Vec<(u32, usize)> = Vec::new();
337 for (labels, shape) in [(lhs_labels, &lhs_shape), (rhs_labels, &rhs_shape)] {
338 for (axis, label) in labels.iter().enumerate() {
339 match extents.iter().find(|(existing, _)| existing == label) {
340 Some((_, existing)) if *existing != shape[axis] => {
341 return Err(tenferro_runtime::Error::from(
342 tenferro_tensor::Error::invalid_argument(
343 name,
344 "inputs",
345 "the operands disagree on the extent of a shared label",
346 ),
347 ))
348 }
349 Some(_) => {}
350 None => extents.push((*label, shape[axis])),
351 }
352 }
353 }
354 let extent_of = |label: u32| {
355 extents
356 .iter()
357 .find(|(existing, _)| *existing == label)
358 .map(|(_, extent)| *extent)
359 .unwrap_or(1)
360 };
361 let out_shape: Vec<usize> = out_labels.iter().map(|label| extent_of(*label)).collect();
362 let mut summed_labels: Vec<u32> = Vec::new();
363 for label in lhs_labels.iter().chain(rhs_labels.iter()) {
364 if !out_labels.contains(label) && !summed_labels.contains(label) {
365 summed_labels.push(*label);
366 }
367 }
368 let summed_shape: Vec<usize> = summed_labels
369 .iter()
370 .map(|label| extent_of(*label))
371 .collect();
372
373 let out_count = element_count(&out_shape);
374 let summed_count = element_count(&summed_shape);
375 let mut accumulated = vec![0.0_f32; out_count];
376 let mut out_index = vec![0usize; out_shape.len()];
377 let mut summed_index = vec![0usize; summed_shape.len()];
378 for slot in accumulated.iter_mut() {
379 for value in summed_index.iter_mut() {
380 *value = 0;
381 }
382 let mut total = 0.0_f32;
383 for _ in 0..summed_count {
384 let lhs_offset = offset_for(
385 lhs_labels,
386 &lhs_shape,
387 out_labels,
388 &out_index,
389 &summed_labels,
390 &summed_index,
391 );
392 let rhs_offset = offset_for(
393 rhs_labels,
394 &rhs_shape,
395 out_labels,
396 &out_index,
397 &summed_labels,
398 &summed_index,
399 );
400 total += lhs_values[lhs_offset] * rhs_values[rhs_offset];
401 advance(&mut summed_index, &summed_shape);
402 }
403 *slot = total;
404 advance(&mut out_index, &out_shape);
405 }
406
407 let rounded: Vec<Bf16> = accumulated.into_iter().map(Bf16::from_f32).collect();
409 let tensor = TypedTensor::<_, DynRank, Host>::from_host_vec_col_major(out_shape, rounded)
410 .map_err(tenferro_runtime::Error::from)?;
411 Ok(vec![Tensor::external(
412 tenferro_tensor::ErasedHostTensor::new(tensor),
413 )])
414}
415
416#[derive(Debug)]
418struct Bf16EinsumEngine<B: std::fmt::Debug + Send + Sync> {
419 family_id: &'static str,
420 engine_id: EngineId,
421 _backend: PhantomData<B>,
422}
423
424impl<B: Engine + std::fmt::Debug + Send + Sync + 'static> ExtensionEngine for Bf16EinsumEngine<B> {
425 fn family_id(&self) -> &'static str {
426 self.family_id
427 }
428
429 fn engine_id(&self) -> &EngineId {
430 &self.engine_id
431 }
432
433 fn context_identity(&self) -> ExecutionContextIdentity {
434 ExecutionContextIdentity::of::<B>()
435 }
436
437 fn prepare(
438 &self,
439 request: ExtensionPrepareRequest<'_>,
440 ) -> Result<PrepareCapability, PrepareError> {
441 if request.operation().family_id() != self.family_id {
442 return Err(PrepareError::ProviderContract {
443 source: ProviderContractError::WrongOperationFamily {
444 expected: CoreCapabilityKind::Elementwise,
445 operation: self.family_id,
446 },
447 });
448 }
449 let prepared = Arc::new(Bf16EinsumPrepared::<B> {
450 binding: request.binding().clone(),
451 specialization: request.specialization().clone(),
452 op: request.operation().clone_arc(),
453 _backend: PhantomData,
454 });
455 Ok(PrepareCapability::Prepared(
456 PreparedOperationPlan::executable(prepared.clone(), prepared),
457 ))
458 }
459}
460
461#[derive(Debug)]
466struct Bf16EinsumPlanning {
467 family_id: &'static str,
468}
469
470impl ExtensionPlanningConfig for Bf16EinsumPlanning {
471 fn family_id(&self) -> &'static str {
472 self.family_id
473 }
474
475 fn as_any(&self) -> &dyn Any {
476 self
477 }
478
479 fn payload_hash(&self, _state: &mut dyn Hasher) {}
480
481 fn payload_eq(&self, other: &dyn ExtensionPlanningConfig) -> bool {
482 other.family_id() == self.family_id
483 }
484
485 fn retained_bytes(&self) -> usize {
486 0
487 }
488}
489
490#[derive(Debug)]
492struct Bf16EinsumPrepared<B: std::fmt::Debug + Send + Sync> {
493 binding: PreparedOperationBinding,
494 specialization: SpecializationProjection,
495 op: Arc<dyn ExtensionOp>,
496 _backend: PhantomData<B>,
497}
498
499impl<B: Engine + std::fmt::Debug + Send + Sync + 'static> PreparedOperation
500 for Bf16EinsumPrepared<B>
501{
502 fn binding(&self) -> &PreparedOperationBinding {
503 &self.binding
504 }
505
506 fn specialization(&self) -> &SpecializationProjection {
507 &self.specialization
508 }
509
510 fn retained_bytes(&self) -> usize {
511 0
512 }
513}
514
515impl<B: Engine + std::fmt::Debug + Send + Sync + 'static> PreparedOperationExecutor
516 for Bf16EinsumPrepared<B>
517{
518 fn execute(
519 &self,
520 context: &mut ErasedExecutionContext<'_>,
521 extension_caches: &mut ExtensionCacheStore,
522 inputs: &[TensorRead<'_>],
523 ) -> tenferro_runtime::Result<Vec<Tensor>> {
524 let engine = context
526 .downcast_mut::<B>(self.binding.context_identity())
527 .map_err(|source| {
528 tenferro_runtime::Error::runtime_state_source(
529 "extension",
530 ErrorPhase::Execution,
531 source,
532 )
533 })?;
534 let _ = extension_caches;
535 let materialized = inputs
536 .iter()
537 .cloned()
538 .map(|input| engine.to_contiguous_read(input))
539 .collect::<tenferro_tensor::Result<Vec<Tensor>>>()
540 .map_err(tenferro_runtime::Error::from)?;
541 let borrowed: Vec<&Tensor> = materialized.iter().collect();
542 contract(self.op.as_ref(), &borrowed)
543 }
544}
545
546#[derive(Debug)]
548struct Bf16EinsumModule<B: std::fmt::Debug + Send + Sync> {
549 module_id: ExtensionModuleId,
550 engine_id: EngineId,
551 _backend: PhantomData<B>,
552}
553
554impl<B: Engine + std::fmt::Debug + Send + Sync + 'static> ExtensionModule for Bf16EinsumModule<B> {
555 fn module_id(&self) -> &ExtensionModuleId {
556 &self.module_id
557 }
558
559 fn configure(
560 &self,
561 registrar: &mut ExtensionModuleRegistrar<'_>,
562 ) -> Result<(), tenferro_runtime::ExtensionModuleError> {
563 registrar.register_engine(Arc::new(Bf16EinsumEngine::<B> {
564 family_id: BF16_EINSUM_FAMILY,
565 engine_id: self.engine_id.clone(),
566 _backend: PhantomData,
567 }))?;
568 registrar.register_planning_config(
569 self.engine_id.clone(),
570 Arc::new(Bf16EinsumPlanning {
571 family_id: BF16_EINSUM_FAMILY,
572 }),
573 )?;
574 Ok(())
575 }
576}
577
578pub fn module() -> Result<Arc<dyn ExtensionModule>, RuntimeConfigError> {
593 Ok(Arc::new(Bf16EinsumModule::<tenferro_cpu::CpuEngine> {
594 module_id: ExtensionModuleId::new("tenferro-bf16-proof.module")?,
595 engine_id: tenferro_cpu::runtime_engine_id()?,
596 _backend: PhantomData,
597 }))
598}