Skip to content

Deploy tc#633

Draft
strub wants to merge 307 commits into
mainfrom
deploy-tc
Draft

Deploy tc#633
strub wants to merge 307 commits into
mainfrom
deploy-tc

Conversation

@strub
Copy link
Copy Markdown
Member

@strub strub commented Sep 26, 2024

No description provided.

strub added 30 commits May 14, 2026 09:23
Drop the [real_unit] op wrapper — the instance form accepts an inline
lambda for [op unit]. unitout now uses [smt(invr0)] (the [inv 0%r = 0%r]
rule), removing the previous reliance on the circular
[instax_inst_real_idomain_unitout] axiom.
[opprK] and [mulrNz] are TC-polymorphic; in minimal-mode SMT we have
to point them at [int] explicitly. Also drops the duplicate [opprK].
In TC-minimal mode, two issues blocked section-abstract lemmas from
applying to goals at the same abstract carrier:

  - [placeholder_dict] emitted a fresh [missing_dict<N>] for every
    TC-op call site, so the goal and the user-hinted lemma used
    distinct dicts for the same [(*)]. Cached on
    (carrier_w3_ty, tc_name) so calls at the same abstract carrier +
    class share one constant.

  - [trans_class] emitted chain-projection spec axioms describing
    [parent_field(proj d) = child_field(d)]. Skipped in minimal mode:
    we send class operators but not TC axioms.

Also:

  - Track [pi.pr_wanted] in [tenv.te_wanted]. A TC-polymorphic lemma
    explicitly requested via [smt(L)] without a [<:T>] instantiation
    is now a hard error (not a silent skip).

  - Arity-check [<:T1, …>] against the lemma's [ax_tparams] in
    [process_dbhint]; mismatched counts raise [hierror] at scope
    time instead of being dropped silently in [trans_axiom].

  - TcNumber line 747: instantiate [mul0r<:t>] (the only TC-poly
    lemma in that hint set; the rest are section-local).
In TC-minimal mode the dict-projection encoding was emitting one-step
projections at the witness's class (e.g. [tcrealdomain_times d]) while
operator bodies that internally project via chain projections produced
multi-hop forms (e.g. [monoid_mop (mulmonoid_to_monoid_0 (...)) x y]).
The two never matched without chain-projection spec axioms — and even
with them, the noise drowned Z3/CVC5.

This commit:

  - [try_dict_proj] now canonicalizes class-op Fops in minimal mode:
    walk the dict all the way to the OP's class via [lift] and project
    using the op's local name there. Both lemma and operator-body refs
    converge at the SAME (carrier, op_class, lift) key.

  - Pre-emit one flat-constant logic-definition per
    (carrier, reachable-ancestor-class, lift-of-edges) at init time.
    The body is the explicit chain composition; references to the
    constant unfold to the same chain expression when needed. Both
    [try_dict_proj] and [compute_op_dicts] route through this cache —
    every body term becomes a flat [<class>_<op> d_t_<class>_<lift> …]
    rather than a 4-deep nested [proj1 (proj2 (...))] expression.

  - [trans_class] in minimal mode skips emitting chain-proj spec axioms
    (canonicalization makes them redundant) AND emits projection
    lsymbols only for the natively-declared ops of each class
    (inherited ops are reached via origin canonicalization, not via
    leaf-class field clones).

  - [lenv_of_tparams_for_hyp] strips the leading tick from EC tparam
    tysymbol names ([ec_tv_a] instead of ['a]) and [trans_hyp] uses
    [preid_lid] for lsymbol names so the dump's [.why] companion is
    valid Why3 source. [str_p_raw] sanitises operator/punctuation
    chars in path-derived names.

  - [emit_one_dict] gains [?emit_axioms:bool]; minimal-mode dict
    emission passes [~emit_axioms:false] (no [axhold] / no
    [tcaxiom_] decls).

  - Lemma instantiation in [trans_axiom] uses
    [EcUnify.UniEnv.opentvi] to resolve witnesses for [smt(L<:T>)]
    hints — the same path as proof-term elaboration. Handles
    section-abstract carriers correctly, replacing the hand-rolled
    [List.find_opt] lookup.

  - [process_dbhint] now arity-checks [<:T1,…>] against
    [ax_tparams] at scope time (mismatched count is a hard
    [hierror], not a silent skip in [trans_axiom]).

Status: Alt-Ergo proves the TcBigalg:291 task in 0.02s. Z3 and CVC5
still struggle (Unknown / Timeout) despite identical SMT-symbol
matching across lemma / hypotheses / goal — investigation continues
(possibly per-call-site specialisation à la option C).
…e 1)

In TC-minimal mode, [try_dict_proj] now emits a CONCRETE-TYPED lsymbol
per (carrier, op_class, lift) instead of a dict-passing projection.
This mimics what clone-based theories produce: one fresh first-order
function symbol per (concrete instantiation, leg), with no polymorphism
or dict argument visible to the SMT prover.

  - Cache keyed by (carrier_w3_ty, op_class_path, local_name) in
    [te_carrier_ops]. Each entry is a fresh lsymbol whose
    [ls_args]/[ls_value] come from substituting the op's self-tparam
    with the carrier in the EC signature.

  - Lemma side (after [opentvi]) and operator-body side at the same
    (carrier, leg) hit the same cache entry — bytewise-identical SMT
    terms across the task. Z3 and CVC5 pattern-match without needing
    to instantiate polymorphic types or unfold dict projections.

  - Partial / over-application paths now branch on whether we
    resolved to [`Concrete ls] (minimal mode) or [`Field (d, w3cd, f)]
    (dict-passing mode); HO wrappers for the concrete form reuse
    [mk_highorder_func] from regular-op translation.

Sweep at this point (regular ops with TC tparams still polymorphic,
i.e. [bigM] keeps a dict argument — Phase 2 will specialize those
per call site too):

  PASS: TcMonoid, TcRing, TcInt, TcReal, TcNumber, TcBigop, TcBigalg,
        TcPolySmokeTest, TcZModPSmokeTest
  FAIL: TcBinomial:14, TcPoly, TcZModP:294
…nches

  - Remove the [tc_minimal_mode] env-var flag and all
    [if (not) (tc_minimal_mode ()) then …] conditionals — keep the
    minimal-mode body, drop the polymorphic-dict-passing branches.

  - Drop chain-projection spec axiom emission from [trans_class]
    (replaced by origin canonicalization in [try_dict_proj]).

  - Drop the polymorphic-dict-passing axiom encoding in [trans_axiom]
    plus its [_at_<carrier>_<class>] instance specialization
    (replaced by [do_instantiated] via [smt(L<:T>)] hints).

  - Drop the ancestor-class flattening in [trans_class] (only emit
    fields for natively-declared ops of the current class).

  - Drop the [Field] case of [try_dict_proj]'s [resolved] disjunction
    — class-op references always resolve to the concrete-typed
    [`Concrete] lsymbol now.

  - [emit_one_dict] no longer takes an [?emit_axioms] parameter; the
    axhold / tcaxiom emission paths are gone. It always emits
    dict-const + flat-constant logic-defs for ancestors.

  - [init] simplifies — no Phase B branch, just direct emission of
    tparam + abstract-type dicts.

Sweep unchanged from previous commit: 9 PASS, 3 FAIL (TcBinomial:14,
TcPoly, TcZModP:294).
…rrier

Three call sites of [smt(ge0_deg)] and two of [smt(oner_neq0)] in
sections declaring [c :: comring] / [c :: idomain]. Both lemmas are
TC-polymorphic; the minimal-mode encoding requires explicit [<:c>]
instantiation.
  - TcZModP:unitE — replace [smt(zmod_mulrC zmod_mul1r choicebP)]
    with [apply: (unitr0<:zmod>)] (analogue of main's
    [apply: ZModpRing.unitr0]).
  - TcZModP:zmod_mulf_eq0 — port main's case-analysis proof
    using [mul0r] / [mulr0] / [mulrI] / [unitE].
  - TcBinomial:fact0 — replace [rewrite /fact /bigiM /bigM
    range_geq /#] with [rewrite /fact big_geq // ler_naddl]
    (main's proof).
  - TcBinomial:size_bin1 — replace the [/#] tail with main's
    [subz0 ler_maxr ?size_ge0] rewrite chain.

All four had been rewritten with [smt(...)] / [/#] tails that
relied on auto-relevance to pull in lemmas the minimal-mode
encoding doesn't surface. Backporting main's proofs verbatim
closes them.
…rier

[pmulr_gt0] is TC-polymorphic; the minimal-mode SMT encoding requires
explicit [<:t>] instantiation (section's [t :: tcrealdomain]).
[prodr_ge0_seq] is section-local with 0 tparams — left bare.
Conflicts resolved in 6 files, all from origin/main's [ac42e2a
subtype: generalize over section-declared free types at section close].
That commit's subtype-tracking change had already been applied to
HEAD's [module Ty.add_subtype]/[Ty.add] independently (tyd_subtype
field threaded through, carrier+pred stored on the tydecl), so the
conflict resolutions all KEEP HEAD's structure:

  - [tydecl] keeps HEAD's [tyd_resolve] field on top of the
    [tyd_subtype] field both branches added.
  - Type-body constructors stay as polymorphic variants
    ([`Abstract], [`Concrete]) — TC needs the typeclass-list payload
    on [`Abstract tc] that main's plain constructor form doesn't
    carry.
  - Subtype-related tydecl construction sites all carry the
    [tyd_resolve = …] field.
  - [generalize_tydecl] in [ecSection] keeps the destructuring
    [fun (id, _) -> …] for HEAD's tparam-with-tcs tuple shape.
  - [ecScope.ml]'s conflict was a structural duplicate (origin/main's
    [module Ty] block was being pasted before HEAD's [module Search];
    both branches already have [module Ty] independently) — dropped
    the duplicated insertion.

Verified: [dune build] clean, tcalgebra sweep 12/12 PASS after merge.
Commit [0b2f706 TC: matcher recognizes ops with same canonical
origin] left this line as a broken split [rewrite ... addrAC.
rewrite !addzA. ler_subr_addl (...).] — apparent WIP that didn't
get re-joined. Restoring main's single-line form
[rewrite ... addrAC !addrA ler_subr_addl (IntID.addrC 1).].
Commit [5e04bf6 TC: drain pending TC-constraints before [try_delta]'s
tc_reduce check] added [flush_tc_problems] + [norm f1] / [norm f2]
at the entrance of [try_delta]. The flush is needed; the [norm] calls
are not — they re-substitute ev/tu bindings that may have been pinned
during earlier sibling-argument matches, which can change which heads
appear after [destr_app] and silently steer the case dispatch away
from the [Op.reducible] branch that would otherwise apply.

Concrete regression: [theories/algebra/IntDiv.ec:1234]'s
[rewrite -(big_mapT _ idfun)] failed with [nothing to rewrite]
because the pattern's [idfun \o ?h] couldn't unfold past the norm-
substituted form. Dropping the [norm] calls restores the match
(IntDiv.ec passes again; tcalgebra 12/12 still PASS).

[flush_tc_problems] alone is enough to make the queued [TcCtt]
problems get resolved so [tc_reducible] can fire on the now-pinned
witnesses.
…ding

Reverts the identifier-mangling that was added solely so the Why3 task
could be re-emitted as a parseable .why source. The mangling
(lower/uppercasing first chars, mapping operator chars to alphabetic
prefixes, stripping ticks from EC tparam names) produced lowercased
prelude identifiers (top_*) that Z3 4.12 was sensitive to: Matrix.eca:145
returned unknown under the lowercased form but unsat under main's
case-preserving identifiers.

Removed:
- dump_task_theory function and its caller in out_task
- str_lid / str_uid / str_p_raw / str_p_ctor / preid_p_ctor / preid_lid
  (folded back into main's simple str_p / preid)
- sanitize_op_name (HO-wrapper and carrier-op naming) — use raw names
- strip_tick mangling in lenv_of_tparams_for_hyp — use preid id directly

tcalgebra: 12/12 still pass. make stdlib: Matrix.eca:145 now passes
again (was unsat-regressed); DynMatrix.eca:1666 unchanged (independent).
TC class axioms are lemmas. They must never be auto-emitted into the
why3 task — neither as a side-effect of generating an instance dict,
nor through auto-instantiation. The only paths to surface them are:

  - user-explicit hint: smt(L<:T>) — instantiates and emits.
  - relevance: blocked by ax_smt = false on TC class axioms.

Code changes:
- emit_instance_dict: drop the auto-emitted instax_* ancestor-class
  axioms. Dict const + axhold + bridges (user definitions, not class
  axioms) remain.
- trans_axiom: replace the failwith on TC-poly explicit hints with a
  registered SmtHintError exception — clean EC-style error, no anomaly.
- Delete the dead trans_tc_axioms helper.
- Add te_hyps_lenv + te_hyps_tparams to tenv, populated in init from
  the goal's lenv/h_tvar. do_instantiated uses them so substituted
  axioms translate against the goal's why3 tysymbols/dicts AND so
  flush_tc_problems can infer TC witnesses for [Tvar 'a] carriers.
- Thread active_tparams(scope) through do_prover_info →
  process_prover_option → process_dbhint, so <:'a> in smt(L<:'a>)
  resolves to the lemma's own tparam ident instead of minting a
  fresh one.

Test changes:
- Delete tests/tc-concretize-fold.ec (depended on the just-removed
  examples/tcstdlib/).
- tests/tc/smt.ec, tests/tc/diamond.ec: add explicit <:'a> / <:t> on
  every TC-poly hint at abstract carriers.

Verification: make unit passes; tcalgebra 12/12; make stdlib leaves
only Logic.ec:525 + DynMatrix.eca:1666, both pre-existing in main.
The two TC docs accumulated drift faster than they were maintained:

- typeclasses.md §9 documents the now-removed auto-axiom SMT inclusion;
  §10's "diamond" claim about deduplicated auto-axioms is also gone.
- The "Examples" section points at examples/tcstdlib/ and
  examples/typeclasses/ (removed in 1d48ccd, 3d23703) and
  tests/tc-concretize-fold.ec (removed in 116589f).
- The "Files of interest" table cites src/ecSmt.ml trans_tc_axioms
  which was deleted in 116589f.
- typeclasses-inference.md describes a multi-phase strategy-framework
  redesign that was never implemented in that form; the live resolver
  in ecUnify.ml is what governs behavior.

Also drop the dangling "See doc/typeclasses-inference.md ..." comment
in ecUnify.ml.
The additive identity in [addmonoid] was named [zero], diverging from
the conventional stdlib name [zeror] used in [Ring.ZModule.zeror],
[ComRing.zeror], etc. This is a prerequisite to porting stdlib files
(Matrix.eca next) whose proof bodies reference [zeror] verbatim and
that we want to keep unchanged.

Word-boundary rename across all examples/tcalgebra/*.ec:

- TcMonoid.ec: the [addmonoid <: (monoid with idm = zero, ...)] rename
  clause and the [abbrev zero ['a <: addmonoid] = idm<:'a>] declaration.
- All call sites (333 occurrences across 8 files).

Comment text containing the word "zero" (e.g. "zero divisors") gets the
rename too -- acceptable noise.

tcalgebra sweep: 12/12 pass.
[reduce_user_gen] in ecReduction.ml backs the [hint simplify]
machinery. It opens the rule's tparams as fresh univars, walks the
goal subterm against the rule pattern via [unify_etyarg], then checks
closedness. Three issues prevented TC-polymorphic lemmas from
matching:

1. The unienv was created with [None] tparams, so when the matcher
   tried to unify a fresh univar (bounded by a TC) with a goal-side
   [Tvar 'r] (also TC-bounded), the unifier had no record of 'r's
   bounds and rejected the unification. Fix: seed [UniEnv.create]
   with the goal's [hyps.h_tvar].

2. [Tvar.subst_etyarg] only substitutes the type slot of the
   pattern's etyargs, leaving witness slots referencing the rule's
   own tparam ids. Those don't match the goal's tparam ids, so the
   TcTw equation falls into the [tcw_equal] arm and fails. Fix: use
   [EcCoreSubst.etyarg_subst] with an [f_subst] populated from
   [tvi.subst] (both [tv] and [tw] maps), so the witnesses are also
   substituted to fresh TC-witness univars that can unify against the
   goal's abstract witnesses via TcTw [bind_uni].

3. After unification, parked [TcCtt] problems (one per opened TC
   bound) remain in [tcenv.problems] without entries in
   [tcenv.resolution], so [closed] returns false. Fix: call
   [flush_tc_problems] after [doit] and before [closed], mirroring
   what [trans_axiom]'s [do_instantiated] already does in ecSmt.ml.

With all three changes, hint simplify on TC-polymorphic lemmas fires
both at top level and inside sections with [declare type r <: tc].

Verification:
- All four probes (same-section, top-level, lemma-in-section-used-at-top,
  cross-section) — three pass; cross-section still fails (separate
  issue: hint registration doesn't propagate across section close).
- tcalgebra 12/12 still pass.
- make unit: all pass.
- make stdlib: only pre-existing Logic.ec:525 and DynMatrix.eca:1666
  fail; no new regressions.
When a user-rewrite rule fires on a TC-polymorphic lemma,
[reduce_user_gen] opens the rule's tparams and unifies its pattern
against the goal subterm. The closing substitution only carried the
type-univar map [assubst ue]; the TC-witness univar map [tw_assubst
ue] was dropped. Result: [TCIUni _] placeholders survived in the
rewritten term and poisoned later matches (closedness check failed,
cbv fell through to delta on the carrier op).

Pass [tw_uni] through to [Tuni.subst] so witness univars resolve
alongside type univars.
[generalize_ctheory] entered a sub-theory, accumulated substitutions /
tparams / binds / clears for its items in a local [genenv], then
returned only the compiled theory body. The outer [genenv] kept its
original [tg_subst] — so use sites in *later* items of the same
section that referenced an op renamed inside the sub-theory were
never rewritten with the section's freshly-introduced tparams. The
[Fop (sub.op, [])] left behind crashed at first reduction with
[List.combine: list lengths differ] (n_tparams=1, n_tys=0).

Triggered by [subtype X as Sub] inside a section: [Sub.insubd] gets
generalised properly within [Sub], but downstream [op f = Sub.insubd
...] saw the un-substituted reference.

Fix: pull [tg_params] / [tg_binds] / [tg_subst] / [tg_clear] from
the inner genenv back to the outer one before reassembling [tg_env].
[examples/tcalgebra/TcMatrix.eca]: TC port of [theories/algebra/Matrix.eca]
over [r <: comring]. Vector and matrix are now subtype-based (not
axiomatic); the [clone import Ring.ZModule] for each becomes [instance
addgroup … reducible] with obligations discharged via [realize] after
the instance declaration.

Proofs are backported verbatim. Two forced TC adaptations:
  - scalevE: [smt(offunvK tofunvK)] -> [smt(offunvK<:r> tofunvK<:r>)]
    (smt hints require explicit TC instantiation).
  - offunM: [/getm_outL|/getm_outR] -> [/getm_outL<:r>|/getm_outR<:r>]
    (the lemma's premise [!(0 <= i < size)] doesn't mention 'r, so
    the discriminator step can't pin 'r before the next [->] runs).

Matrix's [Matrix.offunB] is renamed to [offunmB] to avoid clashing
with [Vector.offunB] at top level (both lose their theory namespace
when moved outside their respective sections, where the addgroup
instance is registered).
[examples/tcalgebra/TcDynMatrix.eca]: TC port of
[theories/algebra/DynMatrix.eca]. Dynamic-size vectors and matrices
as quotient types via [Quotient.EquivQuotient], over [r <: comring].
No addgroup instance — dynamic-size carriers don't form a Z-module
(no canonical zero across all sizes; [add0v v : zerov (size v) + v
= v] depends on the size).

Proofs are backported verbatim. Forced TC adaptations on a handful
of SMT-hint sites where the lemma is type-class polymorphic and the
smt pipeline requires explicit instantiation:
  - dotpDr:           smt(... mul0r) -> smt(... mul0r<:r>)
  - dotp_scalarv:     smt(mulrA mulrC) -> smt(mulrA<:r> mulrC<:r>)
  - mulmxA, catmrDr:  smt(... mulr0 mul0r ...) -> ...<:r>
  - addm_catmr:       smt(addrA addrC) -> smt(addrA<:r> addrC<:r>)
  - mul_colmxc:       Big.BAdd.big_int1 -> big_int1 (TC name)

Two unrelated stdlib-side proof breakages also fixed in-place during
the backport: [catmr_subm] and [scalarNm] both fail to close with
their existing hints (smt accepts [size_*] but cannot project the
resulting pair equation into the [rows = ... /\ cols = ...]
components it needs). Replacing [size_X] with [rows_X cols_X] in
those smt calls gives the solver the int-shaped equations directly.
The original DynMatrix.eca fails identically on deploy-tc/main —
the fix is not TC-related.
The [hint simplify subrr.] declaration inside the addgroup section did
not survive section close (per the project's standing observation
that hint declarations are section-local). Re-register it at top
level so the TC-polymorphic [subrr] rule fires on goals like
[zeror<:t> - zeror<:t> = zeror<:t>] at use sites of [t <: addgroup]
in other files (e.g. closing the trivial subgoal of
[apply/idealP => //] for the [id0] ideal).
When a TC instance has multiple obligations with the same axiom name
reached through different parent-class paths (e.g. [comring] reaches
[mopA] both via [addgroup/addmonoid/monoid] and [mulmonoid/monoid]),
[check_tci_axioms] disambiguates by encoding the effective name as
[mopA<:addgroup/addmonoid/monoid>] in the pending-obligation path.
The inline [proof X<:Lbl> by Y] form on the instance declaration
matches via a sub-sequence containment on labels. The [realize]
command, however, only accepted a bare qident and tried exact path
equality, so [realize mopA<:addmonoid>] could not be used to
discharge such obligations.

Extend the [realize] grammar to optionally accept the same
[<: l1 / l2 / ... >] label suffix as the inline form, and lookup
the matching pending obligation via the same sub-sequence rule.

prealize gains [pr_labels : psymbol list option]. Labelled form is
restricted to unqualified obligation names (the parsetree's
[pr_name] retains the prefix path for the cross-theory case;
labelled lookup is only meaningful inside the active proof context).
[examples/tcalgebra/TcIdeal.eca]: TC port of [theories/algebra/Ideal.ec].

  - [abstract theory TcIdealComRing] declares [type t <: comring]
    directly (replacing stdlib's [clone import Ring.ComRing as
    IComRing]). The ideal theory body (~250 lines: [(%|)], [(%=)],
    [ideal], [idgen], [principal], [dvdr*], [eqp_*]) is backported
    verbatim, TC-polymorphic in [t].

  - [RingQuotientBase] inside keeps the stdlib abstract-theory
    shape: declares the ideal predicate [p : t -> bool], its
    [IdealAxioms], clones [Quotient.EquivQuotient], defines ring
    ops on [qT], proves all ring axioms.

  - [RingQuotientDflInv] / [RingQuotient] each emit
    [instance comring with qT op ... .] (replacing stdlib's [clone
    import ComRingDflInv]/[ComRing]). [RingQuotientDflInv] supplies
    [qunit]/[qinvr] via [choiceb]; [RingQuotient] takes
    [mulVr]/[unitP]/[unitout] as axioms.

  - [TcIdeal] mirrors stdlib's [Ideal] (IDomain specialisation) via
    [clone include TcIdealComRing with type t <- t].

Forced adaptations from verbatim:

  - [ideal_sum] / [eqv_sum]: stdlib's [BAdd.big<:'a> P F s] becomes
    [bigA P F s] (un-annotated). The TC [bigA] has two tparams
    ['a, 't <: addmonoid]; positional [<: t>] would bind the wrong
    one. Explicit param types on [P/F] fix [t] via unification.

  - [in_idgen_mem]: [pose cs := rcons (nseq n zeror) oner] cannot
    pin [zeror]'s type from context. One annotation: [zeror<:t>].

  - [addrN] for [qT]: stdlib's [addNr : left_inverse zeror [-] (+)]
    is kept verbatim. The TC [addgroup] class's axiom is
    [addrN : right_inverse zeror [-] (+)] (opposite side, different
    name). Added a derived [addrN] lemma:
    [by move=> x; rewrite addrC; apply: addNr.]
Backports [theories/algebra/Poly.ec:782+] (finite_for_poly_ledeg,
dpoly, supp_dpoly, dpoly_ll, dpoly_fu, dpoly_uni) into the comring
section of TcPoly. All proofs verbatim from stdlib. Needed by
TcPolyReduce / TcPolyReduceZp's finiteness and uniform-sampling
lemmas (finite_for_polyXnD1, dpolyX, dpolyXnD1).
[examples/tcalgebra/TcPolyReduce.eca]: TC port of
[theories/algebra/PolyReduce.ec]. Builds the ring k[x]/<X^n + 1>.

Structure:

  - [abstract theory TcPolyReduce] declares [type coeff <: comring]
    directly (replacing stdlib's [clone import ComRing as Coeff]).

  - Uses [TcPoly]'s [coeff poly] directly. Drops stdlib's [clone
    export PolyComRing as BasePoly] — TcPoly's instance comring
    already gives us the polynomial ring on TC.

  - [clone import TcIdealComRing as PIdeal with type t <- coeff poly]
    specialises the TC-bound ideal machinery to the polynomial ring.

  - [op n], [op I = idgen [exp X n + poly1]], then
    [clone include RingQuotientDflInv with op p <- I
       rename "qT" as "polyXnD1"]
    creates the quotient type and auto-registers it as a comring
    (via the [instance comring with qT] inside RingQuotientDflInv).

  - Drops stdlib's [clone BigComRing as BigXnD1] — bigops on the
    quotient resolve automatically because [polyXnD1 : comring]
    via the instance.

  - All ~400 lines of [pinject]/[prepr]/[iX]/[( ** )]/[reduce]/
    [reduced]/[crepr] and friends backported verbatim.

  - [abstract theory TcPolyReduceZp] clones [TcZModP.ZModRing] and
    [TcPolyReduce at coeff = Zp.zmod], then defines [dpolyX],
    [dpolyXnD1] and lossless/uniform/full/funi/[reduced_dpoly]
    lemmas.

Forced TC adaptations:

  - In [eqv_reduce] proof: stdlib's [(IntID.mulrC _ n)] becomes
    [(TcRing.mulrC<:int> _ n)] — the local cloned [mulrC] on the
    quotient ring shadows; qualifying with the [TcRing] prefix +
    explicit instantiation picks the integer one.

  - In [finite_for_polyXnD1]: stdlib's [pose P p := deg p <= n]
    becomes [pose P (p : coeff poly) := deg p <= n] — without the
    type ascription [pose] cannot infer [p]'s type from the
    TC-polymorphic [deg]/[n].
When an instance for a typeclass [C] on carrier [T 'a] reuses
existing chain entries from a previously-registered instance of
[C']'s ancestor on the same carrier, those existing entries were
registered at a different tparam bound list (e.g. ['a <: C']) than
the user's new instance (['a <: C]). The reuse exposed body
witnesses encoded at the existing-instance's bound depth, so
[tc_core_reduce]'s post-substitution result had stripped lifts and
the obligation's proof script could not match.

Fix: compute a per-chain-entry "bridging" lift — the parent-index
path through context-changing chain steps from chain_decls[0]
(user's class) to that entry. A step is context-changing iff the
two entries' tparam bound lists differ (using TC-name equality);
the existing instance's bounds are read via [TcInstance.by_path] on
the reused path. Bake [bridging] into [self_etyargs]'s
[TCIAbstract] witnesses in [add_tydef]'s [self_witness]: each
witness's [lift] becomes the bridging path, so body's
[AbsV('c, off=k, lift_body)] substitutes to
[AbsV('c, off=k, bridging @ lift_body)] — the use-site walk that
reaches the reused entry's tparam depth before continuing with
the body's own lift.

[tc_core_reduce] also gains a parallel [bridging] tracker on the
walk and threads it to [finalise], which applies it to the etyargs
before building the substitution. This covers obligations whose
class-op witnesses point at fresh entries but transition through
reused ones during reduction.

Unblocks Phase 8 (`instance idomain with ['c <: idomain] ('c poly)`).
All 16 tcalgebra files pass.
Phase 8 instance registration: backport stdlib [Poly.ec:850-974]'s
[abstract theory Poly] (the IDomain coefficient phase). Re-emits
the comring obligations (resolved verbatim from the same
[polyD_*]/[polyM_*] lemmas as the Phase 5 comring instance) plus
[mulf_eq0] discharged via [polyM_mulf_eq0] (already in TcPoly's
idomain section).

Required the bridging-lift fix in [scope/env] (parent commit) to
get past the tparam-context mismatch the obligation form would
otherwise have when the idomain chain reuses the existing
comring/addgroup/addmonoid/monoid chain entries on the same
carrier.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants