# AutoDiffManifold Implementation Tasks **Ngày tạo**: 2024-12-19 **Cập nhật**: 2024-12-19 **Priority**: ⭐⭐⭐ (Medium - Có workaround, nhưng nên implement để đầy đủ) **Estimated Effort**: ✅ **COMPLETE** - Cả C wrapper và C# wrapper đã hoàn thành --- ## 📋 Tổng Quan `AutoDiffManifold` là replacement cho `AutoDiffLocalParameterization` trong Ceres 2.2.0. **Status**: - ✅ **C Wrapper**: **ĐÃ HOÀN THÀNH** - Đã implement trong `ipc/CeresWrapper/` - ✅ **C# Wrapper**: **ĐÃ HOÀN THÀNH** - Đã implement trong `CeresSharp/` **Use Case chính**: `ConstantYawQuaternionPlus` trong Cartographer's IMU-based pose extrapolation. **Reference**: - C Wrapper: `ipc/CeresWrapper/CSHARP_WRAPPER_FINAL_EVALUATION.md` section 14 - C# Wrapper: `CeresSharp/README.md` section "Example 3: AutoDiffManifold", `CeresSharp/IMPLEMENTATION_PROGRESS.md` section 8 - Tests: `CeresSharp.Test/EVALUATION.md` section "13. AutoDiffManifold (Test 25)" --- ## ✅ Implementation Checklist ### Phase 1: C Wrapper (`ipc/CeresWrapper/`) ✅ **ĐÃ HOÀN THÀNH** **Status**: ✅ **COMPLETE** - Đã implement và test **Implementation Details**: - ✅ **Header**: `ceres_wrapper.h` lines 340-380 - Callback typedefs: `ceres_autodiff_manifold_plus_t`, `ceres_autodiff_manifold_minus_t` - Functions: `ceres_wrapper_create_autodiff_manifold()`, `ceres_wrapper_free_autodiff_manifold()` - ✅ **Implementation**: `ceres_wrapper.cc` lines 752-904 - `AutoDiffManifoldWrapper` class extends `ceres::Manifold` - Implements `Plus()`, `Minus()`, `PlusJacobian()`, `MinusJacobian()` - Uses numeric differentiation for Jacobians (epsilon = 1e-8) - ✅ **Tests**: `ceres_wrapper_test.c` lines 1325-1378 - Test create/destroy - Test dimensions (ambient_size, tangent_size) - Test Problem integration - Test Euclidean manifold use case **API Signature** (đã có sẵn): ```c // Callbacks typedef int (*ceres_autodiff_manifold_plus_t)( void* user_data, const double* x, const double* delta, double* x_plus_delta); typedef int (*ceres_autodiff_manifold_minus_t)( void* user_data, const double* y, const double* x, double* y_minus_x); // Functions CERES_WRAPPER_EXPORT ceres_manifold_t* ceres_wrapper_create_autodiff_manifold( int ambient_size, int tangent_size, ceres_autodiff_manifold_plus_t plus_callback, ceres_autodiff_manifold_minus_t minus_callback, void* user_data); CERES_WRAPPER_EXPORT void ceres_wrapper_free_autodiff_manifold(ceres_manifold_t* manifold); ``` **No action needed** - C wrapper đã sẵn sàng cho C# integration. --- #### 1.1. Update Header File ✅ **COMPLETE** **File**: `ipc/CeresWrapper/ceres_wrapper.h` lines 340-380 **Status**: ✅ **Đã có sẵn** **No action needed** --- #### 1.2. Implement C++ Wrapper ✅ **COMPLETE** **File**: `ipc/CeresWrapper/ceres_wrapper.cc` lines 752-904 **Status**: ✅ **Đã implement** **Implementation Highlights**: - ✅ `AutoDiffManifoldWrapper` class extends `ceres::Manifold` - ✅ Implements `Plus()` và `Minus()` via C callbacks - ✅ Implements `PlusJacobian()` và `MinusJacobian()` với numeric differentiation (epsilon = 1e-8) - ✅ Error handling với try-catch - ✅ Memory management với `std::unique_ptr` **No action needed** --- #### 1.3. Build & Test C Wrapper ✅ **COMPLETE** **File**: `ipc/CeresWrapper/ceres_wrapper_test.c` lines 1325-1378 **Status**: ✅ **Đã test** **Test Coverage**: - ✅ Create/destroy AutoDiff manifold - ✅ Verify dimensions (ambient_size, tangent_size) - ✅ Test Plus operation (via Problem integration) - ✅ Test Problem integration (SetManifold, HasManifold, GetTangentSize) - ✅ Test với Euclidean manifold use case **No action needed** --- ### Phase 2: C# Wrapper (`srcs/RobotNet10/RobotApp/Communication/CeresSharp/`) ✅ **ĐÃ HOÀN THÀNH** **Status**: ✅ **COMPLETE** - Đã implement và test #### 2.1. Add Native Declarations ✅ **COMPLETE** **File**: `srcs/RobotNet10/RobotApp/Communication/CeresSharp/Native/CeresNative.cs` lines 594-617 **Status**: ✅ **Đã implement** **Implementation Details**: - ✅ `CeresAutoDiffManifoldPlus` delegate (line 594) - ✅ `CeresAutoDiffManifoldMinus` delegate (line 601) - ✅ `ceres_wrapper_create_autodiff_manifold` P/Invoke declaration (line 608) - ✅ `ceres_wrapper_free_autodiff_manifold` P/Invoke declaration (line 616) **Reference C API** (từ `ceres_wrapper.h` lines 349-377): ```c typedef int (*ceres_autodiff_manifold_plus_t)( void* user_data, const double* x, const double* delta, double* x_plus_delta); typedef int (*ceres_autodiff_manifold_minus_t)( void* user_data, const double* y, const double* x, double* y_minus_x); CERES_WRAPPER_EXPORT ceres_manifold_t* ceres_wrapper_create_autodiff_manifold( int ambient_size, int tangent_size, ceres_autodiff_manifold_plus_t plus_callback, ceres_autodiff_manifold_minus_t minus_callback, void* user_data); CERES_WRAPPER_EXPORT void ceres_wrapper_free_autodiff_manifold(ceres_manifold_t* manifold); ``` **Tasks**: - [x] Add `CeresAutoDiffManifoldPlus` delegate ✅ - [x] `[UnmanagedFunctionPointer(CallingConvention.Cdecl)]` ✅ - [x] Parameters: `IntPtr userData`, `IntPtr x`, `IntPtr delta`, `IntPtr xPlusDelta` ✅ - [x] Return: `int` (1 = success, 0 = failure) ✅ - [x] Add `CeresAutoDiffManifoldMinus` delegate ✅ - [x] `[UnmanagedFunctionPointer(CallingConvention.Cdecl)]` ✅ - [x] Parameters: `IntPtr userData`, `IntPtr y`, `IntPtr x`, `IntPtr yMinusX` ✅ - [x] Return: `int` (1 = success, 0 = failure) ✅ - [x] Add P/Invoke declaration `ceres_wrapper_create_autodiff_manifold` ✅ - [x] `[DllImport(LibraryName, CallingConvention = CallingConvention.Cdecl)]` ✅ - [x] Parameters: `int ambientSize`, `int tangentSize`, `CeresAutoDiffManifoldPlus plus`, `CeresAutoDiffManifoldMinus minus`, `IntPtr userData` ✅ - [x] Return: `IntPtr` (manifold handle) ✅ - [x] Add P/Invoke declaration `ceres_wrapper_free_autodiff_manifold` ✅ - [x] `[DllImport(LibraryName, CallingConvention = CallingConvention.Cdecl)]` ✅ - [x] Parameter: `IntPtr manifold` ✅ **Estimated Time**: ✅ **COMPLETE** (1 hour) **Example Code**: ```csharp // Delegates [UnmanagedFunctionPointer(CallingConvention.Cdecl)] internal delegate int CeresAutoDiffManifoldPlus( IntPtr userData, IntPtr x, IntPtr delta, IntPtr xPlusDelta); [UnmanagedFunctionPointer(CallingConvention.Cdecl)] internal delegate int CeresAutoDiffManifoldMinus( IntPtr userData, IntPtr y, IntPtr x, IntPtr yMinusX); // P/Invoke declarations internal static partial class CeresNative { [DllImport(LibraryName, CallingConvention = CallingConvention.Cdecl)] internal static extern IntPtr ceres_wrapper_create_autodiff_manifold( int ambientSize, int tangentSize, CeresAutoDiffManifoldPlus plus, CeresAutoDiffManifoldMinus minus, IntPtr userData); [DllImport(LibraryName, CallingConvention = CallingConvention.Cdecl)] internal static extern void ceres_wrapper_free_autodiff_manifold(IntPtr manifold); } ``` --- #### 2.2. Create AutoDiffManifold Class ✅ **COMPLETE** **File**: `srcs/RobotNet10/RobotApp/Communication/CeresSharp/Core/AutoDiffManifold.cs` **Status**: ✅ **Đã implement** - Complete implementation với 272 lines **Implementation Details**: - ✅ Public delegates: `PlusOperation`, `MinusOperation` - ✅ Constructor với validation - ✅ `CreateHandle()` static method với callback marshalling - ✅ `Dispose()` method với GCHandle cleanup - ✅ XML documentation comments - ✅ Error handling với CeresException **Reference**: - C API: `ceres_wrapper.h` lines 349-377 - C Implementation: `ceres_wrapper.cc` lines 752-904 - Similar pattern: `AutoDiffCostFunction.cs` (callback marshalling) **Tasks**: - [x] Create file structure ✅ - [x] Namespace: `CeresSharp` ✅ - [x] Using statements: `System`, `System.Runtime.InteropServices`, `CeresSharp.Native`, `CeresSharp.Native.SafeHandles` ✅ - [x] Class: `public sealed class AutoDiffManifold : Manifold` ✅ - [x] Define public delegates (for C# users) ✅ - [x] `PlusOperation` delegate: `(double[] x, double[] delta, double[] xPlusDelta) => bool` ✅ (line 56) - [x] `MinusOperation` delegate: `(double[] y, double[] x, double[] yMinusX) => bool` ✅ (line 65) - [x] Implement constructor ✅ - [x] Parameters: `int ambientSize`, `int tangentSize`, `PlusOperation plus`, `MinusOperation minus` ✅ (lines 77-81) - [x] Validate parameters (ambientSize > 0, tangentSize > 0, tangentSize <= ambientSize) ✅ (lines 108-115) - [x] Validate callbacks (not null) ✅ (lines 116-119) - [x] Call `CreateHandle()` static method ✅ (line 82) - [x] Store `GCHandle` for cleanup ✅ (line 86) - [x] Implement `CreateHandle()` static method ✅ - [x] Create `CallbackWrapper` object với callbacks và sizes ✅ (lines 125-130) - [x] Pin wrapper với `GCHandle.Alloc(wrapper)` ✅ (line 133) - [x] Create native callbacks (marshal C# delegates → C callbacks) ✅ - [x] `CeresAutoDiffManifoldPlus`: Marshal arrays, call C# delegate, marshal result ✅ (lines 136-160) - [x] `CeresAutoDiffManifoldMinus`: Marshal arrays, call C# delegate, marshal result ✅ (lines 163-187) - [x] Pin native callbacks với `GCHandle.Alloc()` ✅ (lines 190-191) - [x] Call `CeresNative.ceres_wrapper_create_autodiff_manifold()` ✅ (lines 194-199) - [x] Error handling: Check for `IntPtr.Zero`, throw `CeresException` on failure ✅ (lines 201-204) - [x] Return `ManifoldHandle.Create(handle)` ✅ (line 206) - [x] Implement `Dispose()` method ✅ - [x] Free `GCHandle` cho wrapper ✅ (lines 214-217) - [x] Free `GCHandle` cho native callbacks (stored in wrapper) ✅ (lines 218-223) - [x] Call base `Dispose()` (frees native handle) ✅ (line 225) - [x] Add XML documentation comments ✅ - [x] Class summary với use case examples ✅ (lines 8-41) - [x] Method summaries ✅ - [x] Parameter descriptions ✅ - [x] Return value descriptions ✅ - [x] Example code snippets ✅ (lines 24-39) **Estimated Time**: ✅ **COMPLETE** (3-4 hours) **Key Implementation Details**: - **Callback marshalling**: Similar to `AutoDiffCostFunction` pattern - Marshal `IntPtr` → `double[]` arrays - Call C# delegate - Marshal result arrays back to `IntPtr` - **Memory management**: - Pin `GCHandle` cho wrapper object - Pin `GCHandle` cho native callbacks - Cleanup trong `Dispose()` (not finalizer) - **Error handling**: - Validate parameters trong constructor - Throw `CeresException` on failure - Handle `IntPtr.Zero` return from native - **Ownership**: - Problem owns manifold when set via `SetManifold()` - But we need to cleanup callbacks (GCHandles) when AutoDiffManifold is disposed - Similar pattern to `AutoDiffCostFunction` **Example Structure** (reference from AutoDiffCostFunction): ```csharp public sealed class AutoDiffManifold : Manifold { private readonly GCHandle _wrapperHandle; private readonly int _ambientSize; private readonly int _tangentSize; public delegate bool PlusOperation(double[] x, double[] delta, double[] xPlusDelta); public delegate bool MinusOperation(double[] y, double[] x, double[] yMinusX); public AutoDiffManifold( int ambientSize, int tangentSize, PlusOperation plus, MinusOperation minus) : base(CreateHandle(ambientSize, tangentSize, plus, minus, out var wrapperHandle)) { _ambientSize = ambientSize; _tangentSize = tangentSize; _wrapperHandle = wrapperHandle; } private static ManifoldHandle CreateHandle(...) { // Similar to AutoDiffCostFunction.CreateHandle() // 1. Create CallbackWrapper // 2. Pin với GCHandle // 3. Create native callbacks // 4. Pin native callbacks // 5. Call ceres_wrapper_create_autodiff_manifold() // 6. Return ManifoldHandle } protected override void Dispose(bool disposing) { if (disposing && _wrapperHandle.IsAllocated) { base.Dispose(disposing); _wrapperHandle.Free(); // Free native callback handles from wrapper } } private class CallbackWrapper { public PlusOperation Plus = null!; public MinusOperation Minus = null!; public int AmbientSize; public int TangentSize; public GCHandle[]? NativeCallbackHandles; } } ``` --- #### 2.3. Add Tests ✅ **COMPLETE** **File**: `srcs/RobotNet10/RobotApp/Communication/CeresSharp.Test/AutoDiffManifoldTests.cs` **Status**: ✅ **Đã implement** - 10 comprehensive tests **Implementation Details**: - ✅ Test file structure với `[TestFixture]` class - ✅ Basic creation test: `AutoDiffManifold_ShouldCreate()` - ✅ Plus operation test: `AutoDiffManifold_Plus_ShouldWork()` - ✅ Minus operation test: `AutoDiffManifold_Minus_ShouldWork()` - ✅ Problem integration test: `AutoDiffManifold_WithProblem_ShouldWork()` - ✅ Validation tests: `AutoDiffManifold_InvalidSizes_ShouldThrow()` (3 edge cases) - ✅ Null checks: `AutoDiffManifold_NullCallbacks_ShouldThrow()` (2 tests) - ✅ Memory management: `AutoDiffManifold_Dispose_ShouldNotCrash()` - ✅ Using pattern: `AutoDiffManifold_UsingStatement_ShouldWork()` - ✅ Different sizes: `AutoDiffManifold_DifferentSizes_ShouldWork()` - ✅ Cost function integration: `AutoDiffManifold_WithCostFunction_ShouldWork()` **Test Results**: ✅ **All 10 tests pass** **Estimated Time**: ✅ **COMPLETE** (1-2 hours) --- #### 2.4. Update Documentation ✅ **COMPLETE** **Files Updated**: 1. **README.md** ✅ - [x] Add AutoDiffManifold vào "Quick Reference" table ✅ (line 27) - [x] Add AutoDiffManifold vào "Available Manifolds" section ✅ (line 207) - [x] Add conversion example từ AutoDiffLocalParameterization ✅ (lines 495-578) - [x] Add usage example cho ConstantYawQuaternion ✅ (lines 549-572) 2. **IMPLEMENTATION_PROGRESS.md** ✅ - [x] Mark AutoDiffManifold as implemented ✅ (lines 290-301) - [x] Update coverage statistics ✅ (line 554: "7 types (6 standard + AutoDiffManifold)") 3. **EVALUATION.md** ✅ - [x] Add AutoDiffManifold test coverage section ✅ (lines 357-378) - [x] Update test statistics ✅ (line 472: "AutoDiffManifold Tests: 10 tests") 4. **CERES_READINESS_EVALUATION.md** (CartographerSharp) - [x] Update status từ "chưa có" → "có sẵn" ✅ **Estimated Time**: ✅ **COMPLETE** (1 hour) --- ## 📊 Summary ### Total Estimated Effort | Phase | Tasks | Time | Status | |-------|-------|------|--------| | **Phase 1: C Wrapper** | Header + Implementation + Testing | 4-6 hours | ✅ **COMPLETE** | | **Phase 2: C# Wrapper** | Native + Class + Tests + Docs | 6-8 hours | ✅ **COMPLETE** | | **Total** | | **10-14 hours** | ✅ **COMPLETE** | | ### Priority - **Current**: ⭐⭐⭐ (Medium) - Có workaround (custom Manifold implementation) - Không block Cartographer conversion - Nhưng nên implement để đầy đủ và dễ dùng hơn ### Recommended Timeline 1. ✅ **Phase 1** (C Wrapper): **ĐÃ HOÀN THÀNH** - C wrapper đã sẵn sàng 2. ✅ **Phase 2** (C# Wrapper): **ĐÃ HOÀN THÀNH** - C# wrapper đã implement và test 3. ✅ **Testing**: **ĐÃ HOÀN THÀNH** - 10 comprehensive tests pass, sẵn sàng cho Cartographer integration 4. ✅ **Documentation**: **ĐÃ HOÀN THÀNH** - README, IMPLEMENTATION_PROGRESS, EVALUATION đã cập nhật 5. ⏳ **Cartographer Integration**: Sẵn sàng cho real Cartographer use cases (ConstantYawQuaternion) 6. ⏳ **Optimization**: PlusJacobian và MinusJacobian đã dùng numeric diff (đủ tốt), có thể optimize sau nếu cần --- ## 🔗 Related Files ### C Wrapper ✅ **COMPLETE** - ✅ `ipc/CeresWrapper/ceres_wrapper.h` lines 340-380 - Header declarations - ✅ `ipc/CeresWrapper/ceres_wrapper.cc` lines 752-904 - Implementation - ✅ `ipc/CeresWrapper/ceres_wrapper_test.c` lines 1325-1378 - Tests - ✅ `ipc/CeresWrapper/CSHARP_WRAPPER_FINAL_EVALUATION.md` - Documentation ### C# Wrapper - `srcs/RobotNet10/RobotApp/Communication/CeresSharp/Native/CeresNative.cs` - P/Invoke declarations - `srcs/RobotNet10/RobotApp/Communication/CeresSharp/Core/AutoDiffManifold.cs` - Main class (NEW) - `srcs/RobotNet10/RobotApp/Communication/CeresSharp/Core/Manifold.cs` - Base class - `srcs/RobotNet10/RobotApp/Communication/CeresSharp.Test/AutoDiffManifoldTests.cs` - Tests (NEW) ### Documentation - `srcs/RobotNet10/RobotApp/Communication/CeresSharp/README.md` - User guide - `srcs/RobotNet10/RobotApp/Communication/CeresSharp/IMPLEMENTATION_PROGRESS.md` - Progress tracking - `srcs/RobotNet10/RobotApp/Communication/CartographerSharp/CERES_READINESS_EVALUATION.md` - Evaluation doc --- ## 📝 Notes ### Implementation Considerations 1. **Memory Management**: - Problem owns manifold when set via `SetManifold()` - But we need to cleanup callbacks (GCHandles) when AutoDiffManifold is disposed - Similar pattern to `AutoDiffCostFunction` 2. **Jacobian Computation**: - ✅ **Đã implement trong C wrapper** với numeric differentiation (epsilon = 1e-8) - ✅ `PlusJacobian`: Finite difference w.r.t. `delta` parameter - ✅ `MinusJacobian`: Finite difference w.r.t. first argument `y` - ✅ **Không cần implement trong C#** - C wrapper đã handle 3. **Error Handling**: - ✅ **C wrapper**: Đã có error handling (try-catch, NULL checks) - [ ] **C# wrapper**: Validate parameters trong constructor - [ ] **C# wrapper**: Throw `CeresException` on failure - [ ] **C# wrapper**: Handle `IntPtr.Zero` return from native 4. **Testing Strategy**: - ✅ **C wrapper**: Đã test với Euclidean manifold - [ ] **C# wrapper**: Test với simple manifolds (Euclidean) - similar to C tests - [ ] **C# wrapper**: Test với ConstantYawQuaternion (Cartographer use case) - [ ] **C# wrapper**: Verify memory management (GCHandle cleanup) - [ ] **C# wrapper**: Test với Problem integration --- --- ## 📝 Implementation Notes ### C Wrapper Implementation Details ✅ **COMPLETE** **File**: `ipc/CeresWrapper/ceres_wrapper.cc` lines 752-904 **Key Features**: - ✅ `AutoDiffManifoldWrapper` class extends `ceres::Manifold` - ✅ `Plus()` và `Minus()` call C callbacks directly - ✅ `PlusJacobian()`: Numeric differentiation w.r.t. `delta` (epsilon = 1e-8) - ✅ `MinusJacobian()`: Numeric differentiation w.r.t. first argument `y` (epsilon = 1e-8) - ✅ Error handling với try-catch - ✅ Memory management với `std::unique_ptr` và custom deleter **Jacobian Computation** (đã implement trong C wrapper): - **PlusJacobian**: Finite difference `(Plus(x, perturbed_delta) - Plus(x, 0)) / epsilon` - Perturb từng element của `delta` - Compute finite difference cho mỗi column - **MinusJacobian**: Finite difference `(Minus(perturbed_y, x) - Minus(x, x)) / epsilon` - Perturb từng element của `y` (first argument) - Compute finite difference cho mỗi column - Epsilon: `1e-8` (sufficient for most use cases) **API Signature** (từ `ceres_wrapper.h`): ```c // Callback types typedef int (*ceres_autodiff_manifold_plus_t)( void* user_data, const double* x, // ambient_size elements const double* delta, // tangent_size elements double* x_plus_delta); // ambient_size elements (output) typedef int (*ceres_autodiff_manifold_minus_t)( void* user_data, const double* y, // ambient_size elements const double* x, // ambient_size elements double* y_minus_x); // tangent_size elements (output) // Functions CERES_WRAPPER_EXPORT ceres_manifold_t* ceres_wrapper_create_autodiff_manifold( int ambient_size, int tangent_size, ceres_autodiff_manifold_plus_t plus_callback, ceres_autodiff_manifold_minus_t minus_callback, void* user_data); CERES_WRAPPER_EXPORT void ceres_wrapper_free_autodiff_manifold(ceres_manifold_t* manifold); ``` **Test Coverage** (từ `ceres_wrapper_test.c`): - ✅ Create/destroy AutoDiff manifold - ✅ Verify dimensions (ambient_size, tangent_size) - ✅ Test Plus operation (via Problem integration) - ✅ Test Problem integration (SetManifold, HasManifold, GetTangentSize) - ✅ Test với Euclidean manifold use case ### C# Wrapper Implementation Pattern **Similar to AutoDiffCostFunction**: - Use `GCHandle` để pin callbacks - Marshal C# delegates → C callbacks - Handle memory cleanup trong `Dispose()` - Problem owns manifold, nhưng cần cleanup callbacks **Reference Implementation**: - ✅ `CeresSharp/Core/AutoDiffCostFunction.cs` - Pattern cho callback marshalling - ✅ `CeresSharp/Core/Manifold.cs` - Base class structure - ✅ `CeresSharp/Core/ProductManifold.cs` - Example của custom manifold với callbacks **Key Differences từ AutoDiffCostFunction**: - AutoDiffCostFunction: `double[][] parameters` → `double[] residuals` - AutoDiffManifold: `double[] x, double[] delta` → `double[] xPlusDelta` (Plus) - AutoDiffManifold: `double[] y, double[] x` → `double[] yMinusX` (Minus) - Simpler array marshalling (single arrays, not jagged arrays) **Memory Management Pattern**: ```csharp // 1. Create CallbackWrapper object var wrapper = new CallbackWrapper { Plus = plus, Minus = minus, ... }; // 2. Pin wrapper var wrapperHandle = GCHandle.Alloc(wrapper); // 3. Create native callbacks (marshal C# → C) var plusCallback = new CeresNative.CeresAutoDiffManifoldPlus((userData, x, delta, xPlusDelta) => { var handle = GCHandle.FromIntPtr(userData); var wrapperObj = (CallbackWrapper)handle.Target!; // Marshal arrays var xArray = new double[wrapperObj.AmbientSize]; var deltaArray = new double[wrapperObj.TangentSize]; var xPlusDeltaArray = new double[wrapperObj.AmbientSize]; Marshal.Copy(x, xArray, 0, wrapperObj.AmbientSize); Marshal.Copy(delta, deltaArray, 0, wrapperObj.TangentSize); // Call C# delegate var success = wrapperObj.Plus(xArray, deltaArray, xPlusDeltaArray); // Marshal result back if (success) Marshal.Copy(xPlusDeltaArray, 0, xPlusDelta, wrapperObj.AmbientSize); return success ? 1 : 0; }); // 4. Pin native callbacks var plusHandle = GCHandle.Alloc(plusCallback); var minusHandle = GCHandle.Alloc(minusCallback); // 5. Call native function var handle = CeresNative.ceres_wrapper_create_autodiff_manifold(...); // 6. Store handles for cleanup wrapper.NativeCallbackHandles = new[] { plusHandle, minusHandle }; ``` --- --- ## 🔍 C Wrapper API Reference ### Header Declarations (`ceres_wrapper.h` lines 340-380) ```c // ============================================================================ // AutoDiff Manifold // ============================================================================ /* Callback for AutoDiff manifold Plus operation */ /* x: point on manifold (ambient_size elements) */ /* delta: tangent vector (tangent_size elements) */ /* x_plus_delta: output point on manifold (ambient_size elements) */ /* Returns 1 on success, 0 on failure */ typedef int (*ceres_autodiff_manifold_plus_t)( void* user_data, const double* x, const double* delta, double* x_plus_delta); /* Callback for AutoDiff manifold Minus operation */ /* y: point on manifold (ambient_size elements) */ /* x: point on manifold (ambient_size elements) */ /* y_minus_x: output tangent vector (tangent_size elements) */ /* Returns 1 on success, 0 on failure */ typedef int (*ceres_autodiff_manifold_minus_t)( void* user_data, const double* y, const double* x, double* y_minus_x); /* Create AutoDiff manifold */ /* ambient_size: dimension of ambient space */ /* tangent_size: dimension of tangent space */ /* plus_callback: callback for Plus operation */ /* minus_callback: callback for Minus operation */ /* user_data: user data passed to callbacks */ CERES_WRAPPER_EXPORT ceres_manifold_t* ceres_wrapper_create_autodiff_manifold( int ambient_size, int tangent_size, ceres_autodiff_manifold_plus_t plus_callback, ceres_autodiff_manifold_minus_t minus_callback, void* user_data); /* Free AutoDiff manifold */ CERES_WRAPPER_EXPORT void ceres_wrapper_free_autodiff_manifold(ceres_manifold_t* manifold); ``` ### Test Example (`ceres_wrapper_test.c` lines 1325-1378) **Euclidean Manifold Test**: ```c // Plus: x + delta int autodiff_manifold_plus_euclidean(void* user_data, const double* x, const double* delta, double* x_plus_delta) { int size = *(int*)user_data; for (int i = 0; i < size; i++) { x_plus_delta[i] = x[i] + delta[i]; } return 1; } // Minus: y - x int autodiff_manifold_minus_euclidean(void* user_data, const double* y, const double* x, double* y_minus_x) { int size = *(int*)user_data; for (int i = 0; i < size; i++) { y_minus_x[i] = y[i] - x[i]; } return 1; } // Usage ceres_manifold_t* manifold = ceres_wrapper_create_autodiff_manifold( 3, 3, // ambient_size=3, tangent_size=3 autodiff_manifold_plus_euclidean, autodiff_manifold_minus_euclidean, &ambient_size); ``` --- **Last Updated**: 2024-12-19 **Status**: - ✅ **Phase 1 (C Wrapper)**: **COMPLETE** - Đã implement và test - ✅ **Phase 2 (C# Wrapper)**: **COMPLETE** - Đã implement và test **Next Steps**: ✅ **READY FOR CARTOGRAPHER INTEGRATION** - AutoDiffManifold đã sẵn sàng cho ConstantYawQuaternion use case