cddlib_rs/
lib.rs

1//! Safe, idiomatic Rust bindings on top of the raw `cddlib-sys` FFI.
2//!
3//! This crate owns the unsafe glue for working with cddlib matrices, polyhedra,
4//! and LP solutions. Callers should be able to use these types without touching
5//! raw pointers or the `cddlib-sys` bindings directly.
6
7use std::convert::TryFrom;
8use std::ffi::c_void;
9use std::marker::PhantomData;
10use std::mem;
11use std::os::raw::c_long;
12use std::ptr::{self, NonNull};
13use std::rc::Rc;
14use std::sync::Once;
15
16#[cfg(any(feature = "gmp", feature = "gmprational"))]
17use std::mem::MaybeUninit;
18
19use thiserror::Error;
20
21pub use cddlib_sys as sys;
22
23#[cfg(all(
24    not(feature = "gmprational"),
25    not(feature = "gmp"),
26    not(feature = "f64")
27))]
28compile_error!("cddlib-rs requires at least one backend feature: f64, gmp, or gmprational");
29
30#[cfg(feature = "gmp")]
31pub struct CddFloat {
32    inner: sys::gmpfloat::mytype,
33}
34
35#[cfg(feature = "gmprational")]
36pub struct CddRational {
37    inner: sys::gmprational::mytype,
38}
39
40#[cfg(feature = "f64")]
41pub type DefaultNumber = f64;
42
43#[cfg(all(not(feature = "f64"), feature = "gmprational"))]
44pub type DefaultNumber = CddRational;
45
46#[cfg(all(not(feature = "f64"), not(feature = "gmprational"), feature = "gmp"))]
47pub type DefaultNumber = CddFloat;
48
49mod sealed {
50    pub trait Sealed {}
51}
52
53pub trait CddNumber: sealed::Sealed + 'static {
54    const MYTYPE_SIZE: usize;
55    const DEFAULT_NUMBER_TYPE: NumberType;
56
57    fn ensure_initialized();
58
59    #[doc(hidden)]
60    fn dd_no_error() -> u32;
61
62    #[doc(hidden)]
63    unsafe fn dd_create_matrix(rows: c_long, cols: c_long) -> *mut c_void;
64
65    #[doc(hidden)]
66    unsafe fn dd_copy_matrix(matrix: *mut c_void) -> *mut c_void;
67
68    #[doc(hidden)]
69    unsafe fn dd_free_matrix(matrix: *mut c_void);
70
71    #[doc(hidden)]
72    unsafe fn dd_matrix_append_to(dst: *mut *mut c_void, src: *mut c_void) -> i32;
73
74    #[doc(hidden)]
75    unsafe fn dd_append_matrix(a: *mut c_void, b: *mut c_void) -> *mut c_void;
76
77    #[doc(hidden)]
78    unsafe fn dd_matrix_row_remove(matrix: *mut *mut c_void, row: c_long) -> i32;
79
80    #[doc(hidden)]
81    unsafe fn dd_initialize_arow(cols: c_long, out: *mut *mut c_void);
82
83    #[doc(hidden)]
84    unsafe fn dd_free_arow(cols: c_long, arow: *mut c_void);
85
86    #[doc(hidden)]
87    unsafe fn dd_redundant(
88        matrix: *mut c_void,
89        row: c_long,
90        cert: *mut c_void,
91        err: *mut u32,
92    ) -> i32;
93
94    #[doc(hidden)]
95    unsafe fn dd_redundant_rows(matrix: *mut c_void, err: *mut u32) -> *mut libc::c_ulong;
96
97    #[doc(hidden)]
98    unsafe fn dd_matrix_canonicalize(
99        matrix: *mut *mut c_void,
100        impl_lin: *mut *mut libc::c_ulong,
101        redset: *mut *mut libc::c_ulong,
102        newpos: *mut *mut c_long,
103        err: *mut u32,
104    ) -> i32;
105
106    #[doc(hidden)]
107    unsafe fn set_groundsize(set: *mut libc::c_ulong) -> c_long;
108
109    #[doc(hidden)]
110    unsafe fn set_member(elem: c_long, set: *mut libc::c_ulong) -> i32;
111
112    #[doc(hidden)]
113    unsafe fn set_free(set: *mut libc::c_ulong);
114
115    #[doc(hidden)]
116    unsafe fn dd_matrix2poly(matrix: *mut c_void, err: *mut u32) -> *mut c_void;
117
118    #[doc(hidden)]
119    unsafe fn dd_free_polyhedra(poly: *mut c_void);
120
121    #[doc(hidden)]
122    unsafe fn dd_copy_inequalities(poly: *mut c_void) -> *mut c_void;
123
124    #[doc(hidden)]
125    unsafe fn dd_copy_generators(poly: *mut c_void) -> *mut c_void;
126
127    #[doc(hidden)]
128    unsafe fn dd_copy_adjacency(poly: *mut c_void) -> *mut c_void;
129
130    #[doc(hidden)]
131    unsafe fn dd_copy_input_adjacency(poly: *mut c_void) -> *mut c_void;
132
133    #[doc(hidden)]
134    unsafe fn dd_copy_incidence(poly: *mut c_void) -> *mut c_void;
135
136    #[doc(hidden)]
137    unsafe fn dd_copy_input_incidence(poly: *mut c_void) -> *mut c_void;
138
139    #[doc(hidden)]
140    unsafe fn dd_append_matrix2poly(poly: *mut *mut c_void, rows: *mut c_void) -> i32;
141
142    #[doc(hidden)]
143    unsafe fn dd_free_set_family(family: *mut c_void);
144
145    #[doc(hidden)]
146    unsafe fn dd_matrix2lp(matrix: *mut c_void, err: *mut u32) -> *mut c_void;
147
148    #[doc(hidden)]
149    unsafe fn dd_free_lp_data(lp: *mut c_void);
150
151    #[doc(hidden)]
152    unsafe fn dd_lp_solve_dual_simplex(lp: *mut c_void, err: *mut u32) -> i32;
153
154    #[doc(hidden)]
155    unsafe fn lp_status_raw(lp: *mut c_void) -> u32;
156
157    #[doc(hidden)]
158    unsafe fn dd_copy_lp_solution(lp: *mut c_void) -> *mut c_void;
159
160    #[doc(hidden)]
161    unsafe fn dd_free_lp_solution(sol: *mut c_void);
162
163    #[doc(hidden)]
164    unsafe fn lp_solution_optvalue_ptr(sol: *mut c_void) -> *const c_void;
165
166    #[doc(hidden)]
167    unsafe fn write_mytype_real(target: *mut c_void, value: f64);
168
169    #[doc(hidden)]
170    unsafe fn write_mytype_int(target: *mut c_void, value: c_long);
171
172    #[doc(hidden)]
173    unsafe fn read_mytype_real(source: *const c_void) -> f64;
174
175    #[doc(hidden)]
176    unsafe fn write_mytype(target: *mut c_void, value: &Self);
177
178    #[doc(hidden)]
179    unsafe fn read_mytype(source: *const c_void) -> Self;
180}
181
182#[cfg(feature = "f64")]
183impl sealed::Sealed for f64 {}
184
185#[cfg(feature = "f64")]
186impl CddNumber for f64 {
187    const MYTYPE_SIZE: usize = mem::size_of::<sys::f64::mytype>();
188    const DEFAULT_NUMBER_TYPE: NumberType = NumberType::Real;
189
190    fn ensure_initialized() {
191        static INIT: Once = Once::new();
192        INIT.call_once(|| unsafe {
193            sys::f64::dd_set_global_constants();
194        });
195    }
196
197    fn dd_no_error() -> u32 {
198        sys::f64::dd_ErrorType_dd_NoError
199    }
200
201    unsafe fn dd_create_matrix(rows: c_long, cols: c_long) -> *mut c_void {
202        unsafe { sys::f64::dd_CreateMatrix(rows, cols).cast() }
203    }
204
205    unsafe fn dd_copy_matrix(matrix: *mut c_void) -> *mut c_void {
206        unsafe { sys::f64::dd_CopyMatrix(matrix.cast()).cast() }
207    }
208
209    unsafe fn dd_free_matrix(matrix: *mut c_void) {
210        unsafe {
211            sys::f64::dd_FreeMatrix(matrix.cast());
212        }
213    }
214
215    unsafe fn dd_matrix_append_to(dst: *mut *mut c_void, src: *mut c_void) -> i32 {
216        unsafe { sys::f64::dd_MatrixAppendTo(dst.cast(), src.cast()) }
217    }
218
219    unsafe fn dd_append_matrix(a: *mut c_void, b: *mut c_void) -> *mut c_void {
220        unsafe { sys::f64::dd_AppendMatrix(a.cast(), b.cast()).cast() }
221    }
222
223    unsafe fn dd_matrix_row_remove(matrix: *mut *mut c_void, row: c_long) -> i32 {
224        unsafe { sys::f64::dd_MatrixRowRemove(matrix.cast(), row) }
225    }
226
227    unsafe fn dd_initialize_arow(cols: c_long, out: *mut *mut c_void) {
228        unsafe {
229            sys::f64::dd_InitializeArow(cols, out.cast());
230        }
231    }
232
233    unsafe fn dd_free_arow(cols: c_long, arow: *mut c_void) {
234        unsafe {
235            sys::f64::dd_FreeArow(cols, arow.cast());
236        }
237    }
238
239    unsafe fn dd_redundant(
240        matrix: *mut c_void,
241        row: c_long,
242        cert: *mut c_void,
243        err: *mut u32,
244    ) -> i32 {
245        unsafe { sys::f64::dd_Redundant(matrix.cast(), row, cert.cast(), err.cast()) }
246    }
247
248    unsafe fn dd_redundant_rows(matrix: *mut c_void, err: *mut u32) -> *mut libc::c_ulong {
249        unsafe { sys::f64::dd_RedundantRows(matrix.cast(), err.cast()).cast() }
250    }
251
252    unsafe fn dd_matrix_canonicalize(
253        matrix: *mut *mut c_void,
254        impl_lin: *mut *mut libc::c_ulong,
255        redset: *mut *mut libc::c_ulong,
256        newpos: *mut *mut c_long,
257        err: *mut u32,
258    ) -> i32 {
259        unsafe {
260            sys::f64::dd_MatrixCanonicalize(
261                matrix.cast(),
262                impl_lin.cast(),
263                redset.cast(),
264                newpos.cast(),
265                err.cast(),
266            )
267        }
268    }
269
270    unsafe fn set_groundsize(set: *mut libc::c_ulong) -> c_long {
271        unsafe { sys::f64::set_groundsize(set.cast()) }
272    }
273
274    unsafe fn set_member(elem: c_long, set: *mut libc::c_ulong) -> i32 {
275        unsafe { sys::f64::set_member(elem, set.cast()) }
276    }
277
278    unsafe fn set_free(set: *mut libc::c_ulong) {
279        unsafe {
280            sys::f64::set_free(set.cast());
281        }
282    }
283
284    unsafe fn dd_matrix2poly(matrix: *mut c_void, err: *mut u32) -> *mut c_void {
285        unsafe { sys::f64::dd_DDMatrix2Poly(matrix.cast(), err.cast()).cast() }
286    }
287
288    unsafe fn dd_free_polyhedra(poly: *mut c_void) {
289        unsafe {
290            sys::f64::dd_FreePolyhedra(poly.cast());
291        }
292    }
293
294    unsafe fn dd_copy_inequalities(poly: *mut c_void) -> *mut c_void {
295        unsafe { sys::f64::dd_CopyInequalities(poly.cast()).cast() }
296    }
297
298    unsafe fn dd_copy_generators(poly: *mut c_void) -> *mut c_void {
299        unsafe { sys::f64::dd_CopyGenerators(poly.cast()).cast() }
300    }
301
302    unsafe fn dd_copy_adjacency(poly: *mut c_void) -> *mut c_void {
303        unsafe { sys::f64::dd_CopyAdjacency(poly.cast()).cast() }
304    }
305
306    unsafe fn dd_copy_input_adjacency(poly: *mut c_void) -> *mut c_void {
307        unsafe { sys::f64::dd_CopyInputAdjacency(poly.cast()).cast() }
308    }
309
310    unsafe fn dd_copy_incidence(poly: *mut c_void) -> *mut c_void {
311        unsafe { sys::f64::dd_CopyIncidence(poly.cast()).cast() }
312    }
313
314    unsafe fn dd_copy_input_incidence(poly: *mut c_void) -> *mut c_void {
315        unsafe { sys::f64::dd_CopyInputIncidence(poly.cast()).cast() }
316    }
317
318    unsafe fn dd_append_matrix2poly(poly: *mut *mut c_void, rows: *mut c_void) -> i32 {
319        unsafe { sys::f64::dd_AppendMatrix2Poly(poly.cast(), rows.cast()) }
320    }
321
322    unsafe fn dd_free_set_family(family: *mut c_void) {
323        unsafe {
324            sys::f64::dd_FreeSetFamily(family.cast());
325        }
326    }
327
328    unsafe fn dd_matrix2lp(matrix: *mut c_void, err: *mut u32) -> *mut c_void {
329        unsafe { sys::f64::dd_Matrix2LP(matrix.cast(), err.cast()).cast() }
330    }
331
332    unsafe fn dd_free_lp_data(lp: *mut c_void) {
333        unsafe {
334            sys::f64::dd_FreeLPData(lp.cast());
335        }
336    }
337
338    unsafe fn dd_lp_solve_dual_simplex(lp: *mut c_void, err: *mut u32) -> i32 {
339        unsafe {
340            sys::f64::dd_LPSolve(
341                lp.cast(),
342                sys::f64::dd_LPSolverType_dd_DualSimplex,
343                err.cast(),
344            )
345        }
346    }
347
348    unsafe fn lp_status_raw(lp: *mut c_void) -> u32 {
349        unsafe { (*lp.cast::<sys::f64::dd_lpdata>()).LPS }
350    }
351
352    unsafe fn dd_copy_lp_solution(lp: *mut c_void) -> *mut c_void {
353        unsafe { sys::f64::dd_CopyLPSolution(lp.cast()).cast() }
354    }
355
356    unsafe fn dd_free_lp_solution(sol: *mut c_void) {
357        unsafe {
358            sys::f64::dd_FreeLPSolution(sol.cast());
359        }
360    }
361
362    unsafe fn lp_solution_optvalue_ptr(sol: *mut c_void) -> *const c_void {
363        unsafe {
364            let sol = sol.cast::<sys::f64::dd_lpsolution>();
365            (&(*sol).optvalue as *const sys::f64::mytype).cast()
366        }
367    }
368
369    unsafe fn write_mytype_real(target: *mut c_void, value: f64) {
370        unsafe {
371            (*target.cast::<sys::f64::mytype>())[0] = value;
372        }
373    }
374
375    unsafe fn write_mytype_int(target: *mut c_void, value: c_long) {
376        unsafe {
377            (*target.cast::<sys::f64::mytype>())[0] = value as f64;
378        }
379    }
380
381    unsafe fn read_mytype_real(source: *const c_void) -> f64 {
382        unsafe { (*source.cast::<sys::f64::mytype>())[0] }
383    }
384
385    unsafe fn write_mytype(target: *mut c_void, value: &Self) {
386        unsafe {
387            Self::write_mytype_real(target, *value);
388        }
389    }
390
391    unsafe fn read_mytype(source: *const c_void) -> Self {
392        unsafe { Self::read_mytype_real(source) }
393    }
394}
395
396#[cfg(feature = "gmp")]
397impl sealed::Sealed for CddFloat {}
398
399#[cfg(feature = "gmp")]
400impl CddNumber for CddFloat {
401    const MYTYPE_SIZE: usize = mem::size_of::<sys::gmpfloat::mytype>();
402    const DEFAULT_NUMBER_TYPE: NumberType = NumberType::Real;
403
404    fn ensure_initialized() {
405        static INIT: Once = Once::new();
406        INIT.call_once(|| unsafe {
407            sys::gmpfloat::dd_set_global_constants();
408        });
409    }
410
411    fn dd_no_error() -> u32 {
412        sys::gmpfloat::dd_ErrorType_dd_NoError
413    }
414
415    unsafe fn dd_create_matrix(rows: c_long, cols: c_long) -> *mut c_void {
416        unsafe { sys::gmpfloat::dd_CreateMatrix(rows, cols).cast() }
417    }
418
419    unsafe fn dd_copy_matrix(matrix: *mut c_void) -> *mut c_void {
420        unsafe { sys::gmpfloat::dd_CopyMatrix(matrix.cast()).cast() }
421    }
422
423    unsafe fn dd_free_matrix(matrix: *mut c_void) {
424        unsafe {
425            sys::gmpfloat::dd_FreeMatrix(matrix.cast());
426        }
427    }
428
429    unsafe fn dd_matrix_append_to(dst: *mut *mut c_void, src: *mut c_void) -> i32 {
430        unsafe { sys::gmpfloat::dd_MatrixAppendTo(dst.cast(), src.cast()) }
431    }
432
433    unsafe fn dd_append_matrix(a: *mut c_void, b: *mut c_void) -> *mut c_void {
434        unsafe { sys::gmpfloat::dd_AppendMatrix(a.cast(), b.cast()).cast() }
435    }
436
437    unsafe fn dd_matrix_row_remove(matrix: *mut *mut c_void, row: c_long) -> i32 {
438        unsafe { sys::gmpfloat::dd_MatrixRowRemove(matrix.cast(), row) }
439    }
440
441    unsafe fn dd_initialize_arow(cols: c_long, out: *mut *mut c_void) {
442        unsafe {
443            sys::gmpfloat::dd_InitializeArow(cols, out.cast());
444        }
445    }
446
447    unsafe fn dd_free_arow(cols: c_long, arow: *mut c_void) {
448        unsafe {
449            sys::gmpfloat::dd_FreeArow(cols, arow.cast());
450        }
451    }
452
453    unsafe fn dd_redundant(
454        matrix: *mut c_void,
455        row: c_long,
456        cert: *mut c_void,
457        err: *mut u32,
458    ) -> i32 {
459        unsafe { sys::gmpfloat::dd_Redundant(matrix.cast(), row, cert.cast(), err.cast()) }
460    }
461
462    unsafe fn dd_redundant_rows(matrix: *mut c_void, err: *mut u32) -> *mut libc::c_ulong {
463        unsafe { sys::gmpfloat::dd_RedundantRows(matrix.cast(), err.cast()).cast() }
464    }
465
466    unsafe fn dd_matrix_canonicalize(
467        matrix: *mut *mut c_void,
468        impl_lin: *mut *mut libc::c_ulong,
469        redset: *mut *mut libc::c_ulong,
470        newpos: *mut *mut c_long,
471        err: *mut u32,
472    ) -> i32 {
473        unsafe {
474            sys::gmpfloat::dd_MatrixCanonicalize(
475                matrix.cast(),
476                impl_lin.cast(),
477                redset.cast(),
478                newpos.cast(),
479                err.cast(),
480            )
481        }
482    }
483
484    unsafe fn set_groundsize(set: *mut libc::c_ulong) -> c_long {
485        unsafe { sys::gmpfloat::set_groundsize(set.cast()) }
486    }
487
488    unsafe fn set_member(elem: c_long, set: *mut libc::c_ulong) -> i32 {
489        unsafe { sys::gmpfloat::set_member(elem, set.cast()) }
490    }
491
492    unsafe fn set_free(set: *mut libc::c_ulong) {
493        unsafe {
494            sys::gmpfloat::set_free(set.cast());
495        }
496    }
497
498    unsafe fn dd_matrix2poly(matrix: *mut c_void, err: *mut u32) -> *mut c_void {
499        unsafe { sys::gmpfloat::dd_DDMatrix2Poly(matrix.cast(), err.cast()).cast() }
500    }
501
502    unsafe fn dd_free_polyhedra(poly: *mut c_void) {
503        unsafe {
504            sys::gmpfloat::dd_FreePolyhedra(poly.cast());
505        }
506    }
507
508    unsafe fn dd_copy_inequalities(poly: *mut c_void) -> *mut c_void {
509        unsafe { sys::gmpfloat::dd_CopyInequalities(poly.cast()).cast() }
510    }
511
512    unsafe fn dd_copy_generators(poly: *mut c_void) -> *mut c_void {
513        unsafe { sys::gmpfloat::dd_CopyGenerators(poly.cast()).cast() }
514    }
515
516    unsafe fn dd_copy_adjacency(poly: *mut c_void) -> *mut c_void {
517        unsafe { sys::gmpfloat::dd_CopyAdjacency(poly.cast()).cast() }
518    }
519
520    unsafe fn dd_copy_input_adjacency(poly: *mut c_void) -> *mut c_void {
521        unsafe { sys::gmpfloat::dd_CopyInputAdjacency(poly.cast()).cast() }
522    }
523
524    unsafe fn dd_copy_incidence(poly: *mut c_void) -> *mut c_void {
525        unsafe { sys::gmpfloat::dd_CopyIncidence(poly.cast()).cast() }
526    }
527
528    unsafe fn dd_copy_input_incidence(poly: *mut c_void) -> *mut c_void {
529        unsafe { sys::gmpfloat::dd_CopyInputIncidence(poly.cast()).cast() }
530    }
531
532    unsafe fn dd_append_matrix2poly(poly: *mut *mut c_void, rows: *mut c_void) -> i32 {
533        unsafe { sys::gmpfloat::dd_AppendMatrix2Poly(poly.cast(), rows.cast()) }
534    }
535
536    unsafe fn dd_free_set_family(family: *mut c_void) {
537        unsafe {
538            sys::gmpfloat::dd_FreeSetFamily(family.cast());
539        }
540    }
541
542    unsafe fn dd_matrix2lp(matrix: *mut c_void, err: *mut u32) -> *mut c_void {
543        unsafe { sys::gmpfloat::dd_Matrix2LP(matrix.cast(), err.cast()).cast() }
544    }
545
546    unsafe fn dd_free_lp_data(lp: *mut c_void) {
547        unsafe {
548            sys::gmpfloat::dd_FreeLPData(lp.cast());
549        }
550    }
551
552    unsafe fn dd_lp_solve_dual_simplex(lp: *mut c_void, err: *mut u32) -> i32 {
553        unsafe {
554            sys::gmpfloat::dd_LPSolve(
555                lp.cast(),
556                sys::gmpfloat::dd_LPSolverType_dd_DualSimplex,
557                err.cast(),
558            )
559        }
560    }
561
562    unsafe fn lp_status_raw(lp: *mut c_void) -> u32 {
563        unsafe { (*lp.cast::<sys::gmpfloat::dd_lpdata>()).LPS }
564    }
565
566    unsafe fn dd_copy_lp_solution(lp: *mut c_void) -> *mut c_void {
567        unsafe { sys::gmpfloat::dd_CopyLPSolution(lp.cast()).cast() }
568    }
569
570    unsafe fn dd_free_lp_solution(sol: *mut c_void) {
571        unsafe {
572            sys::gmpfloat::dd_FreeLPSolution(sol.cast());
573        }
574    }
575
576    unsafe fn lp_solution_optvalue_ptr(sol: *mut c_void) -> *const c_void {
577        unsafe {
578            let sol = sol.cast::<sys::gmpfloat::dd_lpsolution>();
579            (&(*sol).optvalue as *const sys::gmpfloat::mytype).cast()
580        }
581    }
582
583    unsafe fn write_mytype_real(target: *mut c_void, value: f64) {
584        unsafe {
585            sys::gmpfloat::__gmpf_set_d(target.cast(), value);
586        }
587    }
588
589    unsafe fn write_mytype_int(target: *mut c_void, value: c_long) {
590        unsafe {
591            sys::gmpfloat::__gmpf_set_si(target.cast(), value);
592        }
593    }
594
595    unsafe fn read_mytype_real(source: *const c_void) -> f64 {
596        unsafe { sys::gmpfloat::__gmpf_get_d(source.cast()) }
597    }
598
599    unsafe fn write_mytype(target: *mut c_void, value: &Self) {
600        unsafe {
601            sys::gmpfloat::ddd_set(target.cast(), value.inner.as_ptr().cast_mut());
602        }
603    }
604
605    unsafe fn read_mytype(source: *const c_void) -> Self {
606        unsafe {
607            Self::ensure_initialized();
608            let mut inner = MaybeUninit::<sys::gmpfloat::mytype>::uninit();
609            sys::gmpfloat::ddd_init(inner.as_mut_ptr().cast());
610            sys::gmpfloat::ddd_set(
611                inner.as_mut_ptr().cast(),
612                source.cast::<sys::gmpfloat::__mpf_struct>().cast_mut(),
613            );
614            CddFloat {
615                inner: inner.assume_init(),
616            }
617        }
618    }
619}
620
621#[cfg(feature = "gmprational")]
622impl sealed::Sealed for CddRational {}
623
624#[cfg(feature = "gmprational")]
625impl CddNumber for CddRational {
626    const MYTYPE_SIZE: usize = mem::size_of::<sys::gmprational::mytype>();
627    const DEFAULT_NUMBER_TYPE: NumberType = NumberType::Rational;
628
629    fn ensure_initialized() {
630        static INIT: Once = Once::new();
631        INIT.call_once(|| unsafe {
632            sys::gmprational::dd_set_global_constants();
633        });
634    }
635
636    fn dd_no_error() -> u32 {
637        sys::gmprational::dd_ErrorType_dd_NoError
638    }
639
640    unsafe fn dd_create_matrix(rows: c_long, cols: c_long) -> *mut c_void {
641        unsafe { sys::gmprational::dd_CreateMatrix(rows, cols).cast() }
642    }
643
644    unsafe fn dd_copy_matrix(matrix: *mut c_void) -> *mut c_void {
645        unsafe { sys::gmprational::dd_CopyMatrix(matrix.cast()).cast() }
646    }
647
648    unsafe fn dd_free_matrix(matrix: *mut c_void) {
649        unsafe {
650            sys::gmprational::dd_FreeMatrix(matrix.cast());
651        }
652    }
653
654    unsafe fn dd_matrix_append_to(dst: *mut *mut c_void, src: *mut c_void) -> i32 {
655        unsafe { sys::gmprational::dd_MatrixAppendTo(dst.cast(), src.cast()) }
656    }
657
658    unsafe fn dd_append_matrix(a: *mut c_void, b: *mut c_void) -> *mut c_void {
659        unsafe { sys::gmprational::dd_AppendMatrix(a.cast(), b.cast()).cast() }
660    }
661
662    unsafe fn dd_matrix_row_remove(matrix: *mut *mut c_void, row: c_long) -> i32 {
663        unsafe { sys::gmprational::dd_MatrixRowRemove(matrix.cast(), row) }
664    }
665
666    unsafe fn dd_initialize_arow(cols: c_long, out: *mut *mut c_void) {
667        unsafe {
668            sys::gmprational::dd_InitializeArow(cols, out.cast());
669        }
670    }
671
672    unsafe fn dd_free_arow(cols: c_long, arow: *mut c_void) {
673        unsafe {
674            sys::gmprational::dd_FreeArow(cols, arow.cast());
675        }
676    }
677
678    unsafe fn dd_redundant(
679        matrix: *mut c_void,
680        row: c_long,
681        cert: *mut c_void,
682        err: *mut u32,
683    ) -> i32 {
684        unsafe { sys::gmprational::dd_Redundant(matrix.cast(), row, cert.cast(), err.cast()) }
685    }
686
687    unsafe fn dd_redundant_rows(matrix: *mut c_void, err: *mut u32) -> *mut libc::c_ulong {
688        unsafe { sys::gmprational::dd_RedundantRows(matrix.cast(), err.cast()).cast() }
689    }
690
691    unsafe fn dd_matrix_canonicalize(
692        matrix: *mut *mut c_void,
693        impl_lin: *mut *mut libc::c_ulong,
694        redset: *mut *mut libc::c_ulong,
695        newpos: *mut *mut c_long,
696        err: *mut u32,
697    ) -> i32 {
698        unsafe {
699            sys::gmprational::dd_MatrixCanonicalize(
700                matrix.cast(),
701                impl_lin.cast(),
702                redset.cast(),
703                newpos.cast(),
704                err.cast(),
705            )
706        }
707    }
708
709    unsafe fn set_groundsize(set: *mut libc::c_ulong) -> c_long {
710        unsafe { sys::gmprational::set_groundsize(set.cast()) }
711    }
712
713    unsafe fn set_member(elem: c_long, set: *mut libc::c_ulong) -> i32 {
714        unsafe { sys::gmprational::set_member(elem, set.cast()) }
715    }
716
717    unsafe fn set_free(set: *mut libc::c_ulong) {
718        unsafe {
719            sys::gmprational::set_free(set.cast());
720        }
721    }
722
723    unsafe fn dd_matrix2poly(matrix: *mut c_void, err: *mut u32) -> *mut c_void {
724        unsafe { sys::gmprational::dd_DDMatrix2Poly(matrix.cast(), err.cast()).cast() }
725    }
726
727    unsafe fn dd_free_polyhedra(poly: *mut c_void) {
728        unsafe {
729            sys::gmprational::dd_FreePolyhedra(poly.cast());
730        }
731    }
732
733    unsafe fn dd_copy_inequalities(poly: *mut c_void) -> *mut c_void {
734        unsafe { sys::gmprational::dd_CopyInequalities(poly.cast()).cast() }
735    }
736
737    unsafe fn dd_copy_generators(poly: *mut c_void) -> *mut c_void {
738        unsafe { sys::gmprational::dd_CopyGenerators(poly.cast()).cast() }
739    }
740
741    unsafe fn dd_copy_adjacency(poly: *mut c_void) -> *mut c_void {
742        unsafe { sys::gmprational::dd_CopyAdjacency(poly.cast()).cast() }
743    }
744
745    unsafe fn dd_copy_input_adjacency(poly: *mut c_void) -> *mut c_void {
746        unsafe { sys::gmprational::dd_CopyInputAdjacency(poly.cast()).cast() }
747    }
748
749    unsafe fn dd_copy_incidence(poly: *mut c_void) -> *mut c_void {
750        unsafe { sys::gmprational::dd_CopyIncidence(poly.cast()).cast() }
751    }
752
753    unsafe fn dd_copy_input_incidence(poly: *mut c_void) -> *mut c_void {
754        unsafe { sys::gmprational::dd_CopyInputIncidence(poly.cast()).cast() }
755    }
756
757    unsafe fn dd_append_matrix2poly(poly: *mut *mut c_void, rows: *mut c_void) -> i32 {
758        unsafe { sys::gmprational::dd_AppendMatrix2Poly(poly.cast(), rows.cast()) }
759    }
760
761    unsafe fn dd_free_set_family(family: *mut c_void) {
762        unsafe {
763            sys::gmprational::dd_FreeSetFamily(family.cast());
764        }
765    }
766
767    unsafe fn dd_matrix2lp(matrix: *mut c_void, err: *mut u32) -> *mut c_void {
768        unsafe { sys::gmprational::dd_Matrix2LP(matrix.cast(), err.cast()).cast() }
769    }
770
771    unsafe fn dd_free_lp_data(lp: *mut c_void) {
772        unsafe {
773            sys::gmprational::dd_FreeLPData(lp.cast());
774        }
775    }
776
777    unsafe fn dd_lp_solve_dual_simplex(lp: *mut c_void, err: *mut u32) -> i32 {
778        unsafe {
779            sys::gmprational::dd_LPSolve(
780                lp.cast(),
781                sys::gmprational::dd_LPSolverType_dd_DualSimplex,
782                err.cast(),
783            )
784        }
785    }
786
787    unsafe fn lp_status_raw(lp: *mut c_void) -> u32 {
788        unsafe { (*lp.cast::<sys::gmprational::dd_lpdata>()).LPS }
789    }
790
791    unsafe fn dd_copy_lp_solution(lp: *mut c_void) -> *mut c_void {
792        unsafe { sys::gmprational::dd_CopyLPSolution(lp.cast()).cast() }
793    }
794
795    unsafe fn dd_free_lp_solution(sol: *mut c_void) {
796        unsafe {
797            sys::gmprational::dd_FreeLPSolution(sol.cast());
798        }
799    }
800
801    unsafe fn lp_solution_optvalue_ptr(sol: *mut c_void) -> *const c_void {
802        unsafe {
803            let sol = sol.cast::<sys::gmprational::dd_lpsolution>();
804            (&(*sol).optvalue as *const sys::gmprational::mytype).cast()
805        }
806    }
807
808    unsafe fn write_mytype_real(target: *mut c_void, value: f64) {
809        unsafe {
810            sys::gmprational::__gmpq_set_d(target.cast(), value);
811        }
812    }
813
814    unsafe fn write_mytype_int(target: *mut c_void, value: c_long) {
815        unsafe {
816            sys::gmprational::__gmpq_set_si(target.cast(), value, 1);
817        }
818    }
819
820    unsafe fn read_mytype_real(source: *const c_void) -> f64 {
821        unsafe { sys::gmprational::__gmpq_get_d(source.cast()) }
822    }
823
824    unsafe fn write_mytype(target: *mut c_void, value: &Self) {
825        unsafe {
826            sys::gmprational::ddd_set(target.cast(), value.inner.as_ptr().cast_mut());
827        }
828    }
829
830    unsafe fn read_mytype(source: *const c_void) -> Self {
831        unsafe {
832            Self::ensure_initialized();
833            let mut inner = MaybeUninit::<sys::gmprational::mytype>::uninit();
834            sys::gmprational::ddd_init(inner.as_mut_ptr().cast());
835            sys::gmprational::ddd_set(
836                inner.as_mut_ptr().cast(),
837                source.cast::<sys::gmprational::__mpq_struct>().cast_mut(),
838            );
839            CddRational {
840                inner: inner.assume_init(),
841            }
842        }
843    }
844}
845
846#[cfg(feature = "gmp")]
847impl CddFloat {
848    pub fn to_f64(&self) -> f64 {
849        <Self as CddNumber>::ensure_initialized();
850        unsafe { sys::gmpfloat::__gmpf_get_d(self.inner.as_ptr()) }
851    }
852}
853
854#[cfg(feature = "gmp")]
855impl Clone for CddFloat {
856    fn clone(&self) -> Self {
857        <Self as CddNumber>::ensure_initialized();
858        unsafe {
859            let mut inner = MaybeUninit::<sys::gmpfloat::mytype>::uninit();
860            sys::gmpfloat::ddd_init(inner.as_mut_ptr().cast());
861            sys::gmpfloat::ddd_set(inner.as_mut_ptr().cast(), self.inner.as_ptr().cast_mut());
862            CddFloat {
863                inner: inner.assume_init(),
864            }
865        }
866    }
867}
868
869#[cfg(feature = "gmp")]
870impl Drop for CddFloat {
871    fn drop(&mut self) {
872        <Self as CddNumber>::ensure_initialized();
873        unsafe {
874            sys::gmpfloat::ddd_clear(self.inner.as_mut_ptr());
875        }
876    }
877}
878
879#[cfg(feature = "gmp")]
880impl From<f64> for CddFloat {
881    fn from(value: f64) -> Self {
882        <Self as CddNumber>::ensure_initialized();
883        unsafe {
884            let mut inner = MaybeUninit::<sys::gmpfloat::mytype>::uninit();
885            sys::gmpfloat::ddd_init(inner.as_mut_ptr().cast());
886            sys::gmpfloat::__gmpf_set_d(inner.as_mut_ptr().cast(), value);
887            CddFloat {
888                inner: inner.assume_init(),
889            }
890        }
891    }
892}
893
894#[cfg(feature = "gmprational")]
895impl CddRational {
896    pub fn to_f64(&self) -> f64 {
897        <Self as CddNumber>::ensure_initialized();
898        unsafe { sys::gmprational::__gmpq_get_d(self.inner.as_ptr()) }
899    }
900}
901
902#[cfg(feature = "gmprational")]
903impl Clone for CddRational {
904    fn clone(&self) -> Self {
905        <Self as CddNumber>::ensure_initialized();
906        unsafe {
907            let mut inner = MaybeUninit::<sys::gmprational::mytype>::uninit();
908            sys::gmprational::ddd_init(inner.as_mut_ptr().cast());
909            sys::gmprational::ddd_set(inner.as_mut_ptr().cast(), self.inner.as_ptr().cast_mut());
910            CddRational {
911                inner: inner.assume_init(),
912            }
913        }
914    }
915}
916
917#[cfg(feature = "gmprational")]
918impl Drop for CddRational {
919    fn drop(&mut self) {
920        <Self as CddNumber>::ensure_initialized();
921        unsafe {
922            sys::gmprational::ddd_clear(self.inner.as_mut_ptr());
923        }
924    }
925}
926
927#[cfg(feature = "gmprational")]
928impl From<f64> for CddRational {
929    fn from(value: f64) -> Self {
930        <Self as CddNumber>::ensure_initialized();
931        unsafe {
932            let mut inner = MaybeUninit::<sys::gmprational::mytype>::uninit();
933            sys::gmprational::ddd_init(inner.as_mut_ptr().cast());
934            sys::gmprational::__gmpq_set_d(inner.as_mut_ptr().cast(), value);
935            CddRational {
936                inner: inner.assume_init(),
937            }
938        }
939    }
940}
941
942#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
943pub enum CddErrorCode {
944    DimensionTooLarge,
945    ImproperInputFormat,
946    NegativeMatrixSize,
947    EmptyVRepresentation,
948    EmptyHRepresentation,
949    EmptyRepresentation,
950    InputFileNotFound,
951    OutputFileNotOpen,
952    NoLpObjective,
953    NoRealNumberSupport,
954    NotAvailForH,
955    NotAvailForV,
956    CannotHandleLinearity,
957    RowIndexOutOfRange,
958    ColIndexOutOfRange,
959    LpCycling,
960    NumericallyInconsistent,
961    NoError,
962}
963
964impl CddErrorCode {
965    pub fn from_raw(raw: u32) -> Self {
966        match raw {
967            0 => Self::DimensionTooLarge,
968            1 => Self::ImproperInputFormat,
969            2 => Self::NegativeMatrixSize,
970            3 => Self::EmptyVRepresentation,
971            4 => Self::EmptyHRepresentation,
972            5 => Self::EmptyRepresentation,
973            6 => Self::InputFileNotFound,
974            7 => Self::OutputFileNotOpen,
975            8 => Self::NoLpObjective,
976            9 => Self::NoRealNumberSupport,
977            10 => Self::NotAvailForH,
978            11 => Self::NotAvailForV,
979            12 => Self::CannotHandleLinearity,
980            13 => Self::RowIndexOutOfRange,
981            14 => Self::ColIndexOutOfRange,
982            15 => Self::LpCycling,
983            16 => Self::NumericallyInconsistent,
984            17 => Self::NoError,
985            other => panic!("unknown dd_ErrorType value {other}"),
986        }
987    }
988
989    pub fn as_raw(self) -> u32 {
990        match self {
991            Self::DimensionTooLarge => 0,
992            Self::ImproperInputFormat => 1,
993            Self::NegativeMatrixSize => 2,
994            Self::EmptyVRepresentation => 3,
995            Self::EmptyHRepresentation => 4,
996            Self::EmptyRepresentation => 5,
997            Self::InputFileNotFound => 6,
998            Self::OutputFileNotOpen => 7,
999            Self::NoLpObjective => 8,
1000            Self::NoRealNumberSupport => 9,
1001            Self::NotAvailForH => 10,
1002            Self::NotAvailForV => 11,
1003            Self::CannotHandleLinearity => 12,
1004            Self::RowIndexOutOfRange => 13,
1005            Self::ColIndexOutOfRange => 14,
1006            Self::LpCycling => 15,
1007            Self::NumericallyInconsistent => 16,
1008            Self::NoError => 17,
1009        }
1010    }
1011
1012    fn cddlib_name(self) -> &'static str {
1013        match self {
1014            Self::DimensionTooLarge => "dd_DimensionTooLarge",
1015            Self::ImproperInputFormat => "dd_ImproperInputFormat",
1016            Self::NegativeMatrixSize => "dd_NegativeMatrixSize",
1017            Self::EmptyVRepresentation => "dd_EmptyVrepresentation",
1018            Self::EmptyHRepresentation => "dd_EmptyHrepresentation",
1019            Self::EmptyRepresentation => "dd_EmptyRepresentation",
1020            Self::InputFileNotFound => "dd_IFileNotFound",
1021            Self::OutputFileNotOpen => "dd_OFileNotOpen",
1022            Self::NoLpObjective => "dd_NoLPObjective",
1023            Self::NoRealNumberSupport => "dd_NoRealNumberSupport",
1024            Self::NotAvailForH => "dd_NotAvailForH",
1025            Self::NotAvailForV => "dd_NotAvailForV",
1026            Self::CannotHandleLinearity => "dd_CannotHandleLinearity",
1027            Self::RowIndexOutOfRange => "dd_RowIndexOutOfRange",
1028            Self::ColIndexOutOfRange => "dd_ColIndexOutOfRange",
1029            Self::LpCycling => "dd_LPCycling",
1030            Self::NumericallyInconsistent => "dd_NumericallyInconsistent",
1031            Self::NoError => "dd_NoError",
1032        }
1033    }
1034}
1035
1036impl std::fmt::Display for CddErrorCode {
1037    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
1038        write!(f, "{} (code={})", self.cddlib_name(), self.as_raw())
1039    }
1040}
1041
1042#[derive(Debug, Error)]
1043pub enum CddError {
1044    #[error("cddlib returned {0}")]
1045    Cdd(CddErrorCode),
1046    #[error("cddlib returned a null pointer")]
1047    NullPointer,
1048    #[error("LP error")]
1049    LpError,
1050    #[error("LP did not have an optimal solution (status={0:?})")]
1051    LpStatus(LpStatus),
1052    #[error("cddlib operation returned failure")]
1053    OpFailed,
1054}
1055
1056#[derive(Debug, Error)]
1057pub enum CddWrapperError {
1058    #[error(transparent)]
1059    Cdd(#[from] CddError),
1060    #[error("invalid matrix dimensions (rows={rows}, cols={cols})")]
1061    InvalidMatrix { rows: usize, cols: usize },
1062}
1063
1064pub type CddResult<T> = std::result::Result<T, CddWrapperError>;
1065
1066#[derive(Debug, Clone, Copy, PartialEq, Eq)]
1067pub enum Representation {
1068    Inequality,
1069    Generator,
1070}
1071
1072impl Representation {
1073    fn to_raw(self) -> u32 {
1074        match self {
1075            Representation::Inequality => 1,
1076            Representation::Generator => 2,
1077        }
1078    }
1079
1080    fn from_raw(raw: u32) -> Self {
1081        match raw {
1082            1 => Representation::Inequality,
1083            2 => Representation::Generator,
1084            other => panic!("unknown dd_RepresentationType value {other}"),
1085        }
1086    }
1087}
1088
1089#[derive(Debug, Clone, Copy, PartialEq, Eq)]
1090pub enum NumberType {
1091    Real,
1092    Rational,
1093}
1094
1095impl NumberType {
1096    fn to_raw(self) -> u32 {
1097        match self {
1098            NumberType::Real => 1,
1099            NumberType::Rational => 2,
1100        }
1101    }
1102
1103    fn from_raw(raw: u32) -> Self {
1104        match raw {
1105            1 => NumberType::Real,
1106            2 => NumberType::Rational,
1107            other => panic!("unknown dd_NumberType value {other}"),
1108        }
1109    }
1110}
1111
1112#[derive(Debug, Clone, Copy, PartialEq, Eq)]
1113pub enum LpObjective {
1114    None,
1115    Maximize,
1116    Minimize,
1117}
1118
1119impl LpObjective {
1120    fn to_raw(self) -> u32 {
1121        match self {
1122            LpObjective::None => 0,
1123            LpObjective::Maximize => 1,
1124            LpObjective::Minimize => 2,
1125        }
1126    }
1127}
1128
1129#[derive(Debug, Clone, Copy, PartialEq, Eq)]
1130pub enum LpStatus {
1131    Undecided,
1132    Optimal,
1133    Inconsistent,
1134    DualInconsistent,
1135    StructuralInconsistent,
1136    StructuralDualInconsistent,
1137    Unbounded,
1138    DualUnbounded,
1139}
1140
1141impl LpStatus {
1142    fn from_raw(raw: u32) -> Self {
1143        match raw {
1144            0 => LpStatus::Undecided,
1145            1 => LpStatus::Optimal,
1146            2 => LpStatus::Inconsistent,
1147            3 => LpStatus::DualInconsistent,
1148            4 => LpStatus::StructuralInconsistent,
1149            5 => LpStatus::StructuralDualInconsistent,
1150            6 => LpStatus::Unbounded,
1151            7 => LpStatus::DualUnbounded,
1152            other => panic!("unknown dd_LPStatusType value {other}"),
1153        }
1154    }
1155}
1156
1157#[repr(C)]
1158struct RawMatrixData {
1159    rowsize: c_long,
1160    linset: *mut libc::c_ulong,
1161    colsize: c_long,
1162    representation: u32,
1163    numbtype: u32,
1164    matrix: *mut *mut c_void,
1165    objective: u32,
1166    rowvec: *mut c_void,
1167}
1168
1169#[repr(C)]
1170struct RawSetFamily {
1171    famsize: c_long,
1172    setsize: c_long,
1173    set: *mut *mut libc::c_ulong,
1174}
1175
1176#[derive(Debug)]
1177pub struct Matrix<N: CddNumber = DefaultNumber> {
1178    ptr: NonNull<RawMatrixData>,
1179    _marker: PhantomData<N>,
1180    _no_send_sync: PhantomData<Rc<()>>,
1181}
1182
1183#[derive(Debug)]
1184pub struct CanonicalForm<N: CddNumber = DefaultNumber> {
1185    pub matrix: Matrix<N>,
1186    pub implicit_linearity: Vec<usize>,
1187    pub redundant_rows: Vec<usize>,
1188    pub positions: Vec<isize>,
1189}
1190
1191impl<N: CddNumber> Matrix<N> {
1192    pub fn new(
1193        rows: usize,
1194        cols: usize,
1195        repr: Representation,
1196        num_type: NumberType,
1197    ) -> CddResult<Self> {
1198        N::ensure_initialized();
1199
1200        if rows == 0 || cols == 0 {
1201            return Err(CddWrapperError::InvalidMatrix { rows, cols });
1202        }
1203
1204        let rowrange =
1205            c_long::try_from(rows).map_err(|_| CddWrapperError::InvalidMatrix { rows, cols })?;
1206        let colrange =
1207            c_long::try_from(cols).map_err(|_| CddWrapperError::InvalidMatrix { rows, cols })?;
1208
1209        let ptr = unsafe { N::dd_create_matrix(rowrange, colrange) };
1210        let mut ptr = NonNull::new(ptr.cast::<RawMatrixData>()).ok_or(CddError::NullPointer)?;
1211
1212        unsafe {
1213            ptr.as_mut().representation = repr.to_raw();
1214            ptr.as_mut().numbtype = num_type.to_raw();
1215        }
1216
1217        Ok(Matrix {
1218            ptr,
1219            _marker: PhantomData,
1220            _no_send_sync: PhantomData,
1221        })
1222    }
1223
1224    pub fn rows(&self) -> usize {
1225        unsafe { self.ptr.as_ref().rowsize as usize }
1226    }
1227
1228    pub fn cols(&self) -> usize {
1229        unsafe { self.ptr.as_ref().colsize as usize }
1230    }
1231
1232    pub fn representation(&self) -> Representation {
1233        unsafe { Representation::from_raw(self.ptr.as_ref().representation) }
1234    }
1235
1236    pub fn number_type(&self) -> NumberType {
1237        unsafe { NumberType::from_raw(self.ptr.as_ref().numbtype) }
1238    }
1239
1240    pub fn as_raw(&self) -> *mut c_void {
1241        self.ptr.as_ptr().cast()
1242    }
1243
1244    /// # Safety
1245    ///
1246    /// - `ptr` must be a non-null `dd_MatrixPtr` compatible with the backend `N`.
1247    /// - The pointer must be valid for the lifetime of this wrapper and must be
1248    ///   owned by this wrapper (it will be freed on drop).
1249    pub unsafe fn from_raw(ptr: *mut c_void) -> Self {
1250        Matrix {
1251            ptr: NonNull::new(ptr.cast()).expect("from_raw called with null dd_MatrixPtr"),
1252            _marker: PhantomData,
1253            _no_send_sync: PhantomData,
1254        }
1255    }
1256
1257    pub fn clone_cdd(&self) -> CddResult<Self> {
1258        N::ensure_initialized();
1259
1260        let ptr = unsafe { N::dd_copy_matrix(self.as_raw()) };
1261        let ptr = NonNull::new(ptr).ok_or(CddError::NullPointer)?;
1262        Ok(unsafe { Self::from_raw(ptr.as_ptr()) })
1263    }
1264
1265    pub fn set(&mut self, row: usize, col: usize, value: &N) {
1266        assert!(row < self.rows());
1267        assert!(col < self.cols());
1268        let cell = unsafe { matrix_cell::<N>(self.ptr, row, col) };
1269        unsafe {
1270            N::write_mytype(cell, value);
1271        }
1272    }
1273
1274    pub fn get(&self, row: usize, col: usize) -> N {
1275        assert!(row < self.rows());
1276        assert!(col < self.cols());
1277        let cell = unsafe { matrix_cell::<N>(self.ptr, row, col) };
1278        unsafe { N::read_mytype(cell.cast_const()) }
1279    }
1280
1281    pub fn set_real(&mut self, row: usize, col: usize, value: f64) {
1282        assert!(row < self.rows());
1283        assert!(col < self.cols());
1284        let cell = unsafe { matrix_cell::<N>(self.ptr, row, col) };
1285        unsafe {
1286            N::write_mytype_real(cell, value);
1287        }
1288    }
1289
1290    pub fn get_real(&self, row: usize, col: usize) -> f64 {
1291        assert!(row < self.rows());
1292        assert!(col < self.cols());
1293        let cell = unsafe { matrix_cell::<N>(self.ptr, row, col) };
1294        unsafe { N::read_mytype_real(cell.cast_const()) }
1295    }
1296
1297    pub fn set_generator_type(&mut self, row: usize, is_vertex: bool) {
1298        assert!(row < self.rows());
1299        let cell = unsafe { matrix_cell::<N>(self.ptr, row, 0) };
1300        let value = if is_vertex { 1 } else { 0 };
1301        unsafe {
1302            N::write_mytype_int(cell, value);
1303        }
1304    }
1305
1306    pub fn set_objective_real(&mut self, coeffs: &[f64]) {
1307        assert_eq!(coeffs.len(), self.cols());
1308        let rowvec = unsafe { self.ptr.as_ref().rowvec };
1309        assert!(!rowvec.is_null(), "matrix objective rowvec is null");
1310        for (j, &c) in coeffs.iter().enumerate() {
1311            let cell = unsafe { rowvec_cell::<N>(rowvec, j) };
1312            unsafe {
1313                N::write_mytype_real(cell, c);
1314            }
1315        }
1316    }
1317
1318    pub fn from_vertices<const D: usize>(vertices: &[[N; D]]) -> CddResult<Self> {
1319        if vertices.is_empty() {
1320            return Err(CddWrapperError::InvalidMatrix {
1321                rows: 0,
1322                cols: D + 1,
1323            });
1324        }
1325
1326        let mut m = Self::new(
1327            vertices.len(),
1328            D + 1,
1329            Representation::Generator,
1330            N::DEFAULT_NUMBER_TYPE,
1331        )?;
1332        for (i, v) in vertices.iter().enumerate() {
1333            m.set_generator_type(i, true);
1334            for (j, coord) in v.iter().enumerate() {
1335                m.set(i, j + 1, coord);
1336            }
1337        }
1338        Ok(m)
1339    }
1340
1341    /// Build a generator matrix from a dynamic list of vertices.
1342    ///
1343    /// The ambient dimension is determined from the first vertex. All vertices
1344    /// must have the same length.
1345    pub fn from_vertex_rows(vertices: &[Vec<N>]) -> CddResult<Self> {
1346        let Some(first) = vertices.first() else {
1347            return Err(CddWrapperError::InvalidMatrix { rows: 0, cols: 0 });
1348        };
1349
1350        let dim = first.len();
1351        if dim == 0 {
1352            return Err(CddWrapperError::InvalidMatrix {
1353                rows: vertices.len(),
1354                cols: 0,
1355            });
1356        }
1357
1358        if vertices.iter().skip(1).any(|v| v.len() != dim) {
1359            return Err(CddWrapperError::InvalidMatrix {
1360                rows: vertices.len(),
1361                cols: dim + 1,
1362            });
1363        }
1364
1365        let mut m = Self::new(
1366            vertices.len(),
1367            dim + 1,
1368            Representation::Generator,
1369            N::DEFAULT_NUMBER_TYPE,
1370        )?;
1371        for (row, coords) in vertices.iter().enumerate() {
1372            m.set_generator_type(row, true);
1373            for (col, coord) in coords.iter().enumerate() {
1374                m.set(row, col + 1, coord);
1375            }
1376        }
1377        Ok(m)
1378    }
1379
1380    pub fn append_rows_in_place(&mut self, rows: &Matrix<N>) -> CddResult<()> {
1381        N::ensure_initialized();
1382
1383        if self.cols() != rows.cols() {
1384            return Err(CddWrapperError::InvalidMatrix {
1385                rows: self.rows() + rows.rows(),
1386                cols: rows.cols(),
1387            });
1388        }
1389
1390        if self.representation() != rows.representation()
1391            || self.number_type() != rows.number_type()
1392        {
1393            return Err(CddWrapperError::InvalidMatrix {
1394                rows: self.rows() + rows.rows(),
1395                cols: rows.cols(),
1396            });
1397        }
1398
1399        let mut raw = self.as_raw();
1400        let ok = unsafe { N::dd_matrix_append_to(&mut raw, rows.as_raw()) };
1401        if ok == 0 {
1402            return Err(CddError::OpFailed.into());
1403        }
1404
1405        let raw = NonNull::new(raw.cast()).ok_or(CddError::NullPointer)?;
1406        if raw != self.ptr {
1407            self.ptr = raw;
1408        }
1409        Ok(())
1410    }
1411
1412    pub fn append_rows(&self, rows: &Matrix<N>) -> CddResult<Self> {
1413        N::ensure_initialized();
1414
1415        if self.cols() != rows.cols() {
1416            return Err(CddWrapperError::InvalidMatrix {
1417                rows: self.rows() + rows.rows(),
1418                cols: rows.cols(),
1419            });
1420        }
1421
1422        if self.representation() != rows.representation()
1423            || self.number_type() != rows.number_type()
1424        {
1425            return Err(CddWrapperError::InvalidMatrix {
1426                rows: self.rows() + rows.rows(),
1427                cols: rows.cols(),
1428            });
1429        }
1430
1431        let ptr = unsafe { N::dd_append_matrix(self.as_raw(), rows.as_raw()) };
1432        let ptr = NonNull::new(ptr).ok_or(CddError::NullPointer)?;
1433        Ok(unsafe { Self::from_raw(ptr.as_ptr()) })
1434    }
1435
1436    pub fn append_row(&self, coords: &[N], is_vertex: bool) -> CddResult<Self> {
1437        if coords.len() + 1 != self.cols() {
1438            return Err(CddWrapperError::InvalidMatrix {
1439                rows: self.rows() + 1,
1440                cols: coords.len() + 1,
1441            });
1442        }
1443
1444        let mut row = Self::new(1, self.cols(), self.representation(), self.number_type())?;
1445        row.set_generator_type(0, is_vertex);
1446        for (col, val) in coords.iter().enumerate() {
1447            row.set(0, col + 1, val);
1448        }
1449
1450        self.append_rows(&row)
1451    }
1452
1453    pub fn remove_row(&mut self, row: usize) -> CddResult<()> {
1454        N::ensure_initialized();
1455
1456        if row >= self.rows() {
1457            return Err(CddWrapperError::InvalidMatrix {
1458                rows: self.rows(),
1459                cols: self.cols(),
1460            });
1461        }
1462
1463        let row_idx = c_long::try_from(row + 1).map_err(|_| CddWrapperError::InvalidMatrix {
1464            rows: self.rows(),
1465            cols: self.cols(),
1466        })?;
1467
1468        let mut raw = self.as_raw();
1469        let ok = unsafe { N::dd_matrix_row_remove(&mut raw, row_idx) };
1470        if ok == 0 {
1471            return Err(CddError::OpFailed.into());
1472        }
1473
1474        let raw = NonNull::new(raw.cast()).ok_or(CddError::NullPointer)?;
1475        if raw != self.ptr {
1476            self.ptr = raw;
1477        }
1478        Ok(())
1479    }
1480
1481    pub fn is_row_redundant(&self, row: usize) -> CddResult<bool> {
1482        N::ensure_initialized();
1483
1484        if row >= self.rows() {
1485            return Err(CddWrapperError::InvalidMatrix {
1486                rows: self.rows(),
1487                cols: self.cols(),
1488            });
1489        }
1490
1491        let row_idx = c_long::try_from(row + 1).map_err(|_| CddWrapperError::InvalidMatrix {
1492            rows: self.rows(),
1493            cols: self.cols(),
1494        })?;
1495
1496        let mut err = N::dd_no_error();
1497        let mut cert: *mut c_void = ptr::null_mut();
1498
1499        let cert_cols = match self.representation() {
1500            Representation::Generator => self.cols() + 1,
1501            Representation::Inequality => self.cols(),
1502        };
1503
1504        let colrange = c_long::try_from(cert_cols).map_err(|_| CddWrapperError::InvalidMatrix {
1505            rows: self.rows(),
1506            cols: self.cols(),
1507        })?;
1508
1509        unsafe {
1510            N::dd_initialize_arow(colrange, &mut cert);
1511        }
1512
1513        let redundant = unsafe { N::dd_redundant(self.as_raw(), row_idx, cert, &mut err) };
1514
1515        unsafe {
1516            N::dd_free_arow(colrange, cert);
1517        }
1518
1519        let err = CddErrorCode::from_raw(err);
1520        if err != CddErrorCode::NoError {
1521            return Err(CddError::Cdd(err).into());
1522        }
1523        Ok(redundant != 0)
1524    }
1525
1526    pub fn redundant_rows(&self) -> CddResult<Vec<usize>> {
1527        N::ensure_initialized();
1528
1529        let mut err = N::dd_no_error();
1530        let set = unsafe { N::dd_redundant_rows(self.as_raw(), &mut err) };
1531        let err = CddErrorCode::from_raw(err);
1532        if err != CddErrorCode::NoError {
1533            return Err(CddError::Cdd(err).into());
1534        }
1535        let set = NonNull::new(set).ok_or(CddError::NullPointer)?;
1536
1537        let ground = unsafe { N::set_groundsize(set.as_ptr()) };
1538        let ground = usize::try_from(ground).map_err(|_| CddWrapperError::InvalidMatrix {
1539            rows: self.rows(),
1540            cols: self.cols(),
1541        })?;
1542
1543        let mut rows = Vec::new();
1544        for i in 1..=ground {
1545            let member = unsafe { N::set_member(i as c_long, set.as_ptr()) };
1546            if member != 0 {
1547                rows.push(i - 1);
1548            }
1549        }
1550
1551        unsafe {
1552            N::set_free(set.as_ptr());
1553        }
1554
1555        Ok(rows)
1556    }
1557
1558    pub fn canonicalize(&self) -> CddResult<CanonicalForm<N>> {
1559        N::ensure_initialized();
1560
1561        let clone = self.clone_cdd()?;
1562        let mut raw = clone.as_raw();
1563        let mut impl_lin: *mut libc::c_ulong = ptr::null_mut();
1564        let mut redset: *mut libc::c_ulong = ptr::null_mut();
1565        let mut newpos: *mut c_long = ptr::null_mut();
1566        let mut err = N::dd_no_error();
1567
1568        let ok = unsafe {
1569            N::dd_matrix_canonicalize(&mut raw, &mut impl_lin, &mut redset, &mut newpos, &mut err)
1570        };
1571        let err = CddErrorCode::from_raw(err);
1572        if ok == 0 || err != CddErrorCode::NoError {
1573            unsafe {
1574                if !impl_lin.is_null() {
1575                    N::set_free(impl_lin);
1576                }
1577                if !redset.is_null() {
1578                    N::set_free(redset);
1579                }
1580                if !newpos.is_null() {
1581                    libc::free(newpos.cast());
1582                }
1583            }
1584            if ok == 0 && err == CddErrorCode::NoError {
1585                return Err(CddError::OpFailed.into());
1586            }
1587            return Err(CddError::Cdd(err).into());
1588        }
1589
1590        let canon = unsafe { Self::from_raw(raw) };
1591        let rows = canon.rows();
1592        let implicit = unsafe { read_rowset(impl_lin, rows) };
1593        let redundant = unsafe { read_rowset(redset, rows) };
1594        let positions = unsafe { read_rowindex(newpos, rows) };
1595
1596        unsafe {
1597            N::set_free(impl_lin);
1598            N::set_free(redset);
1599            libc::free(newpos.cast());
1600        }
1601        mem::forget(clone);
1602
1603        Ok(CanonicalForm {
1604            matrix: canon,
1605            implicit_linearity: implicit,
1606            redundant_rows: redundant,
1607            positions,
1608        })
1609    }
1610}
1611
1612impl<N: CddNumber> Drop for Matrix<N> {
1613    fn drop(&mut self) {
1614        unsafe {
1615            N::dd_free_matrix(self.as_raw());
1616        }
1617    }
1618}
1619
1620#[derive(Debug)]
1621pub struct SetFamily<N: CddNumber = DefaultNumber> {
1622    ptr: NonNull<RawSetFamily>,
1623    _marker: PhantomData<N>,
1624    _no_send_sync: PhantomData<Rc<()>>,
1625}
1626
1627impl<N: CddNumber> SetFamily<N> {
1628    /// # Safety
1629    ///
1630    /// - `ptr` must be a non-null `dd_SetFamilyPtr` compatible with the backend `N`.
1631    /// - The pointer must be valid for the lifetime of this wrapper and must be
1632    ///   owned by this wrapper (it will be freed on drop).
1633    pub unsafe fn from_raw(ptr: *mut c_void) -> Self {
1634        SetFamily {
1635            ptr: NonNull::new(ptr.cast()).expect("from_raw called with null dd_SetFamilyPtr"),
1636            _marker: PhantomData,
1637            _no_send_sync: PhantomData,
1638        }
1639    }
1640
1641    pub fn as_raw(&self) -> *mut c_void {
1642        self.ptr.as_ptr().cast()
1643    }
1644
1645    pub fn len(&self) -> usize {
1646        unsafe { self.ptr.as_ref().famsize as usize }
1647    }
1648
1649    pub fn is_empty(&self) -> bool {
1650        self.len() == 0
1651    }
1652
1653    pub fn universe_size(&self) -> usize {
1654        unsafe { self.ptr.as_ref().setsize as usize }
1655    }
1656
1657    pub fn to_adjacency_lists(&self) -> Vec<Vec<usize>> {
1658        let n = self.len();
1659        let universe = self.universe_size();
1660        let mut result = Vec::with_capacity(n);
1661
1662        for i in 0..n {
1663            let set = unsafe { *self.ptr.as_ref().set.add(i) };
1664            let neighbors = unsafe { set_members_bounded(set, universe) };
1665            result.push(neighbors);
1666        }
1667
1668        result
1669    }
1670}
1671
1672impl<N: CddNumber> Drop for SetFamily<N> {
1673    fn drop(&mut self) {
1674        unsafe {
1675            N::dd_free_set_family(self.as_raw());
1676        }
1677    }
1678}
1679
1680#[derive(Debug)]
1681pub struct Polyhedron<N: CddNumber = DefaultNumber> {
1682    ptr: NonNull<c_void>,
1683    _marker: PhantomData<N>,
1684    _no_send_sync: PhantomData<Rc<()>>,
1685}
1686
1687impl<N: CddNumber> Polyhedron<N> {
1688    pub fn from_matrix(m: &Matrix<N>) -> CddResult<Self> {
1689        N::ensure_initialized();
1690        let mut err = N::dd_no_error();
1691        let ptr = unsafe { N::dd_matrix2poly(m.as_raw(), &mut err) };
1692        let err = CddErrorCode::from_raw(err);
1693        if err != CddErrorCode::NoError {
1694            return Err(CddError::Cdd(err).into());
1695        }
1696        let ptr = NonNull::new(ptr).ok_or(CddError::NullPointer)?;
1697        Ok(Polyhedron {
1698            ptr,
1699            _marker: PhantomData,
1700            _no_send_sync: PhantomData,
1701        })
1702    }
1703
1704    pub fn from_generators_matrix(m: &Matrix<N>) -> CddResult<Self> {
1705        Self::from_matrix(m)
1706    }
1707
1708    pub fn from_inequalities_matrix(m: &Matrix<N>) -> CddResult<Self> {
1709        Self::from_matrix(m)
1710    }
1711
1712    pub fn from_vertices<const D: usize>(vertices: &[[N; D]]) -> CddResult<Self> {
1713        let m = Matrix::<N>::from_vertices(vertices)?;
1714        Self::from_generators_matrix(&m)
1715    }
1716
1717    pub fn from_vertex_rows(vertices: &[Vec<N>]) -> CddResult<Self> {
1718        let m = Matrix::<N>::from_vertex_rows(vertices)?;
1719        Self::from_generators_matrix(&m)
1720    }
1721
1722    pub fn facets(&self) -> CddResult<Matrix<N>> {
1723        let ptr = unsafe { N::dd_copy_inequalities(self.ptr.as_ptr()) };
1724        let ptr = NonNull::new(ptr).ok_or(CddError::NullPointer)?;
1725        Ok(unsafe { Matrix::<N>::from_raw(ptr.as_ptr()) })
1726    }
1727
1728    pub fn generators(&self) -> CddResult<Matrix<N>> {
1729        let ptr = unsafe { N::dd_copy_generators(self.ptr.as_ptr()) };
1730        let ptr = NonNull::new(ptr).ok_or(CddError::NullPointer)?;
1731        Ok(unsafe { Matrix::<N>::from_raw(ptr.as_ptr()) })
1732    }
1733
1734    pub fn adjacency(&self) -> CddResult<SetFamily<N>> {
1735        let ptr = unsafe { N::dd_copy_adjacency(self.ptr.as_ptr()) };
1736        let ptr = NonNull::new(ptr).ok_or(CddError::NullPointer)?;
1737        Ok(unsafe { SetFamily::<N>::from_raw(ptr.as_ptr()) })
1738    }
1739
1740    pub fn input_adjacency(&self) -> CddResult<SetFamily<N>> {
1741        let ptr = unsafe { N::dd_copy_input_adjacency(self.ptr.as_ptr()) };
1742        let ptr = NonNull::new(ptr).ok_or(CddError::NullPointer)?;
1743        Ok(unsafe { SetFamily::<N>::from_raw(ptr.as_ptr()) })
1744    }
1745
1746    pub fn incidence(&self) -> CddResult<SetFamily<N>> {
1747        let ptr = unsafe { N::dd_copy_incidence(self.ptr.as_ptr()) };
1748        let ptr = NonNull::new(ptr).ok_or(CddError::NullPointer)?;
1749        Ok(unsafe { SetFamily::<N>::from_raw(ptr.as_ptr()) })
1750    }
1751
1752    pub fn input_incidence(&self) -> CddResult<SetFamily<N>> {
1753        let ptr = unsafe { N::dd_copy_input_incidence(self.ptr.as_ptr()) };
1754        let ptr = NonNull::new(ptr).ok_or(CddError::NullPointer)?;
1755        Ok(unsafe { SetFamily::<N>::from_raw(ptr.as_ptr()) })
1756    }
1757
1758    pub fn append_input_rows(&mut self, rows: &Matrix<N>) -> CddResult<()> {
1759        let mut raw = self.ptr.as_ptr();
1760        let ok = unsafe { N::dd_append_matrix2poly(&mut raw, rows.as_raw()) };
1761        if ok == 0 {
1762            return Err(CddError::OpFailed.into());
1763        }
1764        if raw != self.ptr.as_ptr() {
1765            self.ptr = NonNull::new(raw).ok_or(CddError::NullPointer)?;
1766        }
1767        Ok(())
1768    }
1769}
1770
1771impl<N: CddNumber> Drop for Polyhedron<N> {
1772    fn drop(&mut self) {
1773        unsafe {
1774            N::dd_free_polyhedra(self.ptr.as_ptr());
1775        }
1776    }
1777}
1778
1779#[derive(Debug)]
1780pub struct Lp<N: CddNumber = DefaultNumber> {
1781    ptr: NonNull<c_void>,
1782    _marker: PhantomData<N>,
1783    _no_send_sync: PhantomData<Rc<()>>,
1784}
1785
1786#[derive(Debug)]
1787pub struct LpSolution<N: CddNumber = DefaultNumber> {
1788    ptr: NonNull<c_void>,
1789    _marker: PhantomData<N>,
1790    _no_send_sync: PhantomData<Rc<()>>,
1791}
1792
1793impl<N: CddNumber> Lp<N> {
1794    pub fn from_matrix(matrix: &mut Matrix<N>, objective: LpObjective) -> CddResult<Self> {
1795        N::ensure_initialized();
1796        unsafe {
1797            matrix.ptr.as_mut().objective = objective.to_raw();
1798        }
1799        let mut err = N::dd_no_error();
1800        let ptr = unsafe { N::dd_matrix2lp(matrix.as_raw(), &mut err) };
1801        let err = CddErrorCode::from_raw(err);
1802        if err != CddErrorCode::NoError {
1803            return Err(CddError::Cdd(err).into());
1804        }
1805        let ptr = NonNull::new(ptr).ok_or(CddError::NullPointer)?;
1806        Ok(Lp {
1807            ptr,
1808            _marker: PhantomData,
1809            _no_send_sync: PhantomData,
1810        })
1811    }
1812
1813    pub fn solve(&self) -> CddResult<LpSolution<N>> {
1814        N::ensure_initialized();
1815
1816        let mut err = N::dd_no_error();
1817        let ok = unsafe { N::dd_lp_solve_dual_simplex(self.ptr.as_ptr(), &mut err) };
1818        let err = CddErrorCode::from_raw(err);
1819        if err != CddErrorCode::NoError {
1820            return Err(CddError::Cdd(err).into());
1821        }
1822        if ok == 0 {
1823            return Err(CddError::LpError.into());
1824        }
1825        let status = unsafe { N::lp_status_raw(self.ptr.as_ptr()) };
1826        let status = LpStatus::from_raw(status);
1827        if status != LpStatus::Optimal {
1828            return Err(CddError::LpStatus(status).into());
1829        }
1830        let sol_ptr = unsafe { N::dd_copy_lp_solution(self.ptr.as_ptr()) };
1831        let sol_ptr = NonNull::new(sol_ptr).ok_or(CddError::NullPointer)?;
1832        Ok(LpSolution {
1833            ptr: sol_ptr,
1834            _marker: PhantomData,
1835            _no_send_sync: PhantomData,
1836        })
1837    }
1838}
1839
1840impl<N: CddNumber> Drop for Lp<N> {
1841    fn drop(&mut self) {
1842        unsafe {
1843            N::dd_free_lp_data(self.ptr.as_ptr());
1844        }
1845    }
1846}
1847
1848impl<N: CddNumber> LpSolution<N> {
1849    pub fn opt_value_real(&self) -> f64 {
1850        unsafe {
1851            let opt_ptr = N::lp_solution_optvalue_ptr(self.ptr.as_ptr());
1852            N::read_mytype_real(opt_ptr)
1853        }
1854    }
1855}
1856
1857impl<N: CddNumber> Drop for LpSolution<N> {
1858    fn drop(&mut self) {
1859        unsafe {
1860            N::dd_free_lp_solution(self.ptr.as_ptr());
1861        }
1862    }
1863}
1864
1865pub fn width_in_direction_real<N: CddNumber>(
1866    poly: &Polyhedron<N>,
1867    direction: &[f64],
1868) -> CddResult<f64> {
1869    let mut h_min = poly.facets()?;
1870    let mut h_max = h_min.clone_cdd()?;
1871
1872    if direction.len() + 1 != h_max.cols() {
1873        return Err(CddWrapperError::InvalidMatrix {
1874            rows: h_max.rows(),
1875            cols: h_max.cols(),
1876        });
1877    }
1878
1879    let cols = h_max.cols();
1880    let mut coeffs = vec![0.0f64; cols];
1881
1882    for (i, &u_i) in direction.iter().enumerate() {
1883        coeffs[i + 1] = u_i;
1884    }
1885
1886    h_max.set_objective_real(&coeffs);
1887    let lp_max = Lp::<N>::from_matrix(&mut h_max, LpObjective::Maximize)?;
1888    let sol_max = lp_max.solve()?;
1889    let max_val = sol_max.opt_value_real();
1890
1891    h_min.set_objective_real(&coeffs);
1892    let lp_min = Lp::<N>::from_matrix(&mut h_min, LpObjective::Minimize)?;
1893    let sol_min = lp_min.solve()?;
1894    let min_val = sol_min.opt_value_real();
1895
1896    Ok(max_val - min_val)
1897}
1898
1899#[cfg(feature = "f64")]
1900pub type MatrixF64 = Matrix<f64>;
1901#[cfg(feature = "f64")]
1902pub type PolyhedronF64 = Polyhedron<f64>;
1903
1904#[cfg(feature = "gmp")]
1905pub type MatrixGmpFloat = Matrix<CddFloat>;
1906#[cfg(feature = "gmp")]
1907pub type PolyhedronGmpFloat = Polyhedron<CddFloat>;
1908
1909#[cfg(feature = "gmprational")]
1910pub type MatrixGmpRational = Matrix<CddRational>;
1911#[cfg(feature = "gmprational")]
1912pub type PolyhedronGmpRational = Polyhedron<CddRational>;
1913
1914impl<N: CddNumber> Matrix<N> {
1915    pub fn convert<M: CddNumber>(&self) -> CddResult<Matrix<M>> {
1916        convert_matrix_via_real::<N, M>(self)
1917    }
1918}
1919
1920#[cfg(all(feature = "f64", feature = "gmp"))]
1921impl From<Matrix<f64>> for Matrix<CddFloat> {
1922    fn from(value: Matrix<f64>) -> Self {
1923        value
1924            .convert()
1925            .expect("Matrix<f64> -> Matrix<CddFloat> conversion failed")
1926    }
1927}
1928
1929#[cfg(all(feature = "f64", feature = "gmprational"))]
1930impl From<Matrix<f64>> for Matrix<CddRational> {
1931    fn from(value: Matrix<f64>) -> Self {
1932        value
1933            .convert()
1934            .expect("Matrix<f64> -> Matrix<CddRational> conversion failed")
1935    }
1936}
1937
1938#[cfg(all(feature = "f64", feature = "gmp"))]
1939impl From<Matrix<CddFloat>> for Matrix<f64> {
1940    fn from(value: Matrix<CddFloat>) -> Self {
1941        value
1942            .convert()
1943            .expect("Matrix<CddFloat> -> Matrix<f64> conversion failed")
1944    }
1945}
1946
1947#[cfg(all(feature = "f64", feature = "gmprational"))]
1948impl From<Matrix<CddRational>> for Matrix<f64> {
1949    fn from(value: Matrix<CddRational>) -> Self {
1950        value
1951            .convert()
1952            .expect("Matrix<CddRational> -> Matrix<f64> conversion failed")
1953    }
1954}
1955
1956#[cfg(all(feature = "gmp", feature = "gmprational"))]
1957impl From<Matrix<CddFloat>> for Matrix<CddRational> {
1958    fn from(value: Matrix<CddFloat>) -> Self {
1959        value
1960            .convert()
1961            .expect("Matrix<CddFloat> -> Matrix<CddRational> conversion failed")
1962    }
1963}
1964
1965#[cfg(all(feature = "gmp", feature = "gmprational"))]
1966impl From<Matrix<CddRational>> for Matrix<CddFloat> {
1967    fn from(value: Matrix<CddRational>) -> Self {
1968        value
1969            .convert()
1970            .expect("Matrix<CddRational> -> Matrix<CddFloat> conversion failed")
1971    }
1972}
1973
1974fn convert_matrix_via_real<Src: CddNumber, Dst: CddNumber>(
1975    src: &Matrix<Src>,
1976) -> CddResult<Matrix<Dst>> {
1977    let rows = src.rows();
1978    let cols = src.cols();
1979    let mut out = Matrix::<Dst>::new(rows, cols, src.representation(), Dst::DEFAULT_NUMBER_TYPE)?;
1980
1981    for i in 0..rows {
1982        for j in 0..cols {
1983            out.set_real(i, j, src.get_real(i, j));
1984        }
1985    }
1986
1987    unsafe {
1988        out.ptr.as_mut().objective = src.ptr.as_ref().objective;
1989    }
1990
1991    let rowvec = unsafe { src.ptr.as_ref().rowvec };
1992    if !rowvec.is_null() {
1993        let mut coeffs = Vec::with_capacity(cols);
1994        for j in 0..cols {
1995            let cell = unsafe { rowvec_cell::<Src>(rowvec, j) };
1996            coeffs.push(unsafe { Src::read_mytype_real(cell.cast_const()) });
1997        }
1998        out.set_objective_real(&coeffs);
1999    }
2000
2001    Ok(out)
2002}
2003
2004unsafe fn matrix_cell<N: CddNumber>(
2005    matrix: NonNull<RawMatrixData>,
2006    row: usize,
2007    col: usize,
2008) -> *mut c_void {
2009    unsafe {
2010        let matrix_rows = matrix.as_ref().matrix;
2011        assert!(!matrix_rows.is_null(), "matrix rows pointer is null");
2012        let row_ptr = *matrix_rows.add(row);
2013        assert!(!row_ptr.is_null(), "matrix row pointer is null");
2014        row_ptr
2015            .cast::<u8>()
2016            .add(col * N::MYTYPE_SIZE)
2017            .cast::<c_void>()
2018    }
2019}
2020
2021unsafe fn rowvec_cell<N: CddNumber>(rowvec: *mut c_void, col: usize) -> *mut c_void {
2022    unsafe {
2023        rowvec
2024            .cast::<u8>()
2025            .add(col * N::MYTYPE_SIZE)
2026            .cast::<c_void>()
2027    }
2028}
2029
2030unsafe fn read_rowset(set: *mut libc::c_ulong, rows: usize) -> Vec<usize> {
2031    unsafe { set_members_bounded(set, rows) }
2032}
2033
2034unsafe fn set_members_bounded(set: *mut libc::c_ulong, max_elems: usize) -> Vec<usize> {
2035    assert!(!set.is_null(), "set pointer is null");
2036
2037    let ground = unsafe { *set } as usize;
2038    let bound = max_elems.min(ground);
2039    if bound == 0 {
2040        return Vec::new();
2041    }
2042
2043    let bits_per_block = mem::size_of::<libc::c_ulong>() * 8;
2044    let blocks = (bound - 1) / bits_per_block + 1;
2045
2046    let mut out = Vec::new();
2047    for block_idx in 0..blocks {
2048        let mut word = unsafe { *set.add(1 + block_idx) };
2049        let base = block_idx * bits_per_block;
2050        while word != 0 {
2051            let tz = word.trailing_zeros() as usize;
2052            let idx = base + tz;
2053            if idx < bound {
2054                out.push(idx);
2055            }
2056            word &= word - 1;
2057        }
2058    }
2059
2060    out
2061}
2062
2063unsafe fn read_rowindex(index: *mut c_long, rows: usize) -> Vec<isize> {
2064    unsafe {
2065        let mut out = Vec::with_capacity(rows);
2066        for i in 1..=rows {
2067            out.push(*index.add(i) as isize);
2068        }
2069        out
2070    }
2071}