geosets_rs/cddlib_rs/
mod.rs1mod cdd_bindings;
2
3use crate::sets::errors::SetOperationError;
4use cdd_bindings::*;
5use ndarray::{Array1, Array2};
6use once_cell::sync::Lazy;
7use std::os::raw::c_long;
8use std::sync::Mutex;
9
10static CDD_MUTEX: Lazy<Mutex<()>> = Lazy::new(|| Mutex::new(()));
11
12pub fn compute_polytope_vertices(
17 a: &Array2<f64>,
18 b: &Array1<f64>,
19) -> Result<Array2<f64>, SetOperationError> {
20 if a.nrows() != b.len() {
22 return Err(SetOperationError::DimensionMismatch {
23 expected: a.nrows(),
24 got: b.len(),
25 });
26 }
27
28 let _guard = CDD_MUTEX.lock().unwrap();
31
32 unsafe {
33 dd_set_global_constants();
34 let result = compute_polytope_vertices_inner(a, b);
35 dd_free_global_constants();
36 result
37 }
38}
39
40unsafe fn compute_polytope_vertices_inner(
41 a: &Array2<f64>,
42 b: &Array1<f64>,
43) -> Result<Array2<f64>, SetOperationError> {
44 let m = a.nrows() as c_long;
45 let n = a.ncols() as c_long;
46 unsafe {
49 let mat = dd_CreateMatrix(m, n + 1);
50 if mat.is_null() {
51 dd_free_global_constants();
52 return Err(SetOperationError::DataConversionError {
53 source: "Failed to create cddlib matrix".into(),
54 });
55 }
56
57 (*mat).representation = dd_RepresentationType::dd_Inequality;
58
59 for i in 0..m {
60 let i_usize = i as usize;
61 let i_isize = i as isize;
62
63 let row_ptr = (*mat).matrix.offset(i_isize);
65 let rhs_ptr = (*row_ptr).offset(0);
66 (*rhs_ptr)[0] = b[i_usize];
67
68 for j in 0..n {
70 let j_usize = j as usize;
71 let j_isize = (j + 1) as isize;
72 let coeff_ptr = (*row_ptr).offset(j_isize);
73 (*coeff_ptr)[0] = -a[[i_usize, j_usize]];
74 }
75 }
76
77 let mut err: dd_ErrorType = dd_ErrorType::dd_NoError;
79 let poly = dd_DDMatrix2Poly(mat, &mut err);
80 if err != dd_ErrorType::dd_NoError || poly.is_null() {
81 dd_FreeMatrix(mat);
82 dd_free_global_constants();
83 return Err(SetOperationError::InfeasibleOptimization {
84 source: format!("cddlib error: {:?}", err).into(),
85 });
86 }
87
88 let gens = dd_CopyGenerators(poly);
90 if gens.is_null() {
91 dd_FreePolyhedra(poly);
92 dd_FreeMatrix(mat);
93 dd_free_global_constants();
94 return Err(SetOperationError::DataConversionError {
95 source: "Failed to extract generators from polyhedron".into(),
96 });
97 }
98
99 let mut vertices_data = Vec::new();
100 let mut vertex_count = 0;
101
102 for i in 0..(*gens).rowsize {
103 let i_isize = i as isize;
104 let gen_row_ptr = (*gens).matrix.offset(i_isize);
105 let kind_ptr = (*gen_row_ptr).offset(0);
106 let kind = (*kind_ptr)[0];
107
108 if (kind - 1.0).abs() < 1e-9 {
109 for j in 1..=n {
111 let j_isize = j as isize;
112 let vertex_ptr = (*gen_row_ptr).offset(j_isize);
113 vertices_data.push((*vertex_ptr)[0]);
114 }
115 vertex_count += 1;
116 }
117 }
118
119 dd_FreePolyhedra(poly);
121 dd_FreeMatrix(mat);
122 dd_FreeMatrix(gens);
123 dd_free_global_constants();
124
125 if vertex_count == 0 {
127 Ok(Array2::zeros((0, n as usize)))
128 } else {
129 Array2::from_shape_vec((vertex_count, n as usize), vertices_data).map_err(|e| {
130 SetOperationError::DataConversionError {
131 source: format!("Failed to create Array2 from vertices data: {}", e).into(),
132 }
133 })
134 }
135 }
136}