rgsl/types/combination.rs
1//
2// A rust binding for the GSL library by Guillaume Gomez (guillaume1.gomez@gmail.com)
3//
4
5/*!
6# Combinations
7
8This chapter describes functions for creating and manipulating combinations. A combination c is
9represented by an array of k integers in the range 0 to n-1, where each value c_i occurs at most
10once. The combination c corresponds to indices of k elements chosen from an n element vector.
11Combinations are useful for iterating over all k-element subsets of a set.
12
13## References and Further Reading
14
15Further information on combinations can be found in,
16
17Donald L. Kreher, Douglas R. Stinson, Combinatorial Algorithms: Generation, Enumeration and Search,
181998, CRC Press LLC, ISBN 084933988X
19!*/
20
21use crate::Value;
22use ffi::FFI;
23use std::fmt::{self, Debug, Formatter};
24
25ffi_wrapper!(Combination, *mut sys::gsl_combination, gsl_combination_free);
26
27impl Combination {
28 /// This function allocates memory for a new combination with parameters n, k. The combination
29 /// is not initialized and its elements are undefined. Use the function
30 /// `Combination::new_init_first` if you want to create a combination which is initialized to
31 /// the lexicographically first combination. A null pointer is returned if insufficient memory
32 /// is available to create the combination.
33 #[doc(alias = "gsl_combination_alloc")]
34 pub fn new(n: usize, k: usize) -> Option<Self> {
35 let tmp = unsafe { sys::gsl_combination_alloc(n, k) };
36
37 if tmp.is_null() {
38 None
39 } else {
40 Some(Self::wrap(tmp))
41 }
42 }
43
44 /// This function allocates memory for a new combination with parameters n, k and initializes it
45 /// to the lexicographically first combination. A null pointer is returned if insufficient
46 /// memory is available to create the combination.
47 #[doc(alias = "gsl_combination_calloc")]
48 pub fn new_with_init(n: usize, k: usize) -> Option<Self> {
49 let tmp = unsafe { sys::gsl_combination_calloc(n, k) };
50
51 if tmp.is_null() {
52 None
53 } else {
54 Some(Self::wrap(tmp))
55 }
56 }
57
58 /// This function initializes the combination c to the lexicographically first combination, i.e.
59 /// (0,1,2,...,k-1).
60 #[doc(alias = "gsl_combination_init_first")]
61 pub fn init_first(&mut self) {
62 unsafe { sys::gsl_combination_init_first(self.unwrap_unique()) }
63 }
64
65 /// This function initializes the combination c to the lexicographically last combination, i.e.
66 /// (n-k,n-k+1,…,n-1).
67 #[doc(alias = "gsl_combination_init_last")]
68 pub fn init_last(&mut self) {
69 unsafe { sys::gsl_combination_init_last(self.unwrap_unique()) }
70 }
71
72 /// This function copies the elements of the combination self into the combination dest. The two
73 /// combinations must have the same size.
74 #[doc(alias = "gsl_combination_memcpy")]
75 pub fn copy(&self, dest: &mut Combination) -> Result<(), Value> {
76 let ret =
77 unsafe { sys::gsl_combination_memcpy(dest.unwrap_unique(), self.unwrap_shared()) };
78 result_handler!(ret, ())
79 }
80
81 /// This function returns the value of the i-th element of the combination self. If i lies
82 /// outside the allowed range of 0 to k-1 then the error handler is invoked and 0 is returned.
83 #[doc(alias = "gsl_combination_get")]
84 pub fn get(&self, i: usize) -> usize {
85 unsafe { sys::gsl_combination_get(self.unwrap_shared(), i) }
86 }
87
88 /// This function returns the range (n) of the combination self.
89 #[doc(alias = "gsl_combination_n")]
90 pub fn n(&self) -> usize {
91 unsafe { sys::gsl_combination_n(self.unwrap_shared()) }
92 }
93
94 /// This function returns the number of elements (k) in the combination self.
95 #[doc(alias = "gsl_combination_k")]
96 pub fn k(&self) -> usize {
97 unsafe { sys::gsl_combination_k(self.unwrap_shared()) }
98 }
99
100 // checker:ignore
101 #[doc(alias = "gsl_combination_data")]
102 pub fn as_slice(&self) -> &[usize] {
103 unsafe {
104 let data = sys::gsl_combination_data(self.unwrap_shared());
105 std::slice::from_raw_parts(data, self.k())
106 }
107 }
108
109 // checker:ignore
110 #[doc(alias = "gsl_combination_data")]
111 pub fn as_mut_slice(&mut self) -> &mut [usize] {
112 unsafe {
113 let data = sys::gsl_combination_data(self.unwrap_shared());
114 std::slice::from_raw_parts_mut(data, self.k())
115 }
116 }
117
118 /// This function checks that the combination self is valid. The k elements should lie in the
119 /// range 0 to n-1, with each value occurring once at most and in increasing order.
120 // checker:ignore
121 #[doc(alias = "gsl_combination_valid")]
122 pub fn is_valid(&self) -> Result<(), Value> {
123 // Little hack because `gsl_combination_valid` doesn't in fact need a mutable object...
124 let ret = unsafe { sys::gsl_combination_valid(self.inner) };
125 result_handler!(ret, ())
126 }
127
128 /// This function advances the combination self to the next combination in lexicographic order
129 /// and returns `Success`. If no further combinations are available it returns Failure and
130 /// leaves self unmodified. Starting with the first combination and repeatedly applying this
131 /// function will iterate through all possible combinations of a given order.
132 #[doc(alias = "gsl_combination_next")]
133 pub fn next(&mut self) -> Result<(), Value> {
134 let ret = unsafe { sys::gsl_combination_next(self.unwrap_unique()) };
135 result_handler!(ret, ())
136 }
137
138 /// This function steps backwards from the combination self to the previous combination in
139 /// lexicographic order, returning `Success`. If no previous combination is available it returns
140 /// `Failure` and leaves self unmodified.
141 #[doc(alias = "gsl_combination_prev")]
142 pub fn prev(&mut self) -> Result<(), Value> {
143 let ret = unsafe { sys::gsl_combination_prev(self.unwrap_unique()) };
144 result_handler!(ret, ())
145 }
146}
147
148impl Debug for Combination {
149 #[allow(unused_must_use)]
150 fn fmt(&self, f: &mut Formatter) -> fmt::Result {
151 write!(f, "[");
152 let s = self.as_slice();
153 for (pos, v) in s.iter().enumerate() {
154 if pos == 0 {
155 write!(f, "{}", v).unwrap();
156 } else {
157 write!(f, " {}", v).unwrap();
158 }
159 }
160 write!(f, "]")
161 }
162}