-
Notifications
You must be signed in to change notification settings - Fork 0
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
get jacobian and hessian not only row by row #2
Comments
Hi @eweca-d I see only three possible output matrices. What's the difference between contiguous column by column and contiguous row by row? I will need some time to think of the implementation. What you're suggesting is helpful, but would require separate functions since the output type is for each case is different. Ideally I would like one function that returns the output no matter what the desired output shape is. Doing such things with vectors is easy, but also uses heap allocations which I want to avoid. Give me some to think about it. I will update you soon. |
"contiguous column by column" is the flatten array of column-major matrix, "contiguous row by row" is the flatten array of row-major matrix. There can be constructed by: pub fn get_custom<T: ComplexFloat, const NUM_FUNCS: usize, const NUM_VARS: usize>(function_matrix: &[&dyn Fn(&[T; NUM_VARS]) -> T; NUM_FUNCS], vector_of_points: &[T; NUM_VARS], step_size: f64, mode: mode::DiffMode) -> Result<[[T; NUM_VARS]; NUM_FUNCS], ErrorCode>
{
if function_matrix.is_empty()
{
return Err(ErrorCode::VectorOfFunctionsCannotBeEmpty);
}
// row-major
let mut result = [[T::zero(); NUM_VARS]; NUM_FUNCS];
for row_index in 0..NUM_FUNCS
{
for col_index in 0..NUM_VARS
{
result[row_index][col_index] = single_derivative::get_partial_custom(&function_matrix[row_index], col_index, vector_of_points, step_size, mode)?;
}
}
// col-major
let mut result = [[T::zero(); NUM_FUNCS]; NUM_VARS];
for col_index in 0..NUM_VARS
{
for row_index in 0..NUM_FUNCS
{
result[col_index][row_index] = single_derivative::get_partial_custom(&function_matrix[row_index], col_index, vector_of_points, step_size, mode)?;
}
}
// contiguous row by row
let mut result = [T::zero(); NUM_VARS * NUM_FUNCS];
for row_index in 0..NUM_FUNCS
{
for col_index in 0..NUM_VARS
{
result[row_index * NUM_VARS + col_index] = single_derivative::get_partial_custom(&function_matrix[row_index], col_index, vector_of_points, step_size, mode)?;
}
}
// contiguous col by col
let mut result = [T::zero(); NUM_FUNCS * NUM_VARS];
for col_index in 0..NUM_VARS
{
for row_index in 0..NUM_FUNCS
{
result[col_index * NUM_FUNCS + row_index] = single_derivative::get_partial_custom(&function_matrix[row_index], col_index, vector_of_points, step_size, mode)?;
}
}
return Ok(result);
} As for the heap allocations, I do not think it is a problem. The current implement can just work for a small size Jacobian matrix. However, if I try to fit a curve with 20000 data points, the stack will overflow. Furthermore, the vector has no significant impact on the performance if the size is relatively large. I recommend replace the array of array by |
We can return An example: fn main() {
let a = [0.0, 0.1, 0.2];
let b = [1.1, 1.2];
let jacobian = get_jacobian::<3, 2, 6>(a, b);
println!("{:?}", jacobian);
}
fn get_jacobian_custom<const N: usize, const M: usize, const L: usize>(array1: [f64; N], array2: [f64; M]) -> [f64; L] {
let mut jacobian = [0.0; L];
for i in 0..N {
for j in 0..M {
jacobian[i * M + j] = array1[i] * array2[j];
}
}
jacobian
}
fn get_jacobian<const N: usize, const M: usize, const L: usize>(array1: [f64; N], array2: [f64; M]) -> [[f64; M]; N] {
let jacobian: [f64; L] = get_jacobian_custom(array1, array2);
let ptr = jacobian.as_ptr() as *const [[f64; M]; N];
unsafe { *ptr }
} We can only replace |
You point about stack overflow is a good one. Unfortunately even with nalgebra the static matrices (SMatrix) would soon overflow with 20000 points. What we really need here is a DMatrix for heap allocation. I have started a bigger task of providing methods using vectors and DMatrices as an optional feature of the crate. That one might take some time, but I'm working on it! |
Thank you for your effort! I really expect to enable the new features in my work. |
https://github.com/kmolan/multicalc-rust?tab=readme-ov-file#16-experimental Long term solution is to hand-roll my own numeric trait, but for now this should atleast help you with stack overflows. |
Thank you so much! It will really help if I derive a big Jacobian matrix in my work! |
I am using this crate to do curve fitting with 'nalgebra' that is an algebra crate. For all I know, most algebra library tends to use column-major matrix and store matrix in a vec storage. Hence, I think it is better to provide new api or pass the paramter to control the output matrix shape to be:
[[T; ncols]; nrows]
[[T; nrows]; ncols]
[T; nrows * ncols]
=> default for many crates[T; nrows * ncols]
Thank you for your great job. It works very well in my crate right now.
The text was updated successfully, but these errors were encountered: