@@ -160,6 +160,13 @@ impl MetaController {
160160 CoprocessorKind :: Graphics ,
161161 CoprocessorKind :: Audio ,
162162 CoprocessorKind :: Fpga ,
163+ // Phase 2b subprocess CAS backends — health degrades gracefully
164+ // when the underlying binary is absent.
165+ CoprocessorKind :: PariGp ,
166+ CoprocessorKind :: Maxima ,
167+ CoprocessorKind :: Singular ,
168+ CoprocessorKind :: Gap ,
169+ CoprocessorKind :: Macaulay2 ,
163170 ] ;
164171 let mut out: HashMap < CoprocessorKind , Arc < dyn Coprocessor > > = HashMap :: new ( ) ;
165172 for & k in kinds {
@@ -336,6 +343,135 @@ impl MetaController {
336343 ) ] ,
337344 ) ;
338345
346+ // ── PARI/GP advanced number theory ───────────────────────────────
347+ // Preferred over Math for large semi-primes where ECM/GNFS matters.
348+ r. insert (
349+ "arithmetic.factorisation.advanced" . into ( ) ,
350+ vec ! [ hint_template(
351+ CoprocessorKind :: PariGp ,
352+ CoprocessorOp :: PariGpFactor { n: String :: new( ) } ,
353+ ) ] ,
354+ ) ;
355+ r. insert (
356+ "arithmetic.multiplicative_order" . into ( ) ,
357+ vec ! [ hint_template(
358+ CoprocessorKind :: PariGp ,
359+ CoprocessorOp :: PariGpZnorder { a: String :: new( ) , n: String :: new( ) } ,
360+ ) ] ,
361+ ) ;
362+ r. insert (
363+ "arithmetic.next_prime" . into ( ) ,
364+ vec ! [ hint_template(
365+ CoprocessorKind :: PariGp ,
366+ CoprocessorOp :: PariGpNextPrime { n: String :: new( ) } ,
367+ ) ] ,
368+ ) ;
369+
370+ // ── Maxima symbolic algebra ──────────────────────────────────────
371+ r. insert (
372+ "algebra.symbolic.simplify" . into ( ) ,
373+ vec ! [ hint_template(
374+ CoprocessorKind :: Maxima ,
375+ CoprocessorOp :: MaximaSimplify { expr: String :: new( ) } ,
376+ ) ] ,
377+ ) ;
378+ r. insert (
379+ "algebra.symbolic.factor" . into ( ) ,
380+ vec ! [ hint_template(
381+ CoprocessorKind :: Maxima ,
382+ CoprocessorOp :: MaximaFactor { expr: String :: new( ) } ,
383+ ) ] ,
384+ ) ;
385+ r. insert (
386+ "algebra.symbolic.diff" . into ( ) ,
387+ vec ! [ hint_template(
388+ CoprocessorKind :: Maxima ,
389+ CoprocessorOp :: MaximaDiff { expr: String :: new( ) , var: String :: new( ) } ,
390+ ) ] ,
391+ ) ;
392+
393+ // ── Singular polynomial algebra ──────────────────────────────────
394+ r. insert (
395+ "algebra.groebner.basis" . into ( ) ,
396+ vec ! [ hint_template(
397+ CoprocessorKind :: Singular ,
398+ CoprocessorOp :: SingularGroebner {
399+ ring_char: 0 ,
400+ vars: vec![ ] ,
401+ polys: vec![ ] ,
402+ } ,
403+ ) ] ,
404+ ) ;
405+ r. insert (
406+ "algebra.groebner.membership" . into ( ) ,
407+ vec ! [ hint_template(
408+ CoprocessorKind :: Singular ,
409+ CoprocessorOp :: SingularIdealMembership {
410+ ring_char: 0 ,
411+ vars: vec![ ] ,
412+ poly: String :: new( ) ,
413+ ideal: vec![ ] ,
414+ } ,
415+ ) ] ,
416+ ) ;
417+ r. insert (
418+ "algebra.variety.dimension" . into ( ) ,
419+ vec ! [ hint_template(
420+ CoprocessorKind :: Singular ,
421+ CoprocessorOp :: SingularDimension {
422+ ring_char: 0 ,
423+ vars: vec![ ] ,
424+ polys: vec![ ] ,
425+ } ,
426+ ) ] ,
427+ ) ;
428+
429+ // ── GAP group theory ─────────────────────────────────────────────
430+ r. insert (
431+ "algebra.group.order" . into ( ) ,
432+ vec ! [ hint_template(
433+ CoprocessorKind :: Gap ,
434+ CoprocessorOp :: GapGroupOrder { generators: vec![ ] } ,
435+ ) ] ,
436+ ) ;
437+ r. insert (
438+ "algebra.group.abelian" . into ( ) ,
439+ vec ! [ hint_template(
440+ CoprocessorKind :: Gap ,
441+ CoprocessorOp :: GapIsAbelian { generators: vec![ ] } ,
442+ ) ] ,
443+ ) ;
444+ r. insert (
445+ "algebra.group.symmetric_order" . into ( ) ,
446+ vec ! [ hint_template(
447+ CoprocessorKind :: Gap ,
448+ CoprocessorOp :: GapSymmetricGroupOrder { n: 0 } ,
449+ ) ] ,
450+ ) ;
451+
452+ // ── Macaulay2 algebraic geometry ─────────────────────────────────
453+ r. insert (
454+ "algebra.geometry.groebner" . into ( ) ,
455+ vec ! [ hint_template(
456+ CoprocessorKind :: Macaulay2 ,
457+ CoprocessorOp :: Macaulay2GroebnerBasis { vars: vec![ ] , polys: vec![ ] } ,
458+ ) ] ,
459+ ) ;
460+ r. insert (
461+ "algebra.geometry.dimension" . into ( ) ,
462+ vec ! [ hint_template(
463+ CoprocessorKind :: Macaulay2 ,
464+ CoprocessorOp :: Macaulay2Dimension { vars: vec![ ] , polys: vec![ ] } ,
465+ ) ] ,
466+ ) ;
467+ r. insert (
468+ "algebra.geometry.degree" . into ( ) ,
469+ vec ! [ hint_template(
470+ CoprocessorKind :: Macaulay2 ,
471+ CoprocessorOp :: Macaulay2Degree { vars: vec![ ] , polys: vec![ ] } ,
472+ ) ] ,
473+ ) ;
474+
339475 r
340476 }
341477
@@ -568,13 +704,16 @@ mod tests {
568704 #[ tokio:: test]
569705 async fn registers_all_native_coprocessors ( ) {
570706 let mc = MetaController :: new ( ) ;
571- // 10 always-on (Math, Vector, Tensor, Crypto, Physics, Dsp, Io,
572- // Graphics, Audio, Fpga) + 1 feature-gated (FlintMath).
573- // Without --features flint we expect 10; with it, 11.
707+ // 14 always-on (Math, Vector, Tensor, Crypto, Physics, Dsp, Io,
708+ // Graphics, Audio, Fpga + Phase 2b: PariGp, Maxima, Singular, Gap,
709+ // Macaulay2) + 1 feature-gated (FlintMath).
710+ // Phase 2b backends degrade to Unhealthy if the binary is absent, but
711+ // they ARE registered — health is checked at dispatch time, not at
712+ // registration time. Without --features flint we get 15; with it 16.
574713 let n = mc. num_coprocessors ( ) ;
575714 assert ! (
576- n == 10 || n == 11 ,
577- "expected 10 (no flint) or 11 (with flint), got {n}"
715+ n == 15 || n == 16 ,
716+ "expected 15 (no flint) or 16 (with flint), got {n}"
578717 ) ;
579718 }
580719
@@ -594,6 +733,12 @@ mod tests {
594733 ( "visualisation.proof_graph" , CoprocessorKind :: Graphics ) ,
595734 ( "audio.completion_chime" , CoprocessorKind :: Audio ) ,
596735 ( "hardware.verilog.synth" , CoprocessorKind :: Fpga ) ,
736+ // Phase 2b CAS backends
737+ ( "arithmetic.factorisation.advanced" , CoprocessorKind :: PariGp ) ,
738+ ( "algebra.symbolic.simplify" , CoprocessorKind :: Maxima ) ,
739+ ( "algebra.groebner.basis" , CoprocessorKind :: Singular ) ,
740+ ( "algebra.group.order" , CoprocessorKind :: Gap ) ,
741+ ( "algebra.geometry.groebner" , CoprocessorKind :: Macaulay2 ) ,
597742 ] ;
598743 for ( aspect, expected_kind) in cases {
599744 let g = dummy_goal ( vec ! [ aspect] ) ;
0 commit comments