Git Product home page Git Product logo

hierarchy-builder's Introduction

Actions Status project chat

Hierarchy Builder

Hierarchy Builder (HB) provides high level commands to declare a hierarchy of algebraic structure (or interfaces if you prefer the glossary of computer science) for the Coq system.

Given a structure one can develop its theory, and that theory becomes automatically applicable to all the examples of the structure. One can also declare alternative interfaces, for convenience or backward compatibility, and provide glue code linking these interfaces to the structures part of the hierarchy.

HB commands compile down to Coq modules, sections, records, coercions, canonical structure instances and notations following the packed classes discipline which is at the core of the Mathematical Components library. All that complexity is hidden behind a few concepts and a few declarative Coq commands.

Example

From HB Require Import structures.
From Coq Require Import ssreflect ZArith.

HB.mixin Record IsAddComoid A := {
  zero : A;
  add : A -> A -> A;
  addrA : forall x y z, add x (add y z) = add (add x y) z;
  addrC : forall x y, add x y = add y x;
  add0r : forall x, add zero x = x;
}.

HB.structure Definition AddComoid := { A of IsAddComoid A }.

Notation "0" := zero.
Infix "+" := add.

Check forall (M : AddComoid.type) (x : M), x + x = 0.

This is all we need to do in order to declare the AddComoid structure and write statements in its signature.

We proceed by declaring how to obtain an Abelian group out of the additive, commutative, monoid.

HB.mixin Record IsAbelianGrp A of IsAddComoid A := {
  opp : A -> A;
  addNr : forall x, opp x + x = 0;
}.

HB.structure Definition AbelianGrp := { A of IsAbelianGrp A & IsAddComoid A }.

Notation "- x" := (opp x).

Abelian groups feature the operations and properties given by the IsAbelianGrp mixin (and its dependency IsAddComoid).

Lemma example (G : AbelianGrp.type) (x : G) : x + (- x) = - 0.
Proof. by rewrite addrC addNr -[LHS](addNr zero) addrC add0r. Qed.

We proceed by showing that Z is an example of both structures, and use the lemma just proved on a statement about Z.

HB.instance Definition Z_CoMoid :=
  IsAddComoid.Build Z 0%Z Z.add Z.add_assoc Z.add_comm Z.add_0_l.
 
HB.instance Definition Z_AbGrp :=
  IsAbelianGrp.Build Z Z.opp Z.add_opp_diag_l.

Lemma example2 (x : Z) : x + (- x) = - 0.
Proof. by rewrite example. Qed.

Documentation

This paper describes the language in details, and the corresponding talk is available on youtube. The wiki gathers some tricks and FAQs. If you want to work on the implementation of HB, this recorded hacking session may be relevant to you.

Installation & availability

(click to expand)

  • You can install HB via OPAM
opam repo add coq-released https://coq.inria.fr/opam/released
opam install coq-hierarchy-builder
  • You can use it in nix with the attribute coqPackages_8_XX.hierarchy-builder e.g. via nix-shell -p coq_8_13 -p coqPackages_8_13.hierarchy-builder

Key concepts

(click to expand)

  • a mixin is a bare bone building block of the hierarchy, it packs operations and axioms.

  • a factory is a package of operations and properties that is elaborated by HB to one or more mixin. A mixin is hence a trivial factory.

  • a structure is declared by attaching zero or more factories to a type.

  • a builder is a user provided piece of code capable of building one or more mixins from a factory.

  • an instance is an example of a structure: it provides all operation and fulfills all axioms.

The commands of HB

(click to expand)

  • HB core commands:

    • HB.mixin declares a mixin,
    • HB.structure declares a structure,
    • HB.factory declares a factory,
    • HB.builders and HB.end declare a set of builders,
    • HB.instance declares a structure instance,
    • HB.declare declares a context with parameters, key and mixins.
    • HB.saturate reconsiders all mixin instances to see if some newly declared structure can be inhabited
  • HB core tactic-in-term:

    • HB.pack to synthesize a structure instance in the middle of a term.
  • HB utility commands:

    • HB.export exports a module and schedules it for re-export
    • HB.reexport exports all modules, instances and constants scheduled for re-export
    • HB.lock locks a definition behind an opaque symbol and an unfolding equation using Coq module system
  • HB queries:

    • HB.about is similar to About but prints more info on HB structures, like the known instances and where they are declared
    • HB.locate is similar to Locate, prints file name and line of any global constant synthesized by HB
    • HB.graph prints the structure hierarchy to a dot file
    • HB.howto prints sequences of factories to equip a type with a given structure
  • HB debug commands:

    • HB.status dumps the contents of the hierarchy (debug purposes)
    • HB.check is similar to Check (testing purposes)

The documentation of all commands can be found in the comments of structures.v, search for Elpi Command and you will find them. All commands can be prefixed with the attribute #[verbose] to get an idea of what they are doing.

For debugging and teaching purposes, passing the attributes #[log] or #[log(raw)] to a HB command prints Coq commands which are almost equivalent to its effect. Hence, copy-pasting the displayed commands into your source file is not expected to work, and we strongly recommend against it.

Demos

(click to expand)

  • demo1 and demo3 declare and evolve a hierarchy up to rings with various clients that are tested not to break when the hierarchy evolves
  • demo2 describes the subtle triangular interaction between groups, topological space and uniform spaces. Indeed, 1. all uniform spaces induce a topology, which makes them topological spaces, but 2. all topological groups (groups that are topological spaces such that the addition and opposite are continuous) induce a uniformity, which makes them uniform spaces. We solve this seamingly mutual dependency using HB.

hierarchy-builder's People

Contributors

cohencyril avatar gares avatar pi8027 avatar proux01 avatar skyskimmer avatar thery avatar thomasportet avatar ybertot avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

hierarchy-builder's Issues

HB.instance Definition f Params := ... (outside a section)

As of today we can only write

Section Foo.
Variable A : Type.
HB.instance Definition list_m1 := m1.Build (option A) (list nat) (cons 7 nil) None.
End Foo.

If we abstract list_m1 over A we get an assertion in

pred mixin-srcs i:term, i:term, o:list prop.
mixin-srcs T X MSL :- std.do! [
  std.assert-ok! (coq.typecheck X XTy) "mixin-src: X illtyped",
  if (not (safe-dest-app XTy (global _) _))
     (coq.error "Term:\n" {coq.term->string X}
                "\nhas type:\n" {coq.term->string XTy}
                "\nwhich is not a record")

Instead we should record the abstractions before the record and put them in front of S

pred declare-instances i:term, i:list class.
declare-instances T [class Class Struct MLwP|Rest] :-
  params->holes MLwP Params,
  get-class-constructor Class Params KC,
  list-w-params_list MLwP ML,
  mterm->term (mterm [/*Params already applied to KC*/] T ML KC) KCApp, % we can build it
  not (local-cs? T Struct), % not already built
  !,
  term->gref T TGR,
  coq.gref->id TGR TID,
  Name is TID ^ "_is_a_" ^ {term->modname Struct},

  if-verbose (coq.say "HB: declare canonical instance" Name),

  get-structure-constructor Struct Params KS,
  S = app[KS, T, KCApp],

Please create a tag for the upcoming release of Coq 8.13

The Coq team is planning to release Coq 8.13-beta1 on December 7, 2020
and Coq 8.13.0 on January 7, 2020.

Your project is currently scheduled for being bundled in the Windows installer.

We are currently testing commit 6089de4
on branch https://github.com/math-comp/hierarchy-builder/tree/coq-master
but we would like to ship a released version instead (a tag in git's slang).

Could you please tag that commit, or communicate us any other tag
that works with the Coq branch v8.13 at the latest 15 days before the
date of the final release?

Thanks!
CC: coq/coq#12334

[wish] hb.generates

I think I'd like a query printing out the mixins (and maybe their contents) that one can get from a set of given factories. In some sense it is what we were doing this morning by hand (used to be explicit in hb.end).

More in general Elpi Print hb.debug is too low level for a final user.
Maybe hb.debug could just have a real main and dump the DB in a human understandable format, but I think being able to query the DB without knowing how to write elpi code may help a final user.

Require Import hb and String scope.

Error messages given by, eg, HB.instance are not intellegible if the string scope is not open.
Should be Export an Open Scope string_scope in hb.v?

A bug with insertion of coercions

In the definition of mixin like the next one:

HB.mixin Record foo T := {
  bar : T -> true;
}.

there is an error without any meaningful explanation. However, after the insertion of coercion manually, it works fine:

HB.mixin Record foo T := {
  bar : T -> (is_true true);
}.

So, it would be great if the coercion insertion was automatic.

Tentative roadmap

I think:

  • we should remove the docs/paper thing
  • move hb.v to tool/HB.v and hb.elpi to tool/HB.elpi
  • move demo* to tests or examples (see the little testing infrastructure I wrote in Makefile.coq.local)
  • have a toplevel Makefile that builds tool (with coq_makefile) and then uses the result to build the rest, putting tool/ in the coqpath as if it was installed in user-contrib (so we test how final users would get HB`
  • make an opam & nix package out of this layout
  • advertise this first iteration of HB

code reorganization

It seems that we should have:

  • hb.elpi with most of the code, but for the various main. If there are conflicts we can use the namespace directive. In this way all commands can share utility code without putting it in the db.
  • hb.v were we declare hb.db with the class & co predicates, but nothing more
  • hb.v were we declare all commands. Each of them accumulates the db, then the file hb.elpi, then a short snippet defining the main, the usage message and having a coqdoc comment
  • demo.v with the demo code
  • in this way it is easy to have commands hb.factory.begin, hb.mixin.begin, hb.mixin.end and hb.factory.end sharing 99% of the code (as it is now, but without the "mixin" argument and the crapload of code in the db).

In a not so close future elpi DBs are supposed to be dynamic (compiled at each execution if needed), while the rest of the code compiled once and forall.

Inheritance of mathcomp's structures

Can you provide the best way to inherit mathcomp's structures? I want to make something like this:

Section foo.
Variable (T : eqType).

HB.mixin my_class_of_eqType T := { ... }. (*or something like that*)

Is there any way to inherit mathcomp's eqType?

HB commands telescope inferrence is dumb

When using HB commands requiring a telescope.
E.g.

HB.builders Context (V : zmodType) .... of stuff V

where stuff requires a zmodType, should make the explicit typing of v optional.

Example files don't run without changes with opam installed HB

If hierachy builder is installed via opam, the examples are

  • not installed
  • don't run if taken from somewhere else

This because they use require statements like From HB.demo2 Require Import classical. which assume that demo2 is installed with HB, but this is not the case. I see a few possible solutions:

1.) Install the examples required as prerequisites including .vo files
2.) Remove the From HB.demo2 so that files can be compiled locally one by one and run (e.g. in CoqIDE with compile buffer)
3.) Install the examples with a _CoqProject file which sets proper -Q options, so that this does work

Error message "you must declare X before Y" is bogus since parameters were introduced

Code

hierarchy-builder/hb.elpi

Lines 501 to 506 in 01c2492

pred assert-building-bottom-up i:class, i:classname.
assert-building-bottom-up CurrentClass C3n :-
class-def (class C3n X Y),
if (not (sub-class? CurrentClass (class C3n X Y)))
(coq.error "You must declare" CurrentClass "before" C3n)
true.

prints stuff like:

You must declare
class (indt «axioms») (global (indt «type»))
 (w-params.nil `A` (sort (typ «bug.9333»)) c0 \
   [triple (indt «Ops_of_Type.axioms_») [] c0,
    triple (indt «Setoid_of_Type.axioms_») [] c0,
    triple (indt «Ptt_of_Ops.axioms_») [] c0]) before
indt «Pttdom.axioms»

The "class" must be printed better, also we should try to print only structure names (classes are sort of internal)

A brief report on trying to port the Iris hierarchy to HB

Hey everyone,

I was very happy to see the hierarchy builder being announced and I wanted to see what would happen if I used it to define the hierarchy in Iris. This was really just for fun since I do not expect the result to be usable given Iris's reliance on type classes. I also wanted to learn from the resulting definitions since I still don't really understand how one is supposed to set up canonical structures.

But my experiment ended before I got to actually trying out the result. I pushed the experiment to https://gitlab.mpi-sws.org/janno/iris-coq/-/tree/janno/try-HB (the branch name is janno/try-HB). The only file that changed is https://gitlab.mpi-sws.org/janno/iris-coq/-/blob/janno/try-HB/theories/bi/interface.v. It contains both old an new definitions, which are confined to lines 150-178. The original file without my new stuff is here: https://gitlab.mpi-sws.org/iris/iris/-/blob/962637df10a879ac4b1b9d523854d6fa4c9e8fb4/theories/bi/interface.v

Of particular interest is https://gitlab.mpi-sws.org/janno/iris-coq/-/blob/janno/try-HB/theories/bi/interface.v#L242 where I cannot get HB to accept the definition of an SBI (an extension of the BI definition in https://gitlab.mpi-sws.org/janno/iris-coq/-/blob/janno/try-HB/theories/bi/interface.v#L156). The error HB reports is this (when using the right printing settings):

The term "@Some" of type "∀ A : Type, A → option A"
cannot be applied to the terms
 "?e5" : "Type"
 "("is not canonically a", bi.type)" : "(string * Type)%type"

I suppose the underlying error is a mistake on my side but I don't know what it would be.

To get to this point I also had to work around an unexpected shortcoming regarding implicit type class arguments. As you can see in the definition of the BI structure, I had to manually spell out all type class instances since HB would not accept the terms otherwise. (This is veeeeery annoying since it also means that notation such as that for equiv needs to be unfolded.)

Finally, there's something that I wouldn't count as a bug but more of a feature request: in the original Iris hierarchy, the bi_mixin Section (at the top of the file) creates local notation for the operators that make the axioms look very natural. I couldn't find a way to replicate this setup. Maybe HB.mixin could accept where clauses for (local) syntax?

Building the branch
My opam switch reports the following packages:

coq-elpi                1.3.1                     Elpi extension language for Coq
coq-hierarchy-builder   0.9.0                     Hierarchy Builder
coq-stdpp               dev.2019-12-06.0.1ef53c55 pinned to version dev.2019-12-06.0.1ef53c55 at git+https://gitlab.mpi-sws.org/iris/stdpp.git

If you want to avoid pinning coq-stdpp to the git hash (the suffix of that weird dev version) you can

opam repo add iris-dev https://gitlab.mpi-sws.org/iris/opam.git

and then opam should be able to find that exact version.

Running make inside a clone of my iris-coq branch should eventually compile interfaces.v and report the errors.

BUG with a `coq.env.add-const`

There is a bug in coq-elpi that I am failing to track down and minimize, @gares could you look into this?

hierarchy-builder/demo2.v

Lines 597 to 601 in 08064db

% TODO BUGFIX: Why is this making coq-elpi make Coq raise an anomaly?
% the bug suddenly appeared while changing sections during an elpi program.
%
% Name is {gref->modname Src} ^ "_to_" ^ {gref->modname Tgt},
% coq.env.add-const Name GoF _GoFTy ff ff GoFC,

The bug was particularly hard to track, because uncommenting the above coq.env-add-const unexpectedly makes the following coq.typecheck fail... (which succeeds otherwise,... this is a really nasty side-effect)

coq.typecheck F Ty,

The bug was not there before, because we used to called Elpi declare_factory_fun ... after we manually closed the section and the module using the vernacular End S. End Module.. But since then, I decided to make the same elpi command close the section and call main-declare-factory-fun, using coq.env.end-section:

coq.env.end-section,

under-canonical-mixins should filter the CS db better

See: https://coq.zulipchat.com/#narrow/stream/237868-Hierarchy-Builder.20devs.20.26.20users/topic/instance.20family.20bug.3F

Test case:

From HB Require Import structures.

HB.mixin Record base_m T := { A : T }.
HB.structure Definition base := { T of base_m T }.

HB.mixin Record child1_m T := { C1 : T }.
HB.structure Definition child1 := { T of base T & child1_m T }.

HB.mixin Record child2_m T := { C2 : T }.
HB.structure Definition child2 := { T of base T & child2_m T }.

Axiom ix : Type.
Definition vec T := ix -> T.

Section b.
Variable T : base.type.
HB.instance Definition v_base_m : base_m (vec T) :=
  base_m.Build _ (fun _ => A).
End b.

Section c1.
Variable T : child1.type.
HB.instance Definition v_child1_m : child1_m (vec T) :=
    child1_m.Build _ (fun _ => C1).
End c1.

Section c2.
Variable T : child2.type.

  (* CS lookup for `vec` says yes... but the instance is for a paramter T of different type, kaboom *)
  HB.instance Definition v_child2_m : child2_m (vec T) :=
  child2_m.Build _ (fun _ => C2).

End c2.

[mock up] RING structure have no inverse

May I add it here?

hierarchy-builder/demo.v

Lines 42 to 50 in 5f59a25

Module RING.
Axiom from_asg_laws : forall T : ASG.type, T -> (T -> T -> T) -> Prop.
Record mixin_of (A : ASG.type) := Mixin {
one : A;
times : A -> A -> A;
_ : from_asg_laws A one times;
}.

We would need to replace this instance with the ring of integers.

hierarchy-builder/demo.v

Lines 93 to 97 in 5f59a25

Axiom N_asg : ASG.laws nat 0 Nat.add.
Canonical NasgType := ASG.Make nat (ASG.Mixin _ _ _ N_asg).
Axiom N_ring : RING.from_asg_laws _ 1 Nat.mul.
Canonical NringType := RING.Make nat (RING.Mixin _ _ _ N_ring).

HB forgets about Canonical Instance

HB.mixin Record eqType_of_Type T := {
  op  : rel T;
  eqP : Equality.axiom op;
}.

HB.structure Definition eq := { T of eqType_of_Type T }.


Canonical hb_eqMixin {T : eq.type} := @EqMixin T _ eqP.
Canonical hb_eqType {T : eq.type} := Eval hnf in EqType T hb_eqMixin.
Definition foo {T : eq.type} (e : T) := e == e.

HB.mixin Record my_class_of_eqType T of eq T := {
  foo: T -> T;
}.

HB.structure Definition my := { T of eq T & my_class_of_eqType T }.

Fail Definition foo1 {T : my.type} (e : T) := e == e.
Fail Canonical porder_eqMixin {T : my.type} := @EqMixin T _ eqP.

I want to make my structure with decidable equality via HB. Then it could be an instance of mathcomp's eqType. I make my.type that inherits eq.type, so my.type is coercible to eq.type which is coercible to eqType. But if you look at foo1 definition you can see that Coq can't solve such a unification problem. Also, I can't make a new Canonical instance for my.type because it conflicts with hb_eqMixin.

[DRAFT] new syntax

#[mixin]
HB Record AbGroup.axioms A of (Monoid.axioms A) := { opp : A->A; stuff..  }.

#[factory]
HB Record Monoid_of_Type.axioms A := { ... } as f.
  #[builder] HB Definition _ : AbGroup.axioms A _ := AbGroup.Axioms A (foo f).
HB End.

HB Structure Ring of Foo.axioms Bar.axioms.

HB Instance T AxT.

Uniform the syntax of HB.structure and HB.mixin/factory

Declare Scope HB_scope.
Notation "{  x  &  P }" := (sigT (fun x : Type => P%type)) (at level 0, x at level 99) : HB_scope.
Notation "{  x  'of'  P  &  ..  &  Q  }" := (sigT (fun x : Type => (prod P .. (prod Q True) ..)%type)) (at level 0, x at level 99) : HB_scope.
Global Open Scope HB_scope.

Check { T of False * True & { W of W = T } & option T }.
Check { T & T * True }.

This seems to work and make it possible to use "A of .. & .." also in structures.

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.