From 852a3a35670a41965c58ecceb92accc1e1556908 Mon Sep 17 00:00:00 2001 From: Doug Torrance Date: Mon, 22 Jun 2026 20:46:55 -0400 Subject: [PATCH] Replace nested promote/lift switches with std::variant dispatch MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Replaces the ~130-line nested switch in ConcreteRing::promote and the ~100-line nested switch in ConcreteRing::lift with a RingVariant + toVariant helper and a two-argument std::visit lambda that calls mypromote/mylift directly on the unwrapped concrete ring references. The old lift switch had three latent bugs now fixed automatically: - ring_RRi and ring_CCi source arms were missing (those mylift specializations in aring-translate.hpp were unreachable) - The ring_CC→ring_CCC and ring_CCC→ring_CC lift template args were swapped Structural drift is now impossible: adding a new ring type requires only adding it to RingVariant and toVariant; the compiler enforces coverage. Co-Authored-By: Claude Sonnet 4.6 --- M2/Macaulay2/e/basic-rings/aring-glue.hpp | 335 +++++----------------- 1 file changed, 66 insertions(+), 269 deletions(-) diff --git a/M2/Macaulay2/e/basic-rings/aring-glue.hpp b/M2/Macaulay2/e/basic-rings/aring-glue.hpp index 363763f52d9..f4375e11e11 100644 --- a/M2/Macaulay2/e/basic-rings/aring-glue.hpp +++ b/M2/Macaulay2/e/basic-rings/aring-glue.hpp @@ -9,6 +9,9 @@ #include "mutable-matrices/mutablemat.hpp" +#include +#include + static const bool displayArithmeticCalls = false; #define COERCE_RING(RingType, R) dynamic_cast(R) @@ -557,48 +560,35 @@ ConcreteRing *ConcreteRing::create(Args &&...args) // to the routines in the namespace ARingTranslate namespace RingPromoter { - template - bool promoter(const Ring *R, - const Ring *S, - const ring_elem fR, - ring_elem &resultS) - { - assert(dynamic_cast *>(R) != 0); - assert(dynamic_cast *>(S) != 0); - const SourceRing &R1 = - dynamic_cast *>(R)->ring(); - const TargetRing &S1 = - dynamic_cast *>(S)->ring(); - - typename SourceRing::Element fR1(R1); - typename TargetRing::Element gS1(S1); - - R1.from_ring_elem(fR1, fR); - bool retval = mypromote(R1, S1, fR1, gS1); - if (retval) S1.to_ring_elem(resultS, gS1); - return retval; - } - - template - bool lifter(const Ring *R, - const Ring *S, - ring_elem &result_gR, - const ring_elem gS) + using RingVariant = std::variant *, + const ConcreteRing *, + const ConcreteRing *, + const ConcreteRing *, + const ConcreteRing *, + const ConcreteRing *, + const ConcreteRing *>; + + inline std::optional toVariant(const Ring *R) { - assert(dynamic_cast *>(R) != 0); - assert(dynamic_cast *>(S) != 0); - const SourceRing &R1 = - dynamic_cast *>(R)->ring(); - const TargetRing &S1 = - dynamic_cast *>(S)->ring(); - - typename SourceRing::Element fR1(R1); - typename TargetRing::Element gS1(S1); - - S1.from_ring_elem(gS1, gS); - bool retval = mylift(R1, S1, fR1, gS1); // sets fR1. - if (retval) R1.to_ring_elem(result_gR, fR1); - return retval; + switch (R->ringID()) + { + case M2::ring_QQ: + return static_cast *>(R); + case M2::ring_RR: + return static_cast *>(R); + case M2::ring_RRR: + return static_cast *>(R); + case M2::ring_RRi: + return static_cast *>(R); + case M2::ring_CC: + return static_cast *>(R); + case M2::ring_CCC: + return static_cast *>(R); + case M2::ring_CCi: + return static_cast *>(R); + default: + return std::nullopt; + } } }; @@ -608,8 +598,6 @@ bool ConcreteRing::promote(const Ring *R, ring_elem &resultS) const { const Ring *S = this; - // fprintf(stderr, "calling promote\n"); - namespace RP = RingPromoter; if (R == globalZZ) { resultS = S->from_int(fR.get_mpz()); @@ -620,134 +608,26 @@ bool ConcreteRing::promote(const Ring *R, resultS = copy(fR); return true; } - switch (R->ringID()) - { - case M2::ring_ZZp: - switch (S->ringID()) - { - case M2::ring_ZZp: - return false; - case M2::ring_ZZpFfpack: - return RP::promoter(R, S, fR, resultS); - default: - return false; - } - break; - case M2::ring_ZZpFfpack: - switch (S->ringID()) - { - case M2::ring_ZZp: - return RP::promoter(R, S, fR, resultS); - case M2::ring_ZZpFfpack: - return RP::promoter( - R, S, fR, resultS); - default: - return false; - } - case M2::ring_QQ: - switch (S->ringID()) - { - case M2::ring_RR: - return RP::promoter(R, S, fR, resultS); - case M2::ring_RRR: - return RP::promoter(R, S, fR, resultS); - case M2::ring_RRi: - return RP::promoter(R, S, fR, resultS); - case M2::ring_CC: - return RP::promoter(R, S, fR, resultS); - case M2::ring_CCC: - return RP::promoter(R, S, fR, resultS); - case M2::ring_CCi: - return RP::promoter(R, S, fR, resultS); - default: - return false; - } - case M2::ring_RR: - switch (S->ringID()) - { - case M2::ring_RR: - return RP::promoter(R, S, fR, resultS); - case M2::ring_RRR: - return RP::promoter(R, S, fR, resultS); - case M2::ring_RRi: - return RP::promoter(R, S, fR, resultS); - case M2::ring_CC: - return RP::promoter(R, S, fR, resultS); - case M2::ring_CCC: - return RP::promoter(R, S, fR, resultS); - case M2::ring_CCi: - return RP::promoter(R, S, fR, resultS); - default: - return false; - } - case M2::ring_RRR: - switch (S->ringID()) - { - case M2::ring_RR: - return RP::promoter(R, S, fR, resultS); - case M2::ring_RRR: - return RP::promoter(R, S, fR, resultS); - case M2::ring_RRi: - return RP::promoter(R, S, fR, resultS); - case M2::ring_CC: - return RP::promoter(R, S, fR, resultS); - case M2::ring_CCC: - return RP::promoter(R, S, fR, resultS); - case M2::ring_CCi: - return RP::promoter(R, S, fR, resultS); - default: - return false; - } - case M2::ring_RRi: - switch (S->ringID()) - { - case M2::ring_RR: - return RP::promoter(R, S, fR, resultS); - case M2::ring_RRR: - return RP::promoter(R, S, fR, resultS); - case M2::ring_RRi: - return RP::promoter(R, S, fR, resultS); - case M2::ring_CCi: - return RP::promoter(R, S, fR, resultS); - default: - return false; - } - case M2::ring_CC: - switch (S->ringID()) - { - case M2::ring_CC: - return RP::promoter(R, S, fR, resultS); - case M2::ring_CCC: - return RP::promoter(R, S, fR, resultS); - case M2::ring_CCi: - return RP::promoter(R, S, fR, resultS); - default: - return false; - } - case M2::ring_CCC: - switch (S->ringID()) - { - case M2::ring_CCC: - return RP::promoter(R, S, fR, resultS); - case M2::ring_CC: - return RP::promoter(R, S, fR, resultS); - case M2::ring_CCi: - return RP::promoter(R, S, fR, resultS); - default: - return false; - } - case M2::ring_CCi: - switch (S->ringID()) - { - case M2::ring_CCi: - return RP::promoter(R, S, fR, resultS); - default: - return false; - } - default: - break; - }; - return false; + auto vR = RingPromoter::toVariant(R); + auto vS = RingPromoter::toVariant(S); + if (!vR || !vS) return false; + return std::visit( + [&fR, &resultS](auto rptr, auto sptr) -> bool { + const auto &R1 = rptr->ring(); + const auto &S1 = sptr->ring(); + using SourceRing = std::decay_t; + using TargetRing = std::decay_t; + typename SourceRing::Element fR1(R1); + typename TargetRing::Element gS1(S1); + R1.from_ring_elem(fR1, fR); + if constexpr (std::is_same_v) + S1.set(gS1, fR1); + else if (!mypromote(R1, S1, fR1, gS1)) + return false; + S1.to_ring_elem(resultS, gS1); + return true; + }, + *vR, *vS); } // given a natural map: R --> S = this, @@ -759,8 +639,6 @@ bool ConcreteRing::lift(const Ring *R, ring_elem &result_gR) const { const Ring *S = this; - - namespace RP = RingPromoter; if (R == S) { result_gR = gS; @@ -771,102 +649,21 @@ bool ConcreteRing::lift(const Ring *R, // MES:TODO!! WRITE ME return false; } - switch (R->ringID()) - { - case M2::ring_ZZp: - switch (S->ringID()) - { - case M2::ring_ZZp: - return false; - case M2::ring_ZZpFfpack: - return RP::lifter(R, S, result_gR, gS); - default: - return false; - } - break; - case M2::ring_ZZpFfpack: - switch (S->ringID()) - { - case M2::ring_ZZp: - return RP::lifter(R, S, result_gR, gS); - case M2::ring_ZZpFfpack: - return RP::lifter( - R, S, result_gR, gS); - default: - return false; - } - case M2::ring_QQ: - switch (S->ringID()) - { - case M2::ring_RR: - return RP::lifter(R, S, result_gR, gS); - case M2::ring_RRR: - return RP::lifter(R, S, result_gR, gS); - default: - return false; - } - case M2::ring_RR: - switch (S->ringID()) - { - case M2::ring_RR: - return RP::lifter(R, S, result_gR, gS); - case M2::ring_RRR: - return RP::lifter(R, S, result_gR, gS); - case M2::ring_RRi: - return RP::lifter(R, S, result_gR, gS); - case M2::ring_CC: - return RP::lifter(R, S, result_gR, gS); - case M2::ring_CCC: - return RP::lifter(R, S, result_gR, gS); - default: - return false; - } - case M2::ring_RRR: - switch (S->ringID()) - { - case M2::ring_RR: - return RP::lifter(R, S, result_gR, gS); - case M2::ring_RRR: - return RP::lifter(R, S, result_gR, gS); - case M2::ring_RRi: - return RP::lifter(R, S, result_gR, gS); - case M2::ring_CC: - return RP::lifter(R, S, result_gR, gS); - case M2::ring_CCC: - return RP::lifter(R, S, result_gR, gS); - default: - return false; - } - case M2::ring_CC: - switch (S->ringID()) - { - case M2::ring_CC: - return RP::lifter(R, S, result_gR, gS); - case M2::ring_CCC: - return RP::lifter(R, S, result_gR, gS); - default: - return false; - } - case M2::ring_CCC: - switch (S->ringID()) - { - case M2::ring_CC: - return RP::lifter(R, S, result_gR, gS); - case M2::ring_CCC: - return RP::lifter(R, S, result_gR, gS); - default: - return false; - } - default: -#ifndef NDEBUG - fprintf(stderr, - "oh no: rings not in list\n, R->ringID()=%d S->ringID()=%d\n", - R->ringID(), - S->ringID()); -#endif - break; - }; - return false; + auto vR = RingPromoter::toVariant(R); + auto vS = RingPromoter::toVariant(S); + if (!vR || !vS) return false; + return std::visit( + [&gS, &result_gR](auto rptr, auto sptr) -> bool { + const auto &R1 = rptr->ring(); + const auto &S1 = sptr->ring(); + typename std::decay_t::Element fR1(R1); + typename std::decay_t::Element gS1(S1); + S1.from_ring_elem(gS1, gS); + bool retval = mylift(R1, S1, fR1, gS1); + if (retval) R1.to_ring_elem(result_gR, fR1); + return retval; + }, + *vR, *vS); } // Note: the only promotion to 'this' allowed is ZZ --> this, which is covered