1use 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 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 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 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}