1use std::alloc::*;
2use std::borrow::Borrow;
3
4use crate::algorithms::convolution::STANDARD_CONVOLUTION;
5use crate::computation::*;
6use crate::homomorphism::*;
7use crate::matrix::OwnedMatrix;
8use crate::rings::extension::galois_field::*;
9use crate::rings::extension::number_field::*;
10use crate::pid::*;
11use crate::primitive_int::StaticRing;
12use crate::rings::extension::extension_impl::*;
13use crate::rings::extension::*;
14use crate::rings::field::{AsField, AsFieldBase};
15use crate::rings::finite::FiniteRingStore;
16use crate::rings::multivariate::{MultivariatePolyRing, MultivariatePolyRingStore};
17use crate::rings::poly::dense_poly::DensePolyRing;
18use crate::rings::poly::*;
19use crate::divisibility::*;
20use crate::field::*;
21use crate::seq::sparse::SparseMapVector;
22use crate::MAX_PROBABILISTIC_REPETITIONS;
23use crate::integer::*;
24use crate::seq::*;
25use crate::ring::*;
26use crate::algorithms::linsolve::*;
27use super::poly_factor::FactorPolyField;
28use super::poly_gcd::PolyTFracGCDRing;
29
30#[stability::unstable(feature = "enable")]
43pub fn extend_number_field<K, Controller>(poly_ring: DensePolyRing<K>, irred_poly: &El<DensePolyRing<K>>, controller: Controller) -> (
44 FreeAlgebraHom<K, NumberField>,
45 El<NumberField>
46)
47 where K: RingStore<Type = NumberFieldBase<DefaultNumberFieldImpl, BigIntRing>>,
48 Controller: ComputationController
49{
50 assert!(!poly_ring.is_zero(&irred_poly));
51 assert!(poly_ring.degree(&irred_poly).unwrap() > 1);
52 assert!(<NumberFieldBase<_, _> as FactorPolyField>::is_irred(&poly_ring, irred_poly));
53
54 extend_number_field_promise_is_irreducible(poly_ring, irred_poly, controller)
55}
56
57fn test_primitive_element<R>(L: R, potential_primitive_element: El<R>) -> Option<(
64 DensePolyRing<<<<R::Type as RingExtension>::BaseRing as RingStore>::Type as RingExtension>::BaseRing>,
65 El<DensePolyRing<<<<R::Type as RingExtension>::BaseRing as RingStore>::Type as RingExtension>::BaseRing>>,
66 El<DensePolyRing<<<<R::Type as RingExtension>::BaseRing as RingStore>::Type as RingExtension>::BaseRing>>,
67 El<DensePolyRing<<<<R::Type as RingExtension>::BaseRing as RingStore>::Type as RingExtension>::BaseRing>>
68)>
69 where R: RingStore,
70 R::Type: FreeAlgebra,
71 <<R::Type as RingExtension>::BaseRing as RingStore>::Type: FreeAlgebra,
72 <<<R::Type as RingExtension>::BaseRing as RingStore>::Type as RingExtension>::BaseRing: Clone,
73 <<<<R::Type as RingExtension>::BaseRing as RingStore>::Type as RingExtension>::BaseRing as RingStore>::Type: LinSolveRing
74{
75 let K = L.base_ring();
76 let k = K.base_ring();
77 let total_rank = L.rank() * K.rank();
78
79 let mut lhs = OwnedMatrix::zero(total_rank, total_rank, k);
81 let mut current = L.one();
82 for j in 0..total_rank {
83 let current_wrt_basis = L.wrt_canonical_basis(¤t);
84 for i1 in 0..L.rank() {
85 let c = current_wrt_basis.at(i1);
86 let c_wrt_basis = K.wrt_canonical_basis(&c);
87 for i2 in 0..K.rank() {
88 *lhs.at_mut(i1 * K.rank() + i2, j) = c_wrt_basis.at(i2);
89 }
90 }
91 drop(current_wrt_basis);
92 L.mul_assign_ref(&mut current, &potential_primitive_element);
93 }
94
95 let mut rhs = OwnedMatrix::zero(total_rank, 3, k);
100 let current_wrt_basis = L.wrt_canonical_basis(¤t);
101 for i1 in 0..L.rank() {
102 let c = current_wrt_basis.at(i1);
103 let c_wrt_basis = K.wrt_canonical_basis(&c);
104 for i2 in 0..K.rank() {
105 *rhs.at_mut(i1 * K.rank() + i2, 0) = c_wrt_basis.at(i2);
106 }
107 }
108 if K.rank() > 1 {
109 *rhs.at_mut(1, 1) = k.one();
110 } else {
111 *rhs.at_mut(0, 1) = K.wrt_canonical_basis(&K.canonical_gen()).at(0);
112 }
113 *rhs.at_mut(K.rank(), 2) = k.one();
114
115 let mut sol = OwnedMatrix::zero(total_rank, 3, k);
116 let has_sol = k.solve_right(lhs.data_mut(), rhs.data_mut(), sol.data_mut()).is_solved();
117
118 if has_sol {
119 let kX = DensePolyRing::new(k.clone(), "X");
120 let gen_poly = kX.from_terms((0..total_rank).map(|i| (k.negate(k.clone_el(sol.at(i, 0))), i)).chain([(k.one(), total_rank)].into_iter()));
121 let K_generator = kX.from_terms((0..total_rank).map(|i| (k.clone_el(sol.at(i, 1)), i)));
122 let L_generator = kX.from_terms((0..total_rank).map(|i| (k.clone_el(sol.at(i, 2)), i)));
123 return Some((
124 kX,
125 gen_poly,
126 K_generator,
127 L_generator
128 ));
129 } else {
130 return None;
131 }
132}
133
134#[stability::unstable(feature = "enable")]
135pub fn extend_galois_field<K>(poly_ring: DensePolyRing<K>, irred_poly: &El<DensePolyRing<K>>) -> (
136 FreeAlgebraHom<K, GaloisField>,
137 El<GaloisField>
138)
139 where K: RingStore<Type = GaloisFieldBase<DefaultGaloisFieldImpl>>
140{
141
142 assert!(!poly_ring.is_zero(&irred_poly));
143 assert!(poly_ring.degree(&irred_poly).unwrap() > 1);
144
145 let K = poly_ring.base_ring();
151 let Fp = K.base_ring();
152
153 let L = AsField::from(
154 AsFieldBase::promise_is_perfect_field(
155 FreeAlgebraImpl::new_with_convolution(
156 K,
157 poly_ring.degree(&irred_poly).unwrap(),
158 (0..poly_ring.degree(&irred_poly).unwrap()).map(|i| K.negate(K.clone_el(poly_ring.coefficient_at(&irred_poly, i)))).collect::<Vec<_>>(),
159 "X",
160 Global,
161 STANDARD_CONVOLUTION
162 )
163 )
164 );
165 let total_rank = L.rank() * K.rank();
166
167 let mut rng = oorandom::Rand64::new(1);
168
169 for _ in 0..MAX_PROBABILISTIC_REPETITIONS {
170 let potential_primitive_element = L.random_element(|| rng.rand_u64());
171
172 if let Some((FpX, gen_poly, K_gen, L_gen)) = test_primitive_element(&L, potential_primitive_element) {
173
174 let mut modulus = SparseMapVector::new(total_rank, Fp.clone());
175 for (x, i) in FpX.terms(&gen_poly).filter(|(_, i)| *i < total_rank) {
176 *modulus.at_mut(i) = Fp.clone_el(x);
177 }
178 _ = modulus.at_mut(0);
179 let potential_result = FreeAlgebraImpl::new(
180 Fp.clone(),
181 total_rank,
182 modulus
183 );
184
185 if let Ok(result) = potential_result.as_field() {
186 let result = GaloisField::create(result);
187
188 let K_generator = result.from_canonical_basis((0..total_rank).map(|i| Fp.clone_el(FpX.coefficient_at(&K_gen, i))));
190 let L_generator = result.from_canonical_basis((0..total_rank).map(|i| Fp.clone_el(FpX.coefficient_at(&L_gen, i))));
191
192 let result = FreeAlgebraHom::promise_is_well_defined(poly_ring.into().into_base_ring(), result, K_generator);
193 return (result, L_generator);
194 }
195 }
196 }
197 unreachable!()
198}
199
200#[stability::unstable(feature = "enable")]
213pub fn extend_number_field_promise_is_irreducible<K, Controller>(poly_ring: DensePolyRing<K>, irred_poly: &El<DensePolyRing<K>>, controller: Controller) -> (
214 FreeAlgebraHom<K, NumberField>,
215 El<NumberField>
216)
217 where K: RingStore<Type = NumberFieldBase<DefaultNumberFieldImpl, BigIntRing>>,
218 Controller: ComputationController
219{
220 static_assert_impls!(NumberFieldBase<DefaultNumberFieldImpl, BigIntRing>: FactorPolyField);
221 static_assert_impls!(NumberFieldBase<DefaultNumberFieldImpl, BigIntRing>: PolyTFracGCDRing);
222
223 assert!(!poly_ring.is_zero(&irred_poly));
224 assert!(poly_ring.degree(&irred_poly).unwrap() > 1);
225
226 controller.run_computation(format_args!("extend_number_field(deg={}, extdeg={})", poly_ring.base_ring().rank(), poly_ring.degree(irred_poly).unwrap()), |controller| {
227
228 let K = poly_ring.base_ring();
229
230 let L = AsField::from(
231 AsFieldBase::promise_is_perfect_field(
232 FreeAlgebraImpl::new_with_convolution(
233 K,
234 poly_ring.degree(&irred_poly).unwrap(),
235 (0..poly_ring.degree(&irred_poly).unwrap()).map(|i| K.negate(K.clone_el(poly_ring.coefficient_at(&irred_poly, i)))).collect::<Vec<_>>(),
236 "X",
237 Global,
238 STANDARD_CONVOLUTION
239 )
240 )
241 );
242
243 let total_rank = K.rank() * L.rank();
244
245 let size_of_A: i32 = (2 * total_rank).try_into().unwrap();
259
260 let mut rng = oorandom::Rand64::new(1);
261
262 for _ in 0..MAX_PROBABILISTIC_REPETITIONS {
263
264 let a = StaticRing::<i32>::RING.get_uniformly_random(&size_of_A, || rng.rand_u64());
265 let potential_primitive_element = L.add(L.canonical_gen(), L.inclusion().map(K.int_hom().mul_map(K.canonical_gen(), a)));
266
267 if let Some((QQX, gen_poly, K_gen, L_gen)) = test_primitive_element(&L, potential_primitive_element) {
268 if let Some((result, x)) = NumberField::try_adjoin_root(&QQX, &gen_poly) {
269
270 let K_generator = QQX.evaluate(&K_gen, &x, result.inclusion());
272 let L_generator = QQX.evaluate(&L_gen, &x, result.inclusion());
273
274 let result = FreeAlgebraHom::promise_is_well_defined(poly_ring.into().into_base_ring(), result, K_generator);
275
276 log_progress!(controller, "success");
277 return (result, L_generator);
278 } else {
279 unreachable!()
280 }
281 } else {
282 log_progress!(controller, "(not_primitive)");
283 }
284 }
285
286 unreachable!()
287})
288}
289
290#[stability::unstable(feature = "enable")]
301pub fn splitting_field<K, F, Controller>(
302 mut poly_ring: DensePolyRing<K>,
303 f: El<DensePolyRing<K>>,
304 mut create_field: F,
305 controller: Controller
306) -> (
307 FreeAlgebraHom<K, K>,
308 Vec<(El<K>, usize)>
309)
310 where K: RingStore + Clone,
311 K::Type: FactorPolyField + FreeAlgebra,
312 F: for<'a> FnMut(DensePolyRing<&'a K>, El<DensePolyRing<&'a K>>, Controller) -> (FreeAlgebraHom<&'a K, K>, El<K>),
313 Controller: ComputationController
314{
315 assert!(!poly_ring.is_zero(&f));
316 let mut to_split = vec![(f, 1)];
317 let mut roots = Vec::new();
318 let mut base_field = None;
319 let mut image_of_base_can_gen = poly_ring.base_ring().canonical_gen();
320
321 controller.run_computation(format_args!("splitting_field(base_deg={}, deg={})", poly_ring.base_ring().rank(), poly_ring.degree(&to_split[0].0).unwrap()), |controller| {
322
323 while let Some((next_to_split, multiplicity)) = to_split.pop() {
324 let (mut factorization, _) = <_ as FactorPolyField>::factor_poly_with_controller(&poly_ring, &next_to_split, controller.clone());
325 let extend_idx = factorization.iter().enumerate().max_by_key(|(_, (f, _))| poly_ring.degree(f).unwrap()).unwrap().0;
326
327 let extend_with_poly = if poly_ring.degree(&factorization[extend_idx].0).unwrap() > 1 {
328 Some(factorization.remove(extend_idx))
329 } else {
330 None
331 };
332
333 for (g, e) in factorization.into_iter() {
334 if poly_ring.degree(&g).unwrap() > 1 {
335 to_split.push((g, e * multiplicity));
336 } else {
337 roots.push((poly_ring.base_ring().negate(poly_ring.base_ring().div(poly_ring.coefficient_at(&g, 0), poly_ring.coefficient_at(&g, 1))), e * multiplicity));
338 }
339 }
340
341 if let Some((extend_with_poly, e)) = extend_with_poly {
342 log_progress!(controller, "({})", poly_ring.degree(&extend_with_poly).unwrap());
343 let ref_poly_ring = DensePolyRing::new(poly_ring.base_ring(), "X");
344 let ref_extend_with_poly = ref_poly_ring.lifted_hom(&poly_ring, poly_ring.base_ring().identity()).map_ref(&extend_with_poly);
345 let (into_new_field, root) = create_field(ref_poly_ring, ref_extend_with_poly, controller.clone());
346 let (old_field, new_field, image) = into_new_field.destruct();
347 let new_poly_ring = DensePolyRing::new(new_field, "X");
348 let into_new_field = FreeAlgebraHom::promise_is_well_defined(old_field, new_poly_ring.base_ring(), image);
349
350 image_of_base_can_gen = into_new_field.map(image_of_base_can_gen);
351 roots = roots.into_iter().map(|(r, e)| (into_new_field.map(r), e)).collect();
352 let lifted_hom = new_poly_ring.lifted_hom(&poly_ring, &into_new_field);
353 to_split = to_split.into_iter().map(|(f, e)| (lifted_hom.map(f), e)).collect();
354
355 to_split.push((new_poly_ring.checked_div(
356 &lifted_hom.map(extend_with_poly),
357 &new_poly_ring.sub(new_poly_ring.indeterminate(), new_poly_ring.inclusion().map_ref(&root))
358 ).unwrap(), multiplicity * e));
359 roots.push((root, multiplicity * e));
360
361 if base_field.is_none() {
362 base_field = Some(poly_ring.into().into_base_ring());
363 }
364 poly_ring = new_poly_ring;
365 }
366 }
367 return (
368 FreeAlgebraHom::promise_is_well_defined(
369 base_field.unwrap_or_else(|| poly_ring.clone().into().into_base_ring()),
370 poly_ring.into().into_base_ring(),
371 image_of_base_can_gen
372 ),
373 roots
374 );
375})
376}
377
378#[stability::unstable(feature = "enable")]
384pub fn variety_from_lex_gb<K, P, F, Controller>(
385 poly_ring: P,
386 lex_gb: &[El<P>],
387 mut create_field: F,
388 controller: Controller
389) -> (FreeAlgebraHom<K, K>, Vec<Vec<El<K>>>)
390 where P: RingStore,
391 K: RingStore + Clone,
392 K::Type: FactorPolyField + FreeAlgebra,
393 P::Type: MultivariatePolyRing,
394 <P::Type as RingExtension>::BaseRing: Borrow<K> + RingStore<Type = K::Type>,
395 F: for<'a> FnMut(DensePolyRing<&'a K>, El<DensePolyRing<&'a K>>, Controller) -> (FreeAlgebraHom<&'a K, K>, El<K>),
396 Controller: ComputationController
397{
398 let n = poly_ring.indeterminate_count();
399 let constant_monomial = poly_ring.create_monomial((0..n).map(|_| 0));
400 if lex_gb.iter().any(|f| poly_ring.appearing_indeterminates(f).len() == 0 && !poly_ring.base_ring().is_zero(poly_ring.coefficient_at(f, &constant_monomial))) {
401 return (FreeAlgebraHom::identity(poly_ring.base_ring().borrow().clone()), Vec::new());
402 }
403
404 let mut relevant_indeterminates = Vec::new();
405 for f in lex_gb {
406 relevant_indeterminates.extend(poly_ring.appearing_indeterminates(f).into_iter().map(|(v, _)| v));
407 }
408 relevant_indeterminates.sort_unstable();
409 relevant_indeterminates.dedup();
410 let contains_indeterminate = |f, indet| poly_ring.appearing_indeterminates(f).iter().any(|(v, _)| v == indet);
411 let has_no_indeterminate_before = |f, indet| poly_ring.appearing_indeterminates(f).iter().all(|(v, _)| v >= indet);
412
413 let polys_for_indeterminate = relevant_indeterminates.iter().map(|indet| {
414 let relevant_polys = lex_gb.iter().filter(|f| contains_indeterminate(f, indet) && has_no_indeterminate_before(f, indet)).collect::<Vec<_>>();
415 assert!(relevant_polys.len() > 0, "basis is either not a lex-GB or does not generate a zero-dimensional ideal");
416 return relevant_polys;
417 }).collect::<Vec<_>>();
418
419 let mut current_embedding: FreeAlgebraHom<_, K> = FreeAlgebraHom::identity(poly_ring.base_ring().borrow().clone());
420 let mut current_roots: Vec<(usize, Vec<El<K>>)> = vec![(0, (0..relevant_indeterminates.len()).map(|_| current_embedding.codomain().zero()).collect())];
421 let mut final_roots: Vec<Vec<El<K>>> = Vec::new();
422
423 while let Some((set_indeterminates, current_root)) = current_roots.pop() {
424 let next_indet_idx = relevant_indeterminates.len() - set_indeterminates - 1;
425 let next_indet = relevant_indeterminates[next_indet_idx];
426
427 let (base_field, current_field, base_field_gen) = current_embedding.destruct();
428 let KX = DensePolyRing::new(current_field, "X");
429 let ref_current_embedding = FreeAlgebraHom::promise_is_well_defined(&base_field, KX.base_ring(), base_field_gen);
430 let next_roots_from: El<DensePolyRing<K>> = polys_for_indeterminate[next_indet_idx].iter().map(|f|
431 poly_ring.evaluate(
432 f,
433 (0..n).map_fn(|i| if i == next_indet {
434 KX.indeterminate()
435 } else {
436 KX.inclusion().map_ref(¤t_root[i])
437 }),
438 KX.inclusion().compose(&ref_current_embedding)
439 )
440 ).fold(KX.zero(), |current, next| KX.ideal_gen(¤t, &next));
441
442 assert!(!KX.is_zero(&next_roots_from), "basis is either not a lex-GB or does not generate a zero-dimensional ideal");
443 if KX.degree(&next_roots_from).unwrap() == 0 {
444 let (_, _, base_field_gen) = ref_current_embedding.destruct();
445 current_embedding = FreeAlgebraHom::promise_is_well_defined(base_field, KX.into().into_base_ring(), base_field_gen);
446 } else if KX.degree(&next_roots_from).unwrap() == 1 {
448 let mut new_root = current_root;
449 new_root[next_indet_idx] = KX.base_ring().negate(KX.base_ring().div(KX.coefficient_at(&next_roots_from, 0), KX.coefficient_at(&next_roots_from, 1)));
450 if set_indeterminates + 1 < relevant_indeterminates.len() {
451 current_roots.push((set_indeterminates + 1, new_root));
452 } else {
453 final_roots.push(new_root);
454 }
455 let (_, _, base_field_gen) = ref_current_embedding.destruct();
456 current_embedding = FreeAlgebraHom::promise_is_well_defined(base_field, KX.into().into_base_ring(), base_field_gen);
457 } else {
458 let (_, _, base_field_gen) = ref_current_embedding.destruct();
459 let (into_new_field, roots) = splitting_field(KX, next_roots_from, &mut create_field, controller.clone());
460
461 final_roots = final_roots.into_iter().map(|root| root.into_iter().map(|x| into_new_field.map(x)).collect()).collect();
462 current_roots = current_roots.into_iter().map(|(l, root)| (l, root.into_iter().map(|x| into_new_field.map(x)).collect())).collect();
463 for (r, _) in roots.into_iter() {
464 let mut new_root: Vec<El<K>> = current_root.iter().map(|x| into_new_field.map_ref(x)).collect();
465 new_root[next_indet_idx] = r;
466 if set_indeterminates + 1 < relevant_indeterminates.len() {
467 current_roots.push((set_indeterminates + 1, new_root));
468 } else {
469 final_roots.push(new_root);
470 }
471 }
472 let base_field_gen = into_new_field.map(base_field_gen);
473 let (_, new_field, _) = into_new_field.destruct();
474 current_embedding = FreeAlgebraHom::promise_is_well_defined(base_field, new_field, base_field_gen);
475 }
476 }
477 return (current_embedding, final_roots);
478}
479
480#[cfg(test)]
481use crate::wrapper::RingElementWrapper;
482#[cfg(test)]
483use crate::rings::rational::RationalField;
484#[cfg(test)]
485use crate::rings::multivariate::multivariate_impl::MultivariatePolyRingImpl;
486
487#[test]
488fn test_extend_field() {
489 let ZZ = BigIntRing::RING;
490 let QQ = RationalField::new(ZZ);
491 let ZZX = DensePolyRing::new(&ZZ, "X");
492 let [f] = ZZX.with_wrapped_indeterminate(|X| [X.pow_ref(2) + 1]);
493 let K = NumberField::new(ZZX, &f);
494 let KX = DensePolyRing::new(&K, "X");
495
496 let [g] = KX.with_wrapped_indeterminate(|X| [X.pow_ref(4) - RingElementWrapper::new(&KX, KX.inclusion().map(K.canonical_gen()))]);
498 let (extension_field_embedding, x) = extend_number_field(KX.clone(), &g, TEST_LOG_PROGRESS);
499 let ext_field = extension_field_embedding.codomain();
500 assert_eq!(8, ext_field.rank());
501 assert_el_eq!(ext_field, ext_field.neg_one(), ext_field.pow(extension_field_embedding.map(K.canonical_gen()), 2));
502 assert_el_eq!(ext_field, extension_field_embedding.map(K.canonical_gen()), ext_field.pow(x, 4));
503
504 crate::homomorphism::generic_tests::test_homomorphism_axioms(
505 &extension_field_embedding,
506 [(0, 0), (0, 1), (1, 0), (2, 0), (-1, 0), (0, -1), (-1, -1)].into_iter().map(|(a, b)| K.from_canonical_basis([QQ.int_hom().map(a), QQ.int_hom().map(b)]))
507 );
508
509 let [g] = KX.with_wrapped_indeterminate(|X| [X.pow_ref(3) - 2]);
511 let (extension_field_embedding, x) = extend_number_field(KX, &g, TEST_LOG_PROGRESS);
512 let ext_field = extension_field_embedding.codomain();
513 assert_eq!(6, ext_field.rank());
514 assert_el_eq!(ext_field, ext_field.neg_one(), ext_field.pow(extension_field_embedding.map(K.canonical_gen()), 2));
515 assert_el_eq!(ext_field, ext_field.int_hom().map(2), ext_field.pow(x, 3));
516
517 crate::homomorphism::generic_tests::test_homomorphism_axioms(
518 &extension_field_embedding,
519 [(0, 0), (0, 1), (1, 0), (2, 0), (-1, 0), (0, -1), (-1, -1)].into_iter().map(|(a, b)| K.from_canonical_basis([QQ.int_hom().map(a), QQ.int_hom().map(b)]))
520 );
521}
522
523#[test]
524fn test_variety_from_lex_gb() {
525 unimplemented!("Currently super slow");
526 let ZZX = DensePolyRing::new(BigIntRing::RING, "X");
527 let [f] = ZZX.with_wrapped_indeterminate(|X| [X - 1]);
528 let QQ = NumberField::new(ZZX, &f);
529 let QQXYZ = MultivariatePolyRingImpl::new(&QQ, 3);
530 let intersection_unitsphere_twistedcubic = QQXYZ.with_wrapped_indeterminates(|[x, y, z]| [
531 x.pow_ref(2) + y.pow_ref(2) + z.pow_ref(2) - 1,
532 y - x.pow_ref(2),
533 z - x.pow_ref(2)
534 ]);
535 let lex_gb = QQXYZ.with_wrapped_indeterminates(|[x, y, z]| [
536 z.pow_ref(6) - 5 * z.pow_ref(4) + 7 * z.pow_ref(2) - 1,
537 y - z.pow_ref(4) + 3 * z.pow_ref(2) - 1,
538 x + z.pow_ref(3) - 2 * z
539 ]);
540 let (into_L, variety) = variety_from_lex_gb(&QQXYZ, &lex_gb, |poly_ring, poly, controller| extend_number_field_promise_is_irreducible(poly_ring, &poly, controller), TEST_LOG_PROGRESS);
541 let L = into_L.codomain();
542
543 assert_eq!(6, variety.len());
544 for point in &variety {
545 assert_el_eq!(L, L.zero(), QQXYZ.evaluate(&intersection_unitsphere_twistedcubic[0], point.clone_ring_els(L), &into_L));
546 assert_el_eq!(L, L.zero(), QQXYZ.evaluate(&intersection_unitsphere_twistedcubic[1], point.clone_ring_els(L), &into_L));
547 assert_el_eq!(L, L.zero(), QQXYZ.evaluate(&intersection_unitsphere_twistedcubic[2], point.clone_ring_els(L), &into_L));
548 }
549}