mod frpr;
mod hadamard;
mod kron;
mod matmul;
mod trace;
mod write;
pub use frpr::FRPRStruct;
pub use hadamard::HadamardStruct;
pub use kron::KronStruct;
pub use matmul::MatmulStruct;
pub use trace::TraceStruct;
pub use write::WriteStruct;
use super::buffer::SizedTensorBuffer;
use qudit_core::ComplexScalar;
use qudit_core::ParamInfo;
use std::collections::BTreeMap;
type GradOffsetTuple = (usize, usize, usize, bool, usize, usize);
type GradOffsetList = Vec<GradOffsetTuple>;
type HessOffsetTuple = (
usize,
usize,
usize,
bool,
usize,
usize,
usize,
usize,
usize,
usize,
);
type HessOffsetList = Vec<HessOffsetTuple>;
fn cache_grad_offset_list<C: ComplexScalar>(
left: &SizedTensorBuffer<C>,
right: &SizedTensorBuffer<C>,
out: &SizedTensorBuffer<C>,
left_param_info: &ParamInfo,
right_param_info: &ParamInfo,
) -> GradOffsetList {
let sorted_left = left_param_info.sorted_non_constant();
let sorted_right = right_param_info.sorted_non_constant();
let mut offset_map = BTreeMap::new();
for (i, param) in sorted_left.iter().enumerate() {
offset_map.insert(
param,
(
left.offset() + left.unit_memory_size() * (i + 1),
right.offset(),
false,
0,
0,
),
);
}
for (i, param) in sorted_right.iter().enumerate() {
offset_map
.entry(param)
.and_modify(|offs| {
offs.2 = true;
offs.3 = left.offset();
offs.4 = right.offset() + right.unit_memory_size() * (i + 1);
})
.or_insert((
left.offset(),
right.offset() + right.unit_memory_size() * (i + 1),
false,
0,
0,
));
}
let mut vec = offset_map.into_iter().collect::<Vec<_>>();
vec.sort();
vec.into_iter()
.enumerate()
.map(|(i, (_, (l_off, r_off, prod, l2_off, r2_off)))| {
(
l_off,
r_off,
out.offset() + out.unit_memory_size() * (i + 1),
prod,
l2_off,
r2_off,
)
})
.collect::<Vec<_>>()
}
fn cache_hess_offset_list<C: ComplexScalar>(
left: &SizedTensorBuffer<C>,
right: &SizedTensorBuffer<C>,
out: &SizedTensorBuffer<C>,
left_param_info: &ParamInfo,
right_param_info: &ParamInfo,
) -> HessOffsetList {
let sorted_left = left_param_info.sorted_non_constant();
let sorted_right = right_param_info.sorted_non_constant();
let mut offset_map = BTreeMap::new();
for (i, param_i) in sorted_left.iter().enumerate() {
for (j, param_j) in sorted_left.iter().enumerate() {
if param_i > param_j {
continue;
}
let k = if i <= j {
j * (j + 1) / 2 + i
} else {
i * (i + 1) / 2 + j
};
offset_map.insert(
(param_i, param_j),
(
left.offset() + left.grad_memory_size() + left.unit_memory_size() * (k + 1),
right.offset(),
false,
0,
0,
left.offset() + left.unit_memory_size() * (i + 1),
0,
left.offset() + left.unit_memory_size() * (j + 1),
0,
),
);
}
}
for (i, param_i) in sorted_right.iter().enumerate() {
for (j, param_j) in sorted_right.iter().enumerate() {
if param_i > param_j {
continue;
}
let k = if i <= j {
j * (j + 1) / 2 + i
} else {
i * (i + 1) / 2 + j
};
offset_map
.entry((param_i, param_j))
.and_modify(|offs| {
offs.2 = true;
offs.3 = left.offset();
offs.4 = right.offset()
+ right.grad_memory_size()
+ right.unit_memory_size() * (k + 1);
offs.6 = right.offset() + right.unit_memory_size() * (j + 1);
offs.8 = right.offset() + right.unit_memory_size() * (i + 1);
})
.or_insert((
left.offset(),
right.offset() + right.grad_memory_size() + right.unit_memory_size() * (k + 1),
false,
0,
0,
0,
right.offset() + right.unit_memory_size() * (j + 1),
0,
right.offset() + right.unit_memory_size() * (i + 1),
));
}
}
for (i, param_i) in sorted_left.iter().enumerate() {
for (j, param_j) in sorted_right.iter().enumerate() {
offset_map
.entry((param_i, param_j))
.or_insert((
left.offset() + left.unit_memory_size() * (i + 1),
right.offset() + right.unit_memory_size() * (j + 1),
false,
0,
0,
0,
0,
0,
0,
));
}
}
let mut vec = offset_map.into_iter().collect::<Vec<_>>();
vec.sort();
vec.into_iter()
.enumerate()
.map(
|(k, (_, (l_off, r_off, prod, l2_off, r2_off, l3_off, r3_off, l4_off, r4_off)))| {
(
l_off,
r_off,
out.offset() + out.grad_memory_size() + out.unit_memory_size() * (k + 1),
prod,
l2_off,
r2_off,
l3_off,
r3_off,
l4_off,
r4_off,
)
},
)
.collect::<Vec<_>>()
}