cliffy_test/
generators.rs1use crate::{bivector, vector, GA3};
10use quickcheck::{Arbitrary, Gen};
11
12fn gen_f64_range(g: &mut Gen, min: f64, max: f64) -> f64 {
14 let val: u64 = u64::arbitrary(g);
17 let normalized = (val as f64) / (u64::MAX as f64);
19 min + normalized * (max - min)
20}
21
22pub fn arbitrary_ga3(g: &mut Gen) -> GA3 {
24 let coeffs: Vec<f64> = vec![
25 gen_f64_range(g, -10.0, 10.0), gen_f64_range(g, -10.0, 10.0), gen_f64_range(g, -10.0, 10.0), gen_f64_range(g, -10.0, 10.0), gen_f64_range(g, -10.0, 10.0), gen_f64_range(g, -10.0, 10.0), gen_f64_range(g, -10.0, 10.0), gen_f64_range(g, -10.0, 10.0), ];
34 GA3::from_coefficients(coeffs)
35}
36
37pub fn arbitrary_vector(g: &mut Gen) -> GA3 {
39 vector(
40 gen_f64_range(g, -10.0, 10.0),
41 gen_f64_range(g, -10.0, 10.0),
42 gen_f64_range(g, -10.0, 10.0),
43 )
44}
45
46pub fn arbitrary_unit_vector(g: &mut Gen) -> GA3 {
48 loop {
49 let v = vector(
50 gen_f64_range(g, -1.0, 1.0),
51 gen_f64_range(g, -1.0, 1.0),
52 gen_f64_range(g, -1.0, 1.0),
53 );
54 let mag = v.magnitude();
55 if mag > 0.1 {
56 return v.normalize().unwrap_or_else(GA3::zero);
58 }
59 }
60}
61
62pub fn arbitrary_rotor(g: &mut Gen) -> GA3 {
67 let angle: f64 = gen_f64_range(g, 0.0, std::f64::consts::TAU);
69 let half_angle = angle / 2.0;
70
71 let bx: f64 = gen_f64_range(g, -1.0, 1.0);
73 let by: f64 = gen_f64_range(g, -1.0, 1.0);
74 let bz: f64 = gen_f64_range(g, -1.0, 1.0);
75 let b = bivector(bx, by, bz);
76 let b_mag = b.magnitude();
77
78 if b_mag > 0.1 {
79 let b_unit = b.normalize().unwrap_or_else(GA3::zero);
80
81 let scalar_part = GA3::scalar(half_angle.cos());
83 let bivector_part = &b_unit * half_angle.sin();
84 &scalar_part + &bivector_part
85 } else {
86 GA3::scalar(1.0)
88 }
89}
90
91pub fn arbitrary_bivector(g: &mut Gen) -> GA3 {
93 bivector(
94 gen_f64_range(g, -10.0, 10.0), gen_f64_range(g, -10.0, 10.0), gen_f64_range(g, -10.0, 10.0), )
98}
99
100#[derive(Clone, Debug)]
102pub struct ArbitraryGA3(pub GA3);
103
104impl Arbitrary for ArbitraryGA3 {
105 fn arbitrary(g: &mut Gen) -> Self {
106 ArbitraryGA3(arbitrary_ga3(g))
107 }
108
109 fn shrink(&self) -> Box<dyn Iterator<Item = Self>> {
110 let mv = self.0.clone();
112 let mag = mv.magnitude();
113 if mag < 0.01 {
114 Box::new(std::iter::empty())
115 } else {
116 let shrunk = &mv * 0.5;
117 Box::new(std::iter::once(ArbitraryGA3(shrunk)))
118 }
119 }
120}
121
122#[derive(Clone, Debug)]
124pub struct ArbitraryVector(pub GA3);
125
126impl Arbitrary for ArbitraryVector {
127 fn arbitrary(g: &mut Gen) -> Self {
128 ArbitraryVector(arbitrary_vector(g))
129 }
130}
131
132#[derive(Clone, Debug)]
134pub struct ArbitraryUnitVector(pub GA3);
135
136impl Arbitrary for ArbitraryUnitVector {
137 fn arbitrary(g: &mut Gen) -> Self {
138 ArbitraryUnitVector(arbitrary_unit_vector(g))
139 }
140}
141
142#[derive(Clone, Debug)]
144pub struct ArbitraryRotor(pub GA3);
145
146impl Arbitrary for ArbitraryRotor {
147 fn arbitrary(g: &mut Gen) -> Self {
148 ArbitraryRotor(arbitrary_rotor(g))
149 }
150}
151
152#[cfg(test)]
153mod tests {
154 use super::*;
155
156 #[test]
157 fn test_arbitrary_vector() {
158 let mut gen = Gen::new(10);
159 let v = arbitrary_vector(&mut gen);
160 assert!(v.get(0).abs() < 1e-10); assert!(v.get(3).abs() < 1e-10); assert!(v.get(5).abs() < 1e-10); assert!(v.get(6).abs() < 1e-10); assert!(v.get(7).abs() < 1e-10); }
167
168 #[test]
169 fn test_arbitrary_unit_vector() {
170 let mut gen = Gen::new(10);
171 for _ in 0..10 {
172 let v = arbitrary_unit_vector(&mut gen);
173 let mag = v.magnitude();
174 assert!((mag - 1.0).abs() < 1e-10, "Unit vector magnitude: {}", mag);
175 }
176 }
177
178 #[test]
179 fn test_arbitrary_rotor_is_unit() {
180 let mut gen = Gen::new(10);
181 for _ in 0..10 {
182 let r = arbitrary_rotor(&mut gen);
183 let norm_sq = r.geometric_product(&r.reverse()).get(0);
185 assert!(
186 (norm_sq - 1.0).abs() < 0.1,
187 "Rotor norm squared: {}",
188 norm_sq
189 );
190 }
191 }
192
193 #[test]
194 fn test_quickcheck_arbitrary() {
195 fn prop_magnitude_positive(v: ArbitraryVector) -> bool {
196 v.0.magnitude() >= 0.0
197 }
198
199 quickcheck::quickcheck(prop_magnitude_positive as fn(ArbitraryVector) -> bool);
200 }
201}