pytact.data_reader
This module provides read access to dataset files of a Tactican API dataset.
Additionally, there is support for communicating with a Coq processes through
the same data-format. The next sections give an overview of how this can be
accomplished. For an overview of examples, see pytact
.
Reading a dataset
The dataset is mapped into memory using mmap, allowing random access to it's structures while keeping memory low. This file contains three entry-points to a dataset in order of preference:
- Contextmanager
data_reader(path)
provides high-level access to the data in directorypath
. This is the preferred entry-point unless you need something special. - Contextmanager
lowlevel_data_reader(path)
provides low-level access to the data in directorypath
, giving direct access to the Cap'n Proto structures of the dataset. Use this whendata_reader
is too slow or you need access to data not provided bydata_reader
. - Contextmanager
file_dataset_reader
provides low-level access to the Cap'n Proto structures of a single file. Using this is usually not advisable.
Additionally, some indexing and traversal helpers are provided:
GlobalContextSets
calculates and caches the global context of a definition as a set, also caching intermediate results.definition_dependencies
andnode_dependencies
traverse the graph starting from a node and return all direct, non-transitive definitions that node depends on.
Communicating with a Coq process
Communication with a Coq process can be done either through a high-level or low-level interface.
Highlevel interface
The function capnp_message_generator
converts a socket into a nested generator that
yields request messages for predictions and expects to be sent response messages
in return. A simple example of how to handle these messages is in pytact.fake_python_server
.
Some docs can be found with capnp_message_generator
.
The capnp_message_generator
function can also dump the sequence of messages send
and received to a file. One can then use capnp_message_generator_from_file
to replay
that sequence against a server, either in a unit-test where the call to capnp_message_generator
is mocked by capnp_message_generator_from_file
, or using a fully fledged socket test
as can be found in pytact.fake_coq_client
.
Lowlevel interface
The function capnp_message_generator_lowlevel
converts a socket into a generator that
yields lowlevel Cap'n Proto request messages for predictions and expects to be sent Cap'n proto
messages in return. There are four types of messages msg
Coq sends.
- Synchronize: If
msg.is_synchronize
is true, Coq is attempting to synchronize its state with the server. APredictionProtocol.Response.synchronized
message is expected in return. - Initialize: If
msg.is_initialize
is true, Coq is sending a list of available tactics and a global context fragment to be added to an existing stack of global context information. An empty stack can be created throughempty_online_definitions_initialize
. To add an initialize message to the stack, you can use
Any subsequent messages will be made in the context of the tactics and predictions sent in this message, until an initialize message is received such thatwith online_definitions_initialize(existing_stack, msg) as definitions: print(type(definitions))
msg.initialize.stack_size
is smaller than the current stack size. APredictionProtocol.Response.initialized
message is expected in response of this message. - Predict: If
msg.is_predict
is true, Coq is asking to predict a list of plausible tactics given a proof state. The proof state can be easily accessed using
Awith online_data_predict(definitions, msg.predict) as proof_state: print(dir(proof_state))
PredictionProtocol.Response.prediction
orPredictionProtocol.Response.textPrediction
message is expected in return. - Check Alignment: If
msg.is_check_alignment
is true, then Coq is asking the server to check which tactics and definitions are known to it. APredictionProtocol.Response.alignment
message is expected in return.
You can wrap the generator produced by capnp_message_generator_lowlevel
into
record_lowlevel_generator
in order to record the exchanged messages to disk.
This trace can later be replayed using
capnp_message_generator_from_file_lowlevel
(or using the high-level interface).
1# NOTE: This file is derived from data_reader.pyx. Any changes here should be reflected there as well. 2 3"""This module provides read access to dataset files of a Tactican API dataset. 4Additionally, there is support for communicating with a Coq processes through 5the same data-format. The next sections give an overview of how this can be 6accomplished. For an overview of examples, see `pytact`. 7 8# Reading a dataset 9 10The dataset is mapped into memory using mmap, allowing random access to it's 11structures while keeping memory low. This file contains three entry-points to a 12dataset in order of preference: 13 141. Contextmanager `pytact.data_reader.data_reader(path)` provides high-level access to the data 15 in directory `path`. This is the preferred entry-point unless you need 16 something special. 172. Contextmanager `pytact.data_reader.lowlevel_data_reader(path)` provides low-level access to 18 the data in directory `path`, giving direct access to the Cap'n Proto structures 19 of the dataset. Use this when `data_reader` is too slow or you need access 20 to data not provided by `data_reader`. 213. Contextmanager `file_dataset_reader` provides low-level access to 22 the Cap'n Proto structures of a single file. Using this is usually not 23 advisable. 24 25Additionally, some indexing and traversal helpers are provided: 26- `GlobalContextSets` calculates and caches the global context of a definition 27 as a set, also caching intermediate results. 28- `definition_dependencies` and `node_dependencies` traverse the graph starting 29 from a node and return all direct, non-transitive definitions that node depends on. 30 31# Communicating with a Coq process 32 33Communication with a Coq process can be done either through a high-level or 34low-level interface. 35 36## Highlevel interface 37 38The function `capnp_message_generator` converts a socket into a nested generator that 39yields request messages for predictions and expects to be sent response messages 40in return. A simple example of how to handle these messages is in `pytact.fake_python_server`. 41Some docs can be found with `capnp_message_generator`. 42 43The `capnp_message_generator` function can also dump the sequence of messages send 44and received to a file. One can then use `capnp_message_generator_from_file` to replay 45that sequence against a server, either in a unit-test where the call to `capnp_message_generator` 46is mocked by `capnp_message_generator_from_file`, or using a fully fledged socket test 47as can be found in `pytact.fake_coq_client`. 48 49## Lowlevel interface 50 51The function `capnp_message_generator_lowlevel` converts a socket into a generator that 52yields lowlevel Cap'n Proto request messages for predictions and expects to be sent Cap'n proto 53messages in return. There are four types of messages `msg` Coq sends. 541. Synchronize: If `msg.is_synchronize` is true, Coq is attempting to synchronize 55 its state with the server. A `PredictionProtocol.Response.synchronized` message is expected 56 in return. 572. Initialize: If `msg.is_initialize` is true, Coq is sending a list of available 58 tactics and a global context fragment to be added to an existing stack of global context 59 information. An empty stack can be created through `empty_online_definitions_initialize`. 60 To add an initialize message to the stack, you can use 61 ``` 62 with pytact.data_reader.online_definitions_initialize(existing_stack, msg) as definitions: 63 print(type(definitions)) 64 ``` 65 Any subsequent messages will be made in the context of the 66 tactics and predictions sent in this message, until an initialize message is received 67 such that `msg.initialize.stack_size` is smaller than the current stack size. 68 A `PredictionProtocol.Response.initialized` message is expected in response of this message. 694. Predict: If `msg.is_predict` is true, Coq is asking to predict a list of plausible 70 tactics given a proof state. The proof state can be easily accessed using 71 ``` 72 with pytact.data_reader.online_data_predict(definitions, msg.predict) as proof_state: 73 print(dir(proof_state)) 74 ``` 75 A `PredictionProtocol.Response.prediction` or `PredictionProtocol.Response.textPrediction` 76 message is expected in return. 775. Check Alignment: If `msg.is_check_alignment` is true, then Coq is asking the server 78 to check which tactics and definitions are known to it. A 79 `PredictionProtocol.Response.alignment` message is expected in return. 80 81You can wrap the generator produced by `capnp_message_generator_lowlevel` into 82`record_lowlevel_generator` in order to record the exchanged messages to disk. 83This trace can later be replayed using 84`capnp_message_generator_from_file_lowlevel` (or using the high-level interface). 85 86""" 87 88from __future__ import annotations 89from contextlib import contextmanager, ExitStack 90from dataclasses import dataclass 91from typing import Any, Callable, TypeAlias, TypeVar, Union, cast, BinaryIO 92from collections.abc import Iterable, Sequence, Generator 93from pathlib import Path 94from immutables import Map 95import signal 96import pytact.graph_api_capnp_cython as apic # type: ignore 97import capnp# type: ignore 98import pytact.graph_api_capnp as graph_api_capnp # type: ignore 99import socket 100import mmap 101import itertools 102import resource 103import threading 104import subprocess 105import shutil 106import time 107 108@contextmanager 109def file_dataset_reader(fname: Path) -> Generator[apic.Dataset_Reader, None, None]: 110 """Load a single dataset file into memory, and expose its raw Cap'n Proto structures. 111 112 This is a low-level function. Prefer to use `data_reader` or `lowlevel_data_reader`. 113 """ 114 ... 115 116class LowlevelDataReader: 117 """A thin wrapper around the raw Cap'n Proto structures contained in a dataset directory. 118 119 Every file in the directory is assigned an integer called a graph-id. This class is a 120 `Sequence` that allows the retrieval of the structures in a file by its graph-id. 121 Additionally, the function `local_to_global` translates a dependency-index relative to 122 a graph-id to a new graph-id. This allows one to find out in which file a node in a 123 graph is located. 124 125 This is a lowlevel interface. For details on using the exposed structures the documentation 126 in the Cap'n Proto API file. 127 """ 128 129 graphid_by_filename : dict[Path, int] 130 """Map from filenames in the data directory to their graph-id's.""" 131 132 graph_files : list[Path] 133 """Map's a graph-id to a filename. Inverse of `graphid_by_filename`.""" 134 135 def local_to_global(self, graph: int, dep_index: int) -> int: 136 """Convert a dependency-index relative to a graph-id to a new graph-id. 137 138 This is used to find the graph-id where a particular node can be found. If `graph` is the 139 graph-id that contains a reference to a node and `dep_index` is the relative location 140 where that node can be found then `local_to_global(graph, dep_index)` finds the graph-id 141 of the file where the node is physically located. 142 """ 143 ... 144 145 def __getitem__(self, graph: int): 146 """Retrieve the raw Cap'n Proto structures associated with a graph-id.""" 147 ... 148 149 def __len__(self) -> int: ... 150 151@contextmanager 152def lowlevel_data_reader(dataset_path: Path) -> Generator[LowlevelDataReader, None, None]: 153 """Map a directory of dataset files into memory, and expose their raw Cap'n Proto structures. 154 155 Arguments: 156 `dataset_path`: Can either be a dataset directory, or a SquashFS image file. In case of an image 157 file `dataset.squ`, the image will be mounted using `squashfuse` on directory 158 `dataset/`, after which the contents of that directory will be read. 159 160 This is a low-level function. Prefer to use `data_reader`. See `LowlevelDataReader` for 161 further documentation. 162 """ 163 ... 164 165ProofStateId = int 166TacticId = int 167GraphId = int 168NodeId = int 169NodeHash = int 170 171class Node: 172 """A node in the calculus of inductive construction graph. 173 174 A node has a `label`, a unique `identity` and `children`. Some nodes are also 175 a `Definition`. 176 """ 177 178 graph : GraphId 179 """The id of the graph in which this node occurs. For lowlevel use only.""" 180 181 nodeid : NodeId 182 """The local id of the node in the dataset. For lowlevel use only.""" 183 184 def __repr__(self): 185 ... 186 187 def __eq__(self, other: object) -> bool: 188 """Physical equality of two nodes. Note that two nodes with a different physical equality 189 may have the same `identity`. See `identity` for details. 190 """ 191 ... 192 193 def __hash__(self): 194 """A hash that is corresponds to physical equality, not to be confused by `identity`.""" 195 ... 196 197 @property 198 def label(self) -> apic.Graph_Node_Label_Reader: 199 """The label of the node, indicating it's function in the CIC graph.""" 200 ... 201 202 @property 203 def identity(self) -> NodeHash: 204 """The identity of a node uniquely determines it. That is, one can consider any to nodes with the same 205 identity to be equal. The notion of equal we use is as follows: 206 1. Graph perspective: Two nodes have the same identity if and only if they are bisimilar. 207 In this notion, bisimilarity does take into consideration the label of the nodes, modulo some 208 equivalence class that is not fully specified here. One aspect of the equivalence class is that 209 for definition nodes their associated global context (accessed through `Definition.previous`) is 210 not taken into account. 211 2. Lambda calculus perspective: Two nodes have the same identity if their corresponding lambda terms 212 are alpha-equivalent. Note that two definitions with the same body are not considered 213 alpha-equivalent. 214 215 The identity of a node is used to perform partial graph-sharing. That is, two nodes with the same 216 identity are merged when the graph is generated. There are two reasons why two nodes with the same 217 semantic identity might have a different physical identity: 218 1. Nodes are only merged when the first node exists in the same graph as the second node, or exists 219 in a dependent graph. Hence, nodes originating from developments that do not depend on each other 220 are never merged. Full graph-sharing would require global analysis on a dataset, which any consumer 221 can optionally do as a post-processing step. 222 2. Two definition nodes with the same name and body have the same identity. But if they occur in 223 different global contexts, these nodes are physically different to ensure the integrity of their 224 global contexts. 225 226 Beware that the identity is currently a 64 bit field. For datasets that have graphs of size in the 227 order of billions of nodes there is a non-trivial chance of a collision. (We consider this acceptable 228 for machine learning purposes.) 229 """ 230 ... 231 232 @property 233 def children(self) -> Sequence[tuple[int, Node]]: 234 """The children of a node, together with the labels of the edges towards the children. 235 Note that for efficiency purposes, the label is represented as an integer. The corresponding 236 enum of this integer is `graph_api_capnp.EdgeClassification`.""" 237 ... 238 239 @property 240 def definition(self) -> Definition | None: 241 """Some nodes in the CIC graph represent definitions. Such nodes contain extra information about the 242 definition. 243 """ 244 ... 245 246class ProofState: 247 """A proof state represents a particular point in the tactical proof of a constant.""" 248 249 @property 250 def lowlevel(self): 251 ... 252 def __repr__(self): 253 ... 254 255 @property 256 def root(self) -> Node: 257 """The entry-point of the proof state, all nodes that are 'part of' the proof state are 258 reachable from here.""" 259 ... 260 261 @property 262 def context(self) -> Sequence[Node]: 263 """The local context of the proof state, given as a tuple of their original name as they appeared in the 264 proof and the corresponding node. 265 266 The nodes always have either label `contextAssum` or `contextDef`. 267 Note that these nodes are also reachable from the root of the proof state. 268 269 The names of the context elements should be used for debugging and viewing purposes only, because 270 hypothesis-generating tactics have been modified to use auto-generated names. Hence, tactics should 271 not be concerned about the names of the context. 272 """ 273 ... 274 275 @property 276 def context_names(self) -> Sequence[str]: 277 """The names of the local context nodes of the proof state, as they originally appeared in the proof. 278 279 These names should be used for debugging and viewing purposes only, because hypothesis-generating tactics have 280 been modified to use auto-generated names. Hence, tactics should not be concerned about the names of 281 the context. 282 """ 283 ... 284 285 @property 286 def context_text(self) -> Sequence[str]: 287 """A textual representation of the type/definition of context nodes 288 """ 289 ... 290 291 @property 292 def conclusion_text(self) -> str: 293 """A textual representation of the conclusion of the proof state. 294 """ 295 ... 296 297 @property 298 def text(self) -> str: 299 """A textual representation of the proof state.""" 300 ... 301 302 def __str__(self) -> str: 303 ... 304 305 @property 306 def id(self) -> ProofStateId: 307 """ 308 A unique identifier of the proof state. Any two proof states in a tactical proof that have an equal id 309 can morally be regarded to be 'the same' proof state. 310 IMPORTANT: Two proof states with the same id may still have different contents. This is because proof states 311 can contain existential variables (represented by the `evar` node) that can be filled as a 312 side-effect by a tactic running on another proof state. 313 """ 314 ... 315 316Unresolvable : TypeAlias = None 317Unknown : TypeAlias = None 318class Outcome: 319 """An outcome is the result of running a tactic on a proof state. A tactic may run on multiple proof states.""" 320 321 tactic : apic.Tactic_Reader | Unknown 322 """The tactic that generated the outcome. For it's arguments, see `tactic_arguments` 323 324 Sometimes a tactic cannot or should not be recorded. In those cases, it is marked as 'unknown'. 325 This currently happens with tactics that are run as a result of the `Proof with tac` construct and it 326 happens for tactics that are known to be unsafe like `change_no_check`, `fix`, `cofix` and more. 327 """ 328 329 @property 330 def lowlevel(self): 331 ... 332 def __repr__(self): 333 ... 334 335 @property 336 def before(self) -> ProofState: 337 """The proof state before the tactic execution.""" 338 ... 339 340 @property 341 def after(self) -> Sequence[ProofState]: 342 """The new proof states that were generated by the tactic.""" 343 ... 344 345 @property 346 def term(self) -> Node: 347 """The proof term that witnesses the transition from the before state to the after states. It contains a 348 hole (an `evar` node) for each of the after states. It may also refer to elements of the local context of 349 the before state. 350 """ 351 ... 352 353 @property 354 def term_text(self) -> str: 355 """A textual representation of the proof term.""" 356 ... 357 358 @property 359 def tactic_arguments(self) -> Sequence[Node | Unresolvable]: 360 """The arguments of the tactic that produced this outcome. 361 362 The node is the root of a graph representing an argument that is a term in the calculus of constructions. 363 Sometimes, an argument is not resolvable to a term, in which case it is marked as `Unresolvable`. 364 """ 365 ... 366 367class ProofStep: 368 """A proof step is the execution of a single tactic on one or more proof states, producing a list of outcomes. 369 """ 370 371 @property 372 def lowlevel(self): 373 ... 374 def __repr__(self): 375 ... 376 377 @property 378 def tactic(self) -> apic.Tactic_Reader | Unknown: 379 """The tactic that generated the proof step. Note that the arguments of the tactic can be found in the 380 individual outcomes, because they may be different for each outcome. 381 382 Sometimes a tactic cannot or should not be recorded. In those cases, it is marked as 'unknown'. 383 This currently happens with tactics that are run as a result of the `Proof with tac` construct and it 384 happens for tactics that are known to be unsafe like `change_no_check`, `fix`, `cofix` and more. 385 """ 386 ... 387 388 @property 389 def outcomes(self) -> Sequence[Outcome]: 390 """A list of transformations of proof states to other proof states, as executed by the tactic of the proof 391 step 392 """ 393 ... 394 395@dataclass 396class Original: 397 """Token that signals that a definition is original, as inputted by the 398 user.""" 399 pass 400 401@dataclass 402class Discharged: 403 """Token that signals that a definition is derived from an original after 404 section closing.""" 405 406 original: Definition 407 408@dataclass 409class Substituted: 410 """Token that signals that a definition is derived from an original after 411 module functor instantiation.""" 412 413 original: Definition 414 415@dataclass 416class Inductive: 417 """Token that signals that a definition is inductive.""" 418 419 representative: Definition 420 """The representative of the mutually recursive cluster. For lowlevel use only""" 421 422@dataclass 423class Constructor: 424 """Token that signals that a definition is a constructor.""" 425 426 representative: Definition 427 """The representative of the mutually recursive cluster. For lowlevel use only""" 428 429@dataclass 430class Projection: 431 """Token that signals that a definition is a projection.""" 432 433 representative: Definition 434 """The representative of the mutually recursive cluster. For lowlevel use only""" 435 436@dataclass 437class ManualConstant: 438 """Token that signals that a definition was inputted by the user by 439 manually inputting a term.""" 440 pass 441 442@dataclass 443class TacticalConstant: 444 """Token that signals that a lemma was proved by the user using 445 a tactic proof.""" 446 447 proof: Sequence[ProofStep] 448 """The proof of the lemma.""" 449 450@dataclass 451class ManualSectionConstant: 452 """Token that signals that a constant is a section variable or let-construct.""" 453 pass 454 455@dataclass 456class TacticalSectionConstant: 457 """Token that signals that a constant is a section let-construct with a tactic proof.""" 458 459 proof: Sequence[ProofStep] 460 """The proof of the lemma.""" 461 462class Definition: 463 """A definition of the CIC, which is either a constant, inductive, constructor, projection or section 464 variable. Constants and section variables can have tactical proofs associated to them. 465 """ 466 467 node : Node 468 """The node that is associated with this definition. It holds that 469 `definition.node.definition == definition`. 470 """ 471 472 @property 473 def lowlevel(self): 474 ... 475 def __repr__(self): 476 ... 477 478 def __eq__(self, other: object) -> bool: 479 """Physical equality of two nodes. Note that two nodes with a different physical equality 480 may have the same `identity`. See `identity` for details. 481 """ 482 ... 483 484 def __hash__(self): 485 """A hash that is corresponds to physical equality, not to be confused by `identity`.""" 486 ... 487 488 @property 489 def name(self) -> str: 490 """The fully-qualified name of the definition. The name should be unique in a particular global context, 491 but is not unique among different branches of the global in a dataset. 492 """ 493 ... 494 495 @property 496 def previous(self) -> Definition | None: 497 """The previous definition within the global context of the current file. 498 499 Note that this is a lowlevel property. Prefer to use `global_context` or `clustered_global_context`. 500 501 The contract on this field is that any definition nodes reachable from the forward closure of the definition 502 must also be reachable through the chain of previous fields. An exception to this rule are mutually 503 recursive definitions. Those nodes are placed into the global context in an arbitrary ordering. 504 """ 505 ... 506 507 @property 508 def external_previous(self) -> Sequence[Definition]: 509 """A list of definitions that are the representatives of files other than the current file that are 510 part of the global context. This list becomes populated when a `Require` statement occurred right before 511 the definition. 512 513 Note that this is a lowlevel property. Prefer to use `global_context` or `clustered_global_context`. 514 """ 515 ... 516 517 def global_context(self, across_files : bool = True, inclusive = False) -> Iterable[Definition]: 518 """All of the definitions in the global context when this definition was created. 519 520 Note that this does not include this definition itself, except when the definition is a inductive, 521 constructor or projection. Because those are mutually recursive objects, they reference themselves 522 and are therefore part of their own global context. 523 524 The resulting iterable is topologically sorted. That is, for any definition in the stream, any 525 definition reachable from the forward closure of the definition also exists in the remainder of the 526 stream. An exception to this rule are mutually recursive definitions, because no topological sort 527 is possible there (see also `clustered_global_context`). 528 529 Arguments: 530 * `across_files`: if `False`, outputs only the definitions from the local file, default `True`. 531 * `inclusive`: if `True`, outputs also itself, default `False`. 532 Note: if it is a self-recursive definition, the `inclusive` argument is ignored, and considered as `True` 533 """ 534 ... 535 536 def clustered_global_context(self, across_files : bool = True, inclusive : bool = False) -> Iterable[list[Definition]]: 537 """All of the definitions in the global context when this definition was created, clustered into 538 mutually recursive cliques. 539 540 The resulting iterable is topologically sorted. That is, for any definition in the stream, any 541 definition reachable from the forward closure of the definition also exists in the remainder of the 542 stream. 543 544 Arguments: 545 * `across_files`: if `False`, outputs only the definitions from the local file, default `True`. 546 * `inclusive`: if `True`, outputs also the cluster of itself, default `False`. 547 Note: if it is a self-recursive definition, the `inclusive` argument is ignored, and considered as `True`. 548 """ 549 ... 550 551 @property 552 def status(self) -> Original | Discharged | Substituted: 553 """ 554 A definition is either 555 (1) an object as originally inputted by the user. 556 (2) a definition that was originally defined in a section and has now had the section 557 variables discharged into it. 558 (3) a definition that was obtained by performing some sort of module functor substitution. 559 When a definition is not original, we cross-reference to the definition that it was derived from. 560 """ 561 ... 562 563 @property 564 def kind(self) -> Union[Inductive, Constructor, Projection, 565 ManualConstant, TacticalConstant, 566 ManualSectionConstant, TacticalSectionConstant]: 567 """The kind of the definition. 568 569 It can be an constant, section constant, inductive, constructor or projection. In case of a constant 570 of a constant or section constant, an optional tactical proof can be associated. In case of an inductive, 571 constructor or projection, another definition that acts as the representative of the mutually recursive 572 cluster of definitions is associated. 573 574 The associated information is low-level. Prefer to use the properties `proof` and `cluster` to access them. 575 """ 576 ... 577 578 @property 579 def proof(self) -> Sequence[ProofStep] | None: 580 """An optional tactical proof that was used to create this definition.""" 581 ... 582 583 @property 584 def cluster_representative(self) -> Definition: 585 """A unique representative of the mutually recursive cluster of definitions this definition is part of. 586 If the definition is not mutually recursive, the representative is itself. 587 588 This is a low-level property. Prefer to use the `cluster` property. 589 """ 590 ... 591 592 @property 593 def cluster(self) -> Iterable[Definition]: 594 """The cluster of mutually recursive definitions that this definition is part of. 595 If the definition is not mutually recursive, the cluster is a singleton.""" 596 ... 597 598 @property 599 def type_text(self) -> str: 600 """A textual representation of the type of this definition.""" 601 ... 602 603 @property 604 def term_text(self) -> str | None: 605 """A textual representation of the body of this definition. 606 For inductives, constructors, projections, section variables and axioms this is `None`. 607 """ 608 ... 609 610 @property 611 def is_file_representative(self) -> bool: 612 """Returns true if this definition is the representative of the super-global context of it's file. 613 Se also `Dataset.representative`.""" 614 ... 615 616class Dataset: 617 """The data corresponding to a single Coq source file. The data contains a representation of all definitions 618 that have existed at any point throughout the compilation of the source file. 619 """ 620 621 graph : GraphId 622 filename : Path 623 """The physical file in which the data contained in this class can be found.""" 624 625 @property 626 def lowlevel(self): 627 ... 628 def __repr__(self): 629 ... 630 631 @property 632 def dependencies(self) -> Sequence[Path]: 633 """A list of physical paths of data files that are direct dependencies of this file. 634 635 It is guaranteed that no cycles exist in the dependency relation between files induced by this field. 636 """ 637 ... 638 639 @property 640 def representative(self) -> Definition | None: 641 """The entry point of the global context of definitions that are available when this file is 'Required' by 642 another file. The full global context can be obtained by following the `previous` node of definitions. 643 If the compilation unit does not contain any 'super'-global definitions this may be `None`. 644 645 This is a low-level property. 646 Prefer to use `definitions(spine_only = True)` and `clustered_definitions(spine_only=True)`. 647 """ 648 ... 649 650 def definitions(self, across_files = False, spine_only = False) -> Iterable[Definition]: 651 """All of the definitions present in the file. 652 Note that some of these nodes may not be part of the 'super-global' context. Those are definitions inside 653 of sections or module functors. 654 655 Arguments: 656 * `across_files`: if `True`, outputs also definitions from dependent files, default `False`. 657 * `spine_only`: if True, outputs only the definitions on the main spine, default `False`. 658 Note: `across_files = True` is incompatible with `spine_only = False`. 659 660 When `spine_only = True`, the resulting iterable is topologically sorted. That is, for 661 any definition in the stream, any definition reachable from the forward closure of the definition 662 also exists in the remainder of the stream. An exception to this rule are mutually recursive definitions, 663 because no topological sort is possible there (see also `clustered_definitions`). 664 """ 665 ... 666 667 def clustered_definitions(self, across_files = False, spine_only = False) -> Iterable[list[Definition]]: 668 """All of the definitions present in the file, clustered by mutually recursive definitions. 669 Note that some of these nodes may not be part of the 'super-global' context. Those are definitions inside 670 of sections or module functors. 671 672 Arguments: 673 * `across_files`: if `True`, outputs also definitions from dependent files, default `False`. 674 * `spine_only`: if `True`, outputs only the definitions on the main spine, default `False`. 675 Note: `across_files = True` is incompatible with `spine_only = False`. 676 677 When `spine_only = True`, the resulting iterable is topologically sorted. That is, for 678 any definition in the stream, any definition reachable from the forward closure of the definition 679 also exists in the remainder of the stream. 680 """ 681 ... 682 683 @property 684 def module_name(self) -> str: 685 ... 686 687 def node_by_id(self, nodeid: NodeId) -> Node: 688 """Lookup a node inside of this file by it's local node-id. This is a low-level function.""" 689 ... 690 691def lowlevel_to_highlevel(lreader : LowlevelDataReader) -> dict[Path, Dataset]: 692 """Convert a dataset initialized as a `LowLevelDataReader` into a high level interface.""" 693 ... 694 695@contextmanager 696def data_reader(dataset_path: Path) -> Generator[dict[Path, Dataset], None, None]: 697 """Load a directory of dataset files into memory, and expose the data they contain. 698 The result is a dictionary that maps physical paths to `Dataset` instances that allow access to the data. 699 700 Arguments: 701 `dataset_path`: Can either be a dataset directory, or a SquashFS image file. In case of an image 702 file `dataset.squ`, the image will be mounted using `squashfuse` on directory 703 `dataset/`, after which the contents of that directory will be read. 704 705 """ 706 ... 707 708class OnlineDefinitionsReader: 709 """This class represents a global context to Python by Coq, containing all 710 known definitions and available tactics.""" 711 712 def local_to_global(self, graph: int, dep_index: int) -> int: 713 """Convert a dependency-index relative to a graph-id to a new graph-id. 714 715 This is used to find the graph-id where a particular node can be found. If `graph` is the 716 graph-id that contains a reference to a node and `dep_index` is the relative location 717 where that node can be found then `local_to_global(graph, dep_index)` finds the index in 718 the global context stack where the node is physically located. 719 720 Lowlevel function. 721 """ 722 ... 723 724 @property 725 def representative(self) -> Definition | None: 726 """The last definition in the global context. All other definitions can be accessed by following 727 the `Definition.previous` chain starting from this definitions. 728 729 This is a low-level property. 730 Prefer to use `definitions` and `clustered_definitions`. 731 """ 732 ... 733 734 def definitions(self, full : bool = True) -> Iterable[Definition]: 735 """The list of definitions that are currently in the global context. 736 737 The resulting iterable is topologically sorted. That is, for any definition in the stream, any 738 definition reachable from the forward closure of the definition also exists in the remainder of 739 the stream. An exception to this rule are mutually recursive definitions, 740 because no topological sort is possible there (see also `clustered_definitions`). 741 """ 742 ... 743 744 def clustered_definitions(self, full : bool = True) -> Iterable[list[Definition]]: 745 """All of the definitions present in the global context, clustered by mutually recursive definitions. 746 747 The resulting iterable is topologically sorted. That is, for any definition in the stream, any 748 definition reachable from the forward closure of the definition also exists in the remainder of 749 the stream. 750 """ 751 ... 752 753@contextmanager 754def online_definitions_initialize(stack: OnlineDefinitionsReader, 755 init: apic.PredictionProtocol_Request_Initialize_Reader) -> Generator[OnlineDefinitionsReader, None, None]: 756 """Given a new initialization message sent by Coq, construct a 757 `OnlineDefinitiosnReader` object. This can be used to inspect the 758 definitions currently available. Additionally, using `online_data_predict` 759 it can be combined with a subsequent prediction request received from Coq 760 to build a `ProofState`. 761 """ 762 ... 763 764def empty_online_definitions_initialize() -> OnlineDefinitionsReader: 765 ... 766 767@contextmanager 768def online_data_predict(base: OnlineDefinitionsReader, 769 predict: apic.PredictionProtocol_Request_Predict_Reader) -> Generator[ProofState, None, None]: 770 """Given a `OnlineDefinitionsReader` instance constructed through 771 `online_data_initialize`, and a prediction message sent by Coq, construct a 772 `ProofState` object that represents the current proof state in Coq. 773 """ 774 ... 775 776@dataclass 777class TacticPredictionGraph: 778 ident : int 779 arguments : list[Node] 780 confidence : float 781 782@dataclass 783class TacticPredictionsGraph: 784 predictions : list[TacticPredictionsGraph] 785 786@dataclass 787class TacticPredictionText: 788 tactic_text : str 789 confidence : float 790 791@dataclass 792class TacticPredictionsText: 793 predictions : list[TacticPredictionsText] 794 795@dataclass 796class CheckAlignmentMessage: 797 pass 798 799@dataclass 800class CheckAlignmentResponse: 801 unknown_definitions : list[Definition] 802 unknown_tactics : list[int] 803 804@dataclass 805class GlobalContextMessage: 806 """A message containing a new global context sent to Python from Coq, 807 including all known definitions and available tactics.""" 808 809 definitions : OnlineDefinitionsReader 810 tactics : Sequence[apic.AbstractTactic_Reader] 811 812 log_annotation : str 813 """An annotation representing the current position of Coq in a source 814 document. For logging and debugging purposes.""" 815 816 prediction_requests : Generator[GlobalContextMessage | ProofState | CheckAlignmentMessage, 817 None | TacticPredictionsGraph | TacticPredictionsText | CheckAlignmentResponse, 818 None] 819 """A sub-generator that produces new requests from Coq that are based on or 820 extend the global context of the current message. Once the sub-generator 821 runs out, the parent generator continues.""" 822 823def capnp_message_generator_lowlevel(socket: socket.socket) -> ( 824 Generator[apic.PredictionProtocol_Request_Reader, 825 capnp.lib.capnp._DynamicStructBuilder, None]): 826 """A generator that facilitates communication between a prediction server and a Coq process. 827 828 Given a `socket`, this function creates a generator that yields messages of type 829 `pytact.graph_api_capnp_cython.PredictionProtocol_Request_Reader` after which a 830 `capnp.lib.capnp._DynamicStructBuilder` message needs to be `send` back. 831 """ 832 ... 833 834def capnp_message_generator_from_file_lowlevel( 835 message_file: BinaryIO, 836 check : Callable[[Any, Any, Any], None] | None = None) -> ( 837 Generator[apic.PredictionProtocol_Request_Reader, 838 capnp.lib.capnp._DynamicStructBuilder, None]): 839 """Replay and verify a pre-recorded communication sequence between Coq and a prediction server. 840 841 Lowlevel variant of `capnp_message_generator_from_file`. 842 843 Accepts a `message_file` containing a stream of Capt'n Proto messages as recorded using 844 `capnp_message_generator(s, record=message_file)`. The resulting generator acts just like the generator 845 created by `capnp_message_generator` except that it is not connected to the socket but just replays the 846 pre-recorded messages. 847 848 Arguments: 849 - `check` is an optional callable that can be used to compare the response of the server to the recorded 850 response. It accepts three arguments: The recorded message that was sent by Coq, the response of the server 851 and the recorded response. 852 """ 853 ... 854 855def record_lowlevel_generator( 856 record_file: BinaryIO, 857 gen: Generator[apic.PredictionProtocol_Request_Reader, 858 capnp.lib.capnp._DynamicStructBuilder, None]) -> ( 859 Generator[apic.PredictionProtocol_Request_Reader, 860 capnp.lib.capnp._DynamicStructBuilder, None]): 861 """Record a trace of the full interaction of a lowlevel generator to a file 862 863 Wrap a lowlevel generator (such as from `capnp_message_generator_lowlevel`) and dump all exchanged messages 864 to the given file. The file can later be replayed with `capnp_message_generator_from_file_lowlevel`. 865 """ 866 ... 867 868def prediction_generator( 869 lgenerator: Generator[apic.PredictionProtocol_Request_Reader, 870 capnp.lib.capnp._DynamicStructBuilder, None], 871 defs: OnlineDefinitionsReader): 872 """Given the current global context stack `defs`, convert a low-level 873 generator to a high-level `GlobalContextMessage`""" 874 ... 875 876def capnp_message_generator(socket: socket.socket, record: BinaryIO | None = None) -> GlobalContextMessage: 877 """A generator that facilitates communication between a prediction server and a Coq process. 878 879 Given a `socket`, this function creates a `GlobalContextMessage` `context`. This message contains an 880 initially empty list of available tactics and definitions in the global context. Through 881 `context.prediction_requests` one can access a generator that yields prediction requests and expects 882 predictions to be sent in response. The possible messages are as follows: 883 - `GlobalContextMessage`: An additional, nested, global context message that amends the current context 884 with additional tactics and definitions. The prediction requests of this nested context need to be 885 exhausted before continuing with messages from the current context. 886 - `CheckAlignmentMessage`: A request to check which of Coq's current tactics and definitions the 887 prediction server currently "knows about". The generator expects a `CheckAlignmentResponse` to be 888 sent in response. 889 - `ProofState`: A request to make tactic predictions for a given proof state. Either a 890 `TacticPredictionsGraph` or a `TacticPredictionsText` message is expected in return. 891 892 When `record` is passed a file descriptor, all received and sent messages will be dumped into that file 893 descriptor. These messages can then be replayed later using `capnp_message_generator_from_file`. 894 """ 895 ... 896 897def capnp_message_generator_from_file(message_file: BinaryIO, 898 check : Callable[[Any, Any, Any], None] | None = None, 899 record: BinaryIO | None = None) -> GlobalContextMessage: 900 """Replay and verify a pre-recorded communication sequence between Coq and a prediction server. 901 902 Highlevel variant of `capnp_message_generator_from_file_lowlevel`. 903 904 Accepts a `message_file` containing a stream of Capt'n Proto messages as recorded using 905 `capnp_message_generator(s, record=message_file)`. The resulting generator acts just like the generator 906 created by `capnp_message_generator` except that it is not connected to the socket but just replays the 907 pre-recorded messages. 908 909 Arguments: 910 - `check` is an optional callable that can be used to compare the response of the server to the recorded 911 response. It accepts three arguments: The recorded message that was sent by Coq, the response of the server 912 and the recorded response. 913 - `record` is an optional file that re-records the interaction with the current server 914 """ 915 ... 916 917class GlobalContextSets: 918 """Lazily retrieve a the global context of a definition as a set, with memoization. 919 920 Because this class can allocate (large) amounts of memory, use it as a context-manager. To create a new 921 instance, and retrieve the context of a definition, use: 922 ``` 923 with GlobalContextSets.new_context() as gcs: 924 gcs.global_context_set(my_definition) 925 ``` 926 This context will be cached, as well as intermediate results (global contexts of other definitions) as 927 long as the context-set is in scope. Caching can be nested by using `sub_context`: 928 ``` 929 with GlobalContextSets.new_context() as gcs: 930 gcs.global_context_set(my_definition) 931 with gcs.sub_context(lambda d:is_file_representative) as gcs_sub: 932 # gcs_sub remembers anything in the case of gcs 933 # caching is propagated to the parent cache only if the provided lambda evaluates to true 934 gcs_sub.global_context_set(my_definition2) 935 ``` 936 """ 937 def __init__(self, cache, parent: GlobalContextSets | None, 938 should_propagate: Callable[[Definition], bool]): 939 """Do not call directly. Use `GlobalContextSets.new_context` and `GlobalContextSets.sub_context`.""" 940 ... 941 942 def global_context_set(self, d: Definition) -> Map: 943 """Retrieve the global context of a definition, caching the result, and intermediate results.""" 944 ... 945 946 @contextmanager 947 def sub_context(self, propagate: Callable[[Definition], bool]) -> Generator[GlobalContextSets, None, None]: 948 """Create a sub-context with a separate cache from it's parent, but sharing any info that was 949 already present in the parent's cache. 950 951 For any intermediate results for a definition `d` for which `propagate(d)` evaluates to true, 952 the result is propagated to the parent's cache.""" 953 ... 954 955 @staticmethod 956 def new_context() -> Generator[GlobalContextSets, None, None]: 957 """Crate a new caching context where global-context-set's can be retrieved and cached.""" 958 ... 959 960def node_dependencies(n: Node, deps: set[Definition] | None = None) -> set[Definition]: 961 """Given a `Node` `n`, calculate the set of `Definition`'s that are directly reachable 962 from `n`. Transitively reachable definitions are not included. 963 """ 964 ... 965 966def definition_dependencies(d: Definition) -> set[Definition]: 967 """Given a `Definition` `d`, calculate the set of `Definition`'s that are directly reachable for `d`. 968 Transitively reachable definitions are not included nor is `d` itself. 969 """ 970 ...
109@contextmanager 110def file_dataset_reader(fname: Path) -> Generator[apic.Dataset_Reader, None, None]: 111 """Load a single dataset file into memory, and expose its raw Cap'n Proto structures. 112 113 This is a low-level function. Prefer to use `data_reader` or `lowlevel_data_reader`. 114 """ 115 ...
Load a single dataset file into memory, and expose its raw Cap'n Proto structures.
This is a low-level function. Prefer to use data_reader
or lowlevel_data_reader
.
117class LowlevelDataReader: 118 """A thin wrapper around the raw Cap'n Proto structures contained in a dataset directory. 119 120 Every file in the directory is assigned an integer called a graph-id. This class is a 121 `Sequence` that allows the retrieval of the structures in a file by its graph-id. 122 Additionally, the function `local_to_global` translates a dependency-index relative to 123 a graph-id to a new graph-id. This allows one to find out in which file a node in a 124 graph is located. 125 126 This is a lowlevel interface. For details on using the exposed structures the documentation 127 in the Cap'n Proto API file. 128 """ 129 130 graphid_by_filename : dict[Path, int] 131 """Map from filenames in the data directory to their graph-id's.""" 132 133 graph_files : list[Path] 134 """Map's a graph-id to a filename. Inverse of `graphid_by_filename`.""" 135 136 def local_to_global(self, graph: int, dep_index: int) -> int: 137 """Convert a dependency-index relative to a graph-id to a new graph-id. 138 139 This is used to find the graph-id where a particular node can be found. If `graph` is the 140 graph-id that contains a reference to a node and `dep_index` is the relative location 141 where that node can be found then `local_to_global(graph, dep_index)` finds the graph-id 142 of the file where the node is physically located. 143 """ 144 ... 145 146 def __getitem__(self, graph: int): 147 """Retrieve the raw Cap'n Proto structures associated with a graph-id.""" 148 ... 149 150 def __len__(self) -> int: ...
A thin wrapper around the raw Cap'n Proto structures contained in a dataset directory.
Every file in the directory is assigned an integer called a graph-id. This class is a
Sequence
that allows the retrieval of the structures in a file by its graph-id.
Additionally, the function local_to_global
translates a dependency-index relative to
a graph-id to a new graph-id. This allows one to find out in which file a node in a
graph is located.
This is a lowlevel interface. For details on using the exposed structures the documentation in the Cap'n Proto API file.
Map from filenames in the data directory to their graph-id's.
136 def local_to_global(self, graph: int, dep_index: int) -> int: 137 """Convert a dependency-index relative to a graph-id to a new graph-id. 138 139 This is used to find the graph-id where a particular node can be found. If `graph` is the 140 graph-id that contains a reference to a node and `dep_index` is the relative location 141 where that node can be found then `local_to_global(graph, dep_index)` finds the graph-id 142 of the file where the node is physically located. 143 """ 144 ...
Convert a dependency-index relative to a graph-id to a new graph-id.
This is used to find the graph-id where a particular node can be found. If graph
is the
graph-id that contains a reference to a node and dep_index
is the relative location
where that node can be found then local_to_global(graph, dep_index)
finds the graph-id
of the file where the node is physically located.
152@contextmanager 153def lowlevel_data_reader(dataset_path: Path) -> Generator[LowlevelDataReader, None, None]: 154 """Map a directory of dataset files into memory, and expose their raw Cap'n Proto structures. 155 156 Arguments: 157 `dataset_path`: Can either be a dataset directory, or a SquashFS image file. In case of an image 158 file `dataset.squ`, the image will be mounted using `squashfuse` on directory 159 `dataset/`, after which the contents of that directory will be read. 160 161 This is a low-level function. Prefer to use `data_reader`. See `LowlevelDataReader` for 162 further documentation. 163 """ 164 ...
Map a directory of dataset files into memory, and expose their raw Cap'n Proto structures.
Arguments:
dataset_path
: Can either be a dataset directory, or a SquashFS image file. In case of an image
file dataset.squ
, the image will be mounted using squashfuse
on directory
dataset/
, after which the contents of that directory will be read.
This is a low-level function. Prefer to use data_reader
. See LowlevelDataReader
for
further documentation.
172class Node: 173 """A node in the calculus of inductive construction graph. 174 175 A node has a `label`, a unique `identity` and `children`. Some nodes are also 176 a `Definition`. 177 """ 178 179 graph : GraphId 180 """The id of the graph in which this node occurs. For lowlevel use only.""" 181 182 nodeid : NodeId 183 """The local id of the node in the dataset. For lowlevel use only.""" 184 185 def __repr__(self): 186 ... 187 188 def __eq__(self, other: object) -> bool: 189 """Physical equality of two nodes. Note that two nodes with a different physical equality 190 may have the same `identity`. See `identity` for details. 191 """ 192 ... 193 194 def __hash__(self): 195 """A hash that is corresponds to physical equality, not to be confused by `identity`.""" 196 ... 197 198 @property 199 def label(self) -> apic.Graph_Node_Label_Reader: 200 """The label of the node, indicating it's function in the CIC graph.""" 201 ... 202 203 @property 204 def identity(self) -> NodeHash: 205 """The identity of a node uniquely determines it. That is, one can consider any to nodes with the same 206 identity to be equal. The notion of equal we use is as follows: 207 1. Graph perspective: Two nodes have the same identity if and only if they are bisimilar. 208 In this notion, bisimilarity does take into consideration the label of the nodes, modulo some 209 equivalence class that is not fully specified here. One aspect of the equivalence class is that 210 for definition nodes their associated global context (accessed through `Definition.previous`) is 211 not taken into account. 212 2. Lambda calculus perspective: Two nodes have the same identity if their corresponding lambda terms 213 are alpha-equivalent. Note that two definitions with the same body are not considered 214 alpha-equivalent. 215 216 The identity of a node is used to perform partial graph-sharing. That is, two nodes with the same 217 identity are merged when the graph is generated. There are two reasons why two nodes with the same 218 semantic identity might have a different physical identity: 219 1. Nodes are only merged when the first node exists in the same graph as the second node, or exists 220 in a dependent graph. Hence, nodes originating from developments that do not depend on each other 221 are never merged. Full graph-sharing would require global analysis on a dataset, which any consumer 222 can optionally do as a post-processing step. 223 2. Two definition nodes with the same name and body have the same identity. But if they occur in 224 different global contexts, these nodes are physically different to ensure the integrity of their 225 global contexts. 226 227 Beware that the identity is currently a 64 bit field. For datasets that have graphs of size in the 228 order of billions of nodes there is a non-trivial chance of a collision. (We consider this acceptable 229 for machine learning purposes.) 230 """ 231 ... 232 233 @property 234 def children(self) -> Sequence[tuple[int, Node]]: 235 """The children of a node, together with the labels of the edges towards the children. 236 Note that for efficiency purposes, the label is represented as an integer. The corresponding 237 enum of this integer is `graph_api_capnp.EdgeClassification`.""" 238 ... 239 240 @property 241 def definition(self) -> Definition | None: 242 """Some nodes in the CIC graph represent definitions. Such nodes contain extra information about the 243 definition. 244 """ 245 ...
A node in the calculus of inductive construction graph.
A node has a label
, a unique identity
and children
. Some nodes are also
a Definition
.
The identity of a node uniquely determines it. That is, one can consider any to nodes with the same identity to be equal. The notion of equal we use is as follows:
- Graph perspective: Two nodes have the same identity if and only if they are bisimilar.
In this notion, bisimilarity does take into consideration the label of the nodes, modulo some
equivalence class that is not fully specified here. One aspect of the equivalence class is that
for definition nodes their associated global context (accessed through
Definition.previous
) is not taken into account. - Lambda calculus perspective: Two nodes have the same identity if their corresponding lambda terms are alpha-equivalent. Note that two definitions with the same body are not considered alpha-equivalent.
The identity of a node is used to perform partial graph-sharing. That is, two nodes with the same identity are merged when the graph is generated. There are two reasons why two nodes with the same semantic identity might have a different physical identity:
- Nodes are only merged when the first node exists in the same graph as the second node, or exists in a dependent graph. Hence, nodes originating from developments that do not depend on each other are never merged. Full graph-sharing would require global analysis on a dataset, which any consumer can optionally do as a post-processing step.
- Two definition nodes with the same name and body have the same identity. But if they occur in different global contexts, these nodes are physically different to ensure the integrity of their global contexts.
Beware that the identity is currently a 64 bit field. For datasets that have graphs of size in the order of billions of nodes there is a non-trivial chance of a collision. (We consider this acceptable for machine learning purposes.)
The children of a node, together with the labels of the edges towards the children.
Note that for efficiency purposes, the label is represented as an integer. The corresponding
enum of this integer is graph_api_capnp.EdgeClassification
.
Some nodes in the CIC graph represent definitions. Such nodes contain extra information about the definition.
247class ProofState: 248 """A proof state represents a particular point in the tactical proof of a constant.""" 249 250 @property 251 def lowlevel(self): 252 ... 253 def __repr__(self): 254 ... 255 256 @property 257 def root(self) -> Node: 258 """The entry-point of the proof state, all nodes that are 'part of' the proof state are 259 reachable from here.""" 260 ... 261 262 @property 263 def context(self) -> Sequence[Node]: 264 """The local context of the proof state, given as a tuple of their original name as they appeared in the 265 proof and the corresponding node. 266 267 The nodes always have either label `contextAssum` or `contextDef`. 268 Note that these nodes are also reachable from the root of the proof state. 269 270 The names of the context elements should be used for debugging and viewing purposes only, because 271 hypothesis-generating tactics have been modified to use auto-generated names. Hence, tactics should 272 not be concerned about the names of the context. 273 """ 274 ... 275 276 @property 277 def context_names(self) -> Sequence[str]: 278 """The names of the local context nodes of the proof state, as they originally appeared in the proof. 279 280 These names should be used for debugging and viewing purposes only, because hypothesis-generating tactics have 281 been modified to use auto-generated names. Hence, tactics should not be concerned about the names of 282 the context. 283 """ 284 ... 285 286 @property 287 def context_text(self) -> Sequence[str]: 288 """A textual representation of the type/definition of context nodes 289 """ 290 ... 291 292 @property 293 def conclusion_text(self) -> str: 294 """A textual representation of the conclusion of the proof state. 295 """ 296 ... 297 298 @property 299 def text(self) -> str: 300 """A textual representation of the proof state.""" 301 ... 302 303 def __str__(self) -> str: 304 ... 305 306 @property 307 def id(self) -> ProofStateId: 308 """ 309 A unique identifier of the proof state. Any two proof states in a tactical proof that have an equal id 310 can morally be regarded to be 'the same' proof state. 311 IMPORTANT: Two proof states with the same id may still have different contents. This is because proof states 312 can contain existential variables (represented by the `evar` node) that can be filled as a 313 side-effect by a tactic running on another proof state. 314 """ 315 ...
A proof state represents a particular point in the tactical proof of a constant.
The entry-point of the proof state, all nodes that are 'part of' the proof state are reachable from here.
The local context of the proof state, given as a tuple of their original name as they appeared in the proof and the corresponding node.
The nodes always have either label contextAssum
or contextDef
.
Note that these nodes are also reachable from the root of the proof state.
The names of the context elements should be used for debugging and viewing purposes only, because hypothesis-generating tactics have been modified to use auto-generated names. Hence, tactics should not be concerned about the names of the context.
The names of the local context nodes of the proof state, as they originally appeared in the proof.
These names should be used for debugging and viewing purposes only, because hypothesis-generating tactics have been modified to use auto-generated names. Hence, tactics should not be concerned about the names of the context.
A textual representation of the type/definition of context nodes
A unique identifier of the proof state. Any two proof states in a tactical proof that have an equal id
can morally be regarded to be 'the same' proof state.
IMPORTANT: Two proof states with the same id may still have different contents. This is because proof states
can contain existential variables (represented by the evar
node) that can be filled as a
side-effect by a tactic running on another proof state.
319class Outcome: 320 """An outcome is the result of running a tactic on a proof state. A tactic may run on multiple proof states.""" 321 322 tactic : apic.Tactic_Reader | Unknown 323 """The tactic that generated the outcome. For it's arguments, see `tactic_arguments` 324 325 Sometimes a tactic cannot or should not be recorded. In those cases, it is marked as 'unknown'. 326 This currently happens with tactics that are run as a result of the `Proof with tac` construct and it 327 happens for tactics that are known to be unsafe like `change_no_check`, `fix`, `cofix` and more. 328 """ 329 330 @property 331 def lowlevel(self): 332 ... 333 def __repr__(self): 334 ... 335 336 @property 337 def before(self) -> ProofState: 338 """The proof state before the tactic execution.""" 339 ... 340 341 @property 342 def after(self) -> Sequence[ProofState]: 343 """The new proof states that were generated by the tactic.""" 344 ... 345 346 @property 347 def term(self) -> Node: 348 """The proof term that witnesses the transition from the before state to the after states. It contains a 349 hole (an `evar` node) for each of the after states. It may also refer to elements of the local context of 350 the before state. 351 """ 352 ... 353 354 @property 355 def term_text(self) -> str: 356 """A textual representation of the proof term.""" 357 ... 358 359 @property 360 def tactic_arguments(self) -> Sequence[Node | Unresolvable]: 361 """The arguments of the tactic that produced this outcome. 362 363 The node is the root of a graph representing an argument that is a term in the calculus of constructions. 364 Sometimes, an argument is not resolvable to a term, in which case it is marked as `Unresolvable`. 365 """ 366 ...
An outcome is the result of running a tactic on a proof state. A tactic may run on multiple proof states.
The tactic that generated the outcome. For it's arguments, see tactic_arguments
Sometimes a tactic cannot or should not be recorded. In those cases, it is marked as 'unknown'.
This currently happens with tactics that are run as a result of the Proof with tac
construct and it
happens for tactics that are known to be unsafe like change_no_check
, fix
, cofix
and more.
The proof term that witnesses the transition from the before state to the after states. It contains a
hole (an evar
node) for each of the after states. It may also refer to elements of the local context of
the before state.
The arguments of the tactic that produced this outcome.
The node is the root of a graph representing an argument that is a term in the calculus of constructions.
Sometimes, an argument is not resolvable to a term, in which case it is marked as Unresolvable
.
368class ProofStep: 369 """A proof step is the execution of a single tactic on one or more proof states, producing a list of outcomes. 370 """ 371 372 @property 373 def lowlevel(self): 374 ... 375 def __repr__(self): 376 ... 377 378 @property 379 def tactic(self) -> apic.Tactic_Reader | Unknown: 380 """The tactic that generated the proof step. Note that the arguments of the tactic can be found in the 381 individual outcomes, because they may be different for each outcome. 382 383 Sometimes a tactic cannot or should not be recorded. In those cases, it is marked as 'unknown'. 384 This currently happens with tactics that are run as a result of the `Proof with tac` construct and it 385 happens for tactics that are known to be unsafe like `change_no_check`, `fix`, `cofix` and more. 386 """ 387 ... 388 389 @property 390 def outcomes(self) -> Sequence[Outcome]: 391 """A list of transformations of proof states to other proof states, as executed by the tactic of the proof 392 step 393 """ 394 ...
A proof step is the execution of a single tactic on one or more proof states, producing a list of outcomes.
The tactic that generated the proof step. Note that the arguments of the tactic can be found in the individual outcomes, because they may be different for each outcome.
Sometimes a tactic cannot or should not be recorded. In those cases, it is marked as 'unknown'.
This currently happens with tactics that are run as a result of the Proof with tac
construct and it
happens for tactics that are known to be unsafe like change_no_check
, fix
, cofix
and more.
A list of transformations of proof states to other proof states, as executed by the tactic of the proof step
396@dataclass 397class Original: 398 """Token that signals that a definition is original, as inputted by the 399 user.""" 400 pass
Token that signals that a definition is original, as inputted by the user.
402@dataclass 403class Discharged: 404 """Token that signals that a definition is derived from an original after 405 section closing.""" 406 407 original: Definition
Token that signals that a definition is derived from an original after section closing.
409@dataclass 410class Substituted: 411 """Token that signals that a definition is derived from an original after 412 module functor instantiation.""" 413 414 original: Definition
Token that signals that a definition is derived from an original after module functor instantiation.
416@dataclass 417class Inductive: 418 """Token that signals that a definition is inductive.""" 419 420 representative: Definition 421 """The representative of the mutually recursive cluster. For lowlevel use only"""
Token that signals that a definition is inductive.
The representative of the mutually recursive cluster. For lowlevel use only
423@dataclass 424class Constructor: 425 """Token that signals that a definition is a constructor.""" 426 427 representative: Definition 428 """The representative of the mutually recursive cluster. For lowlevel use only"""
Token that signals that a definition is a constructor.
The representative of the mutually recursive cluster. For lowlevel use only
430@dataclass 431class Projection: 432 """Token that signals that a definition is a projection.""" 433 434 representative: Definition 435 """The representative of the mutually recursive cluster. For lowlevel use only"""
Token that signals that a definition is a projection.
The representative of the mutually recursive cluster. For lowlevel use only
437@dataclass 438class ManualConstant: 439 """Token that signals that a definition was inputted by the user by 440 manually inputting a term.""" 441 pass
Token that signals that a definition was inputted by the user by manually inputting a term.
443@dataclass 444class TacticalConstant: 445 """Token that signals that a lemma was proved by the user using 446 a tactic proof.""" 447 448 proof: Sequence[ProofStep] 449 """The proof of the lemma."""
Token that signals that a lemma was proved by the user using a tactic proof.
451@dataclass 452class ManualSectionConstant: 453 """Token that signals that a constant is a section variable or let-construct.""" 454 pass
Token that signals that a constant is a section variable or let-construct.
456@dataclass 457class TacticalSectionConstant: 458 """Token that signals that a constant is a section let-construct with a tactic proof.""" 459 460 proof: Sequence[ProofStep] 461 """The proof of the lemma."""
Token that signals that a constant is a section let-construct with a tactic proof.
463class Definition: 464 """A definition of the CIC, which is either a constant, inductive, constructor, projection or section 465 variable. Constants and section variables can have tactical proofs associated to them. 466 """ 467 468 node : Node 469 """The node that is associated with this definition. It holds that 470 `definition.node.definition == definition`. 471 """ 472 473 @property 474 def lowlevel(self): 475 ... 476 def __repr__(self): 477 ... 478 479 def __eq__(self, other: object) -> bool: 480 """Physical equality of two nodes. Note that two nodes with a different physical equality 481 may have the same `identity`. See `identity` for details. 482 """ 483 ... 484 485 def __hash__(self): 486 """A hash that is corresponds to physical equality, not to be confused by `identity`.""" 487 ... 488 489 @property 490 def name(self) -> str: 491 """The fully-qualified name of the definition. The name should be unique in a particular global context, 492 but is not unique among different branches of the global in a dataset. 493 """ 494 ... 495 496 @property 497 def previous(self) -> Definition | None: 498 """The previous definition within the global context of the current file. 499 500 Note that this is a lowlevel property. Prefer to use `global_context` or `clustered_global_context`. 501 502 The contract on this field is that any definition nodes reachable from the forward closure of the definition 503 must also be reachable through the chain of previous fields. An exception to this rule are mutually 504 recursive definitions. Those nodes are placed into the global context in an arbitrary ordering. 505 """ 506 ... 507 508 @property 509 def external_previous(self) -> Sequence[Definition]: 510 """A list of definitions that are the representatives of files other than the current file that are 511 part of the global context. This list becomes populated when a `Require` statement occurred right before 512 the definition. 513 514 Note that this is a lowlevel property. Prefer to use `global_context` or `clustered_global_context`. 515 """ 516 ... 517 518 def global_context(self, across_files : bool = True, inclusive = False) -> Iterable[Definition]: 519 """All of the definitions in the global context when this definition was created. 520 521 Note that this does not include this definition itself, except when the definition is a inductive, 522 constructor or projection. Because those are mutually recursive objects, they reference themselves 523 and are therefore part of their own global context. 524 525 The resulting iterable is topologically sorted. That is, for any definition in the stream, any 526 definition reachable from the forward closure of the definition also exists in the remainder of the 527 stream. An exception to this rule are mutually recursive definitions, because no topological sort 528 is possible there (see also `clustered_global_context`). 529 530 Arguments: 531 * `across_files`: if `False`, outputs only the definitions from the local file, default `True`. 532 * `inclusive`: if `True`, outputs also itself, default `False`. 533 Note: if it is a self-recursive definition, the `inclusive` argument is ignored, and considered as `True` 534 """ 535 ... 536 537 def clustered_global_context(self, across_files : bool = True, inclusive : bool = False) -> Iterable[list[Definition]]: 538 """All of the definitions in the global context when this definition was created, clustered into 539 mutually recursive cliques. 540 541 The resulting iterable is topologically sorted. That is, for any definition in the stream, any 542 definition reachable from the forward closure of the definition also exists in the remainder of the 543 stream. 544 545 Arguments: 546 * `across_files`: if `False`, outputs only the definitions from the local file, default `True`. 547 * `inclusive`: if `True`, outputs also the cluster of itself, default `False`. 548 Note: if it is a self-recursive definition, the `inclusive` argument is ignored, and considered as `True`. 549 """ 550 ... 551 552 @property 553 def status(self) -> Original | Discharged | Substituted: 554 """ 555 A definition is either 556 (1) an object as originally inputted by the user. 557 (2) a definition that was originally defined in a section and has now had the section 558 variables discharged into it. 559 (3) a definition that was obtained by performing some sort of module functor substitution. 560 When a definition is not original, we cross-reference to the definition that it was derived from. 561 """ 562 ... 563 564 @property 565 def kind(self) -> Union[Inductive, Constructor, Projection, 566 ManualConstant, TacticalConstant, 567 ManualSectionConstant, TacticalSectionConstant]: 568 """The kind of the definition. 569 570 It can be an constant, section constant, inductive, constructor or projection. In case of a constant 571 of a constant or section constant, an optional tactical proof can be associated. In case of an inductive, 572 constructor or projection, another definition that acts as the representative of the mutually recursive 573 cluster of definitions is associated. 574 575 The associated information is low-level. Prefer to use the properties `proof` and `cluster` to access them. 576 """ 577 ... 578 579 @property 580 def proof(self) -> Sequence[ProofStep] | None: 581 """An optional tactical proof that was used to create this definition.""" 582 ... 583 584 @property 585 def cluster_representative(self) -> Definition: 586 """A unique representative of the mutually recursive cluster of definitions this definition is part of. 587 If the definition is not mutually recursive, the representative is itself. 588 589 This is a low-level property. Prefer to use the `cluster` property. 590 """ 591 ... 592 593 @property 594 def cluster(self) -> Iterable[Definition]: 595 """The cluster of mutually recursive definitions that this definition is part of. 596 If the definition is not mutually recursive, the cluster is a singleton.""" 597 ... 598 599 @property 600 def type_text(self) -> str: 601 """A textual representation of the type of this definition.""" 602 ... 603 604 @property 605 def term_text(self) -> str | None: 606 """A textual representation of the body of this definition. 607 For inductives, constructors, projections, section variables and axioms this is `None`. 608 """ 609 ... 610 611 @property 612 def is_file_representative(self) -> bool: 613 """Returns true if this definition is the representative of the super-global context of it's file. 614 Se also `Dataset.representative`.""" 615 ...
A definition of the CIC, which is either a constant, inductive, constructor, projection or section variable. Constants and section variables can have tactical proofs associated to them.
The node that is associated with this definition. It holds that
definition.node.definition == definition
.
The fully-qualified name of the definition. The name should be unique in a particular global context, but is not unique among different branches of the global in a dataset.
The previous definition within the global context of the current file.
Note that this is a lowlevel property. Prefer to use global_context
or clustered_global_context
.
The contract on this field is that any definition nodes reachable from the forward closure of the definition must also be reachable through the chain of previous fields. An exception to this rule are mutually recursive definitions. Those nodes are placed into the global context in an arbitrary ordering.
A list of definitions that are the representatives of files other than the current file that are
part of the global context. This list becomes populated when a Require
statement occurred right before
the definition.
Note that this is a lowlevel property. Prefer to use global_context
or clustered_global_context
.
518 def global_context(self, across_files : bool = True, inclusive = False) -> Iterable[Definition]: 519 """All of the definitions in the global context when this definition was created. 520 521 Note that this does not include this definition itself, except when the definition is a inductive, 522 constructor or projection. Because those are mutually recursive objects, they reference themselves 523 and are therefore part of their own global context. 524 525 The resulting iterable is topologically sorted. That is, for any definition in the stream, any 526 definition reachable from the forward closure of the definition also exists in the remainder of the 527 stream. An exception to this rule are mutually recursive definitions, because no topological sort 528 is possible there (see also `clustered_global_context`). 529 530 Arguments: 531 * `across_files`: if `False`, outputs only the definitions from the local file, default `True`. 532 * `inclusive`: if `True`, outputs also itself, default `False`. 533 Note: if it is a self-recursive definition, the `inclusive` argument is ignored, and considered as `True` 534 """ 535 ...
All of the definitions in the global context when this definition was created.
Note that this does not include this definition itself, except when the definition is a inductive, constructor or projection. Because those are mutually recursive objects, they reference themselves and are therefore part of their own global context.
The resulting iterable is topologically sorted. That is, for any definition in the stream, any
definition reachable from the forward closure of the definition also exists in the remainder of the
stream. An exception to this rule are mutually recursive definitions, because no topological sort
is possible there (see also clustered_global_context
).
Arguments:
across_files
: ifFalse
, outputs only the definitions from the local file, defaultTrue
.inclusive
: ifTrue
, outputs also itself, defaultFalse
. Note: if it is a self-recursive definition, theinclusive
argument is ignored, and considered asTrue
537 def clustered_global_context(self, across_files : bool = True, inclusive : bool = False) -> Iterable[list[Definition]]: 538 """All of the definitions in the global context when this definition was created, clustered into 539 mutually recursive cliques. 540 541 The resulting iterable is topologically sorted. That is, for any definition in the stream, any 542 definition reachable from the forward closure of the definition also exists in the remainder of the 543 stream. 544 545 Arguments: 546 * `across_files`: if `False`, outputs only the definitions from the local file, default `True`. 547 * `inclusive`: if `True`, outputs also the cluster of itself, default `False`. 548 Note: if it is a self-recursive definition, the `inclusive` argument is ignored, and considered as `True`. 549 """ 550 ...
All of the definitions in the global context when this definition was created, clustered into mutually recursive cliques.
The resulting iterable is topologically sorted. That is, for any definition in the stream, any definition reachable from the forward closure of the definition also exists in the remainder of the stream.
Arguments:
across_files
: ifFalse
, outputs only the definitions from the local file, defaultTrue
.inclusive
: ifTrue
, outputs also the cluster of itself, defaultFalse
. Note: if it is a self-recursive definition, theinclusive
argument is ignored, and considered asTrue
.
A definition is either (1) an object as originally inputted by the user. (2) a definition that was originally defined in a section and has now had the section variables discharged into it. (3) a definition that was obtained by performing some sort of module functor substitution. When a definition is not original, we cross-reference to the definition that it was derived from.
The kind of the definition.
It can be an constant, section constant, inductive, constructor or projection. In case of a constant of a constant or section constant, an optional tactical proof can be associated. In case of an inductive, constructor or projection, another definition that acts as the representative of the mutually recursive cluster of definitions is associated.
The associated information is low-level. Prefer to use the properties proof
and cluster
to access them.
An optional tactical proof that was used to create this definition.
A unique representative of the mutually recursive cluster of definitions this definition is part of. If the definition is not mutually recursive, the representative is itself.
This is a low-level property. Prefer to use the cluster
property.
The cluster of mutually recursive definitions that this definition is part of. If the definition is not mutually recursive, the cluster is a singleton.
A textual representation of the body of this definition.
For inductives, constructors, projections, section variables and axioms this is None
.
Returns true if this definition is the representative of the super-global context of it's file.
Se also Dataset.representative
.
617class Dataset: 618 """The data corresponding to a single Coq source file. The data contains a representation of all definitions 619 that have existed at any point throughout the compilation of the source file. 620 """ 621 622 graph : GraphId 623 filename : Path 624 """The physical file in which the data contained in this class can be found.""" 625 626 @property 627 def lowlevel(self): 628 ... 629 def __repr__(self): 630 ... 631 632 @property 633 def dependencies(self) -> Sequence[Path]: 634 """A list of physical paths of data files that are direct dependencies of this file. 635 636 It is guaranteed that no cycles exist in the dependency relation between files induced by this field. 637 """ 638 ... 639 640 @property 641 def representative(self) -> Definition | None: 642 """The entry point of the global context of definitions that are available when this file is 'Required' by 643 another file. The full global context can be obtained by following the `previous` node of definitions. 644 If the compilation unit does not contain any 'super'-global definitions this may be `None`. 645 646 This is a low-level property. 647 Prefer to use `definitions(spine_only = True)` and `clustered_definitions(spine_only=True)`. 648 """ 649 ... 650 651 def definitions(self, across_files = False, spine_only = False) -> Iterable[Definition]: 652 """All of the definitions present in the file. 653 Note that some of these nodes may not be part of the 'super-global' context. Those are definitions inside 654 of sections or module functors. 655 656 Arguments: 657 * `across_files`: if `True`, outputs also definitions from dependent files, default `False`. 658 * `spine_only`: if True, outputs only the definitions on the main spine, default `False`. 659 Note: `across_files = True` is incompatible with `spine_only = False`. 660 661 When `spine_only = True`, the resulting iterable is topologically sorted. That is, for 662 any definition in the stream, any definition reachable from the forward closure of the definition 663 also exists in the remainder of the stream. An exception to this rule are mutually recursive definitions, 664 because no topological sort is possible there (see also `clustered_definitions`). 665 """ 666 ... 667 668 def clustered_definitions(self, across_files = False, spine_only = False) -> Iterable[list[Definition]]: 669 """All of the definitions present in the file, clustered by mutually recursive definitions. 670 Note that some of these nodes may not be part of the 'super-global' context. Those are definitions inside 671 of sections or module functors. 672 673 Arguments: 674 * `across_files`: if `True`, outputs also definitions from dependent files, default `False`. 675 * `spine_only`: if `True`, outputs only the definitions on the main spine, default `False`. 676 Note: `across_files = True` is incompatible with `spine_only = False`. 677 678 When `spine_only = True`, the resulting iterable is topologically sorted. That is, for 679 any definition in the stream, any definition reachable from the forward closure of the definition 680 also exists in the remainder of the stream. 681 """ 682 ... 683 684 @property 685 def module_name(self) -> str: 686 ... 687 688 def node_by_id(self, nodeid: NodeId) -> Node: 689 """Lookup a node inside of this file by it's local node-id. This is a low-level function.""" 690 ...
The data corresponding to a single Coq source file. The data contains a representation of all definitions that have existed at any point throughout the compilation of the source file.
A list of physical paths of data files that are direct dependencies of this file.
It is guaranteed that no cycles exist in the dependency relation between files induced by this field.
The entry point of the global context of definitions that are available when this file is 'Required' by
another file. The full global context can be obtained by following the previous
node of definitions.
If the compilation unit does not contain any 'super'-global definitions this may be None
.
This is a low-level property.
Prefer to use definitions(spine_only = True)
and clustered_definitions(spine_only=True)
.
651 def definitions(self, across_files = False, spine_only = False) -> Iterable[Definition]: 652 """All of the definitions present in the file. 653 Note that some of these nodes may not be part of the 'super-global' context. Those are definitions inside 654 of sections or module functors. 655 656 Arguments: 657 * `across_files`: if `True`, outputs also definitions from dependent files, default `False`. 658 * `spine_only`: if True, outputs only the definitions on the main spine, default `False`. 659 Note: `across_files = True` is incompatible with `spine_only = False`. 660 661 When `spine_only = True`, the resulting iterable is topologically sorted. That is, for 662 any definition in the stream, any definition reachable from the forward closure of the definition 663 also exists in the remainder of the stream. An exception to this rule are mutually recursive definitions, 664 because no topological sort is possible there (see also `clustered_definitions`). 665 """ 666 ...
All of the definitions present in the file. Note that some of these nodes may not be part of the 'super-global' context. Those are definitions inside of sections or module functors.
Arguments:
across_files
: ifTrue
, outputs also definitions from dependent files, defaultFalse
.spine_only
: if True, outputs only the definitions on the main spine, defaultFalse
. Note:across_files = True
is incompatible withspine_only = False
.
When spine_only = True
, the resulting iterable is topologically sorted. That is, for
any definition in the stream, any definition reachable from the forward closure of the definition
also exists in the remainder of the stream. An exception to this rule are mutually recursive definitions,
because no topological sort is possible there (see also clustered_definitions
).
668 def clustered_definitions(self, across_files = False, spine_only = False) -> Iterable[list[Definition]]: 669 """All of the definitions present in the file, clustered by mutually recursive definitions. 670 Note that some of these nodes may not be part of the 'super-global' context. Those are definitions inside 671 of sections or module functors. 672 673 Arguments: 674 * `across_files`: if `True`, outputs also definitions from dependent files, default `False`. 675 * `spine_only`: if `True`, outputs only the definitions on the main spine, default `False`. 676 Note: `across_files = True` is incompatible with `spine_only = False`. 677 678 When `spine_only = True`, the resulting iterable is topologically sorted. That is, for 679 any definition in the stream, any definition reachable from the forward closure of the definition 680 also exists in the remainder of the stream. 681 """ 682 ...
All of the definitions present in the file, clustered by mutually recursive definitions. Note that some of these nodes may not be part of the 'super-global' context. Those are definitions inside of sections or module functors.
Arguments:
across_files
: ifTrue
, outputs also definitions from dependent files, defaultFalse
.spine_only
: ifTrue
, outputs only the definitions on the main spine, defaultFalse
. Note:across_files = True
is incompatible withspine_only = False
.
When spine_only = True
, the resulting iterable is topologically sorted. That is, for
any definition in the stream, any definition reachable from the forward closure of the definition
also exists in the remainder of the stream.
692def lowlevel_to_highlevel(lreader : LowlevelDataReader) -> dict[Path, Dataset]: 693 """Convert a dataset initialized as a `LowLevelDataReader` into a high level interface.""" 694 ...
Convert a dataset initialized as a LowLevelDataReader
into a high level interface.
696@contextmanager 697def data_reader(dataset_path: Path) -> Generator[dict[Path, Dataset], None, None]: 698 """Load a directory of dataset files into memory, and expose the data they contain. 699 The result is a dictionary that maps physical paths to `Dataset` instances that allow access to the data. 700 701 Arguments: 702 `dataset_path`: Can either be a dataset directory, or a SquashFS image file. In case of an image 703 file `dataset.squ`, the image will be mounted using `squashfuse` on directory 704 `dataset/`, after which the contents of that directory will be read. 705 706 """ 707 ...
Load a directory of dataset files into memory, and expose the data they contain.
The result is a dictionary that maps physical paths to Dataset
instances that allow access to the data.
Arguments:
dataset_path
: Can either be a dataset directory, or a SquashFS image file. In case of an image
file dataset.squ
, the image will be mounted using squashfuse
on directory
dataset/
, after which the contents of that directory will be read.
709class OnlineDefinitionsReader: 710 """This class represents a global context to Python by Coq, containing all 711 known definitions and available tactics.""" 712 713 def local_to_global(self, graph: int, dep_index: int) -> int: 714 """Convert a dependency-index relative to a graph-id to a new graph-id. 715 716 This is used to find the graph-id where a particular node can be found. If `graph` is the 717 graph-id that contains a reference to a node and `dep_index` is the relative location 718 where that node can be found then `local_to_global(graph, dep_index)` finds the index in 719 the global context stack where the node is physically located. 720 721 Lowlevel function. 722 """ 723 ... 724 725 @property 726 def representative(self) -> Definition | None: 727 """The last definition in the global context. All other definitions can be accessed by following 728 the `Definition.previous` chain starting from this definitions. 729 730 This is a low-level property. 731 Prefer to use `definitions` and `clustered_definitions`. 732 """ 733 ... 734 735 def definitions(self, full : bool = True) -> Iterable[Definition]: 736 """The list of definitions that are currently in the global context. 737 738 The resulting iterable is topologically sorted. That is, for any definition in the stream, any 739 definition reachable from the forward closure of the definition also exists in the remainder of 740 the stream. An exception to this rule are mutually recursive definitions, 741 because no topological sort is possible there (see also `clustered_definitions`). 742 """ 743 ... 744 745 def clustered_definitions(self, full : bool = True) -> Iterable[list[Definition]]: 746 """All of the definitions present in the global context, clustered by mutually recursive definitions. 747 748 The resulting iterable is topologically sorted. That is, for any definition in the stream, any 749 definition reachable from the forward closure of the definition also exists in the remainder of 750 the stream. 751 """ 752 ...
This class represents a global context to Python by Coq, containing all known definitions and available tactics.
713 def local_to_global(self, graph: int, dep_index: int) -> int: 714 """Convert a dependency-index relative to a graph-id to a new graph-id. 715 716 This is used to find the graph-id where a particular node can be found. If `graph` is the 717 graph-id that contains a reference to a node and `dep_index` is the relative location 718 where that node can be found then `local_to_global(graph, dep_index)` finds the index in 719 the global context stack where the node is physically located. 720 721 Lowlevel function. 722 """ 723 ...
Convert a dependency-index relative to a graph-id to a new graph-id.
This is used to find the graph-id where a particular node can be found. If graph
is the
graph-id that contains a reference to a node and dep_index
is the relative location
where that node can be found then local_to_global(graph, dep_index)
finds the index in
the global context stack where the node is physically located.
Lowlevel function.
The last definition in the global context. All other definitions can be accessed by following
the Definition.previous
chain starting from this definitions.
This is a low-level property.
Prefer to use definitions
and clustered_definitions
.
735 def definitions(self, full : bool = True) -> Iterable[Definition]: 736 """The list of definitions that are currently in the global context. 737 738 The resulting iterable is topologically sorted. That is, for any definition in the stream, any 739 definition reachable from the forward closure of the definition also exists in the remainder of 740 the stream. An exception to this rule are mutually recursive definitions, 741 because no topological sort is possible there (see also `clustered_definitions`). 742 """ 743 ...
The list of definitions that are currently in the global context.
The resulting iterable is topologically sorted. That is, for any definition in the stream, any
definition reachable from the forward closure of the definition also exists in the remainder of
the stream. An exception to this rule are mutually recursive definitions,
because no topological sort is possible there (see also clustered_definitions
).
745 def clustered_definitions(self, full : bool = True) -> Iterable[list[Definition]]: 746 """All of the definitions present in the global context, clustered by mutually recursive definitions. 747 748 The resulting iterable is topologically sorted. That is, for any definition in the stream, any 749 definition reachable from the forward closure of the definition also exists in the remainder of 750 the stream. 751 """ 752 ...
All of the definitions present in the global context, clustered by mutually recursive definitions.
The resulting iterable is topologically sorted. That is, for any definition in the stream, any definition reachable from the forward closure of the definition also exists in the remainder of the stream.
754@contextmanager 755def online_definitions_initialize(stack: OnlineDefinitionsReader, 756 init: apic.PredictionProtocol_Request_Initialize_Reader) -> Generator[OnlineDefinitionsReader, None, None]: 757 """Given a new initialization message sent by Coq, construct a 758 `OnlineDefinitiosnReader` object. This can be used to inspect the 759 definitions currently available. Additionally, using `online_data_predict` 760 it can be combined with a subsequent prediction request received from Coq 761 to build a `ProofState`. 762 """ 763 ...
Given a new initialization message sent by Coq, construct a
OnlineDefinitiosnReader
object. This can be used to inspect the
definitions currently available. Additionally, using online_data_predict
it can be combined with a subsequent prediction request received from Coq
to build a ProofState
.
768@contextmanager 769def online_data_predict(base: OnlineDefinitionsReader, 770 predict: apic.PredictionProtocol_Request_Predict_Reader) -> Generator[ProofState, None, None]: 771 """Given a `OnlineDefinitionsReader` instance constructed through 772 `online_data_initialize`, and a prediction message sent by Coq, construct a 773 `ProofState` object that represents the current proof state in Coq. 774 """ 775 ...
Given a OnlineDefinitionsReader
instance constructed through
online_data_initialize
, and a prediction message sent by Coq, construct a
ProofState
object that represents the current proof state in Coq.
777@dataclass 778class TacticPredictionGraph: 779 ident : int 780 arguments : list[Node] 781 confidence : float
800@dataclass 801class CheckAlignmentResponse: 802 unknown_definitions : list[Definition] 803 unknown_tactics : list[int]
805@dataclass 806class GlobalContextMessage: 807 """A message containing a new global context sent to Python from Coq, 808 including all known definitions and available tactics.""" 809 810 definitions : OnlineDefinitionsReader 811 tactics : Sequence[apic.AbstractTactic_Reader] 812 813 log_annotation : str 814 """An annotation representing the current position of Coq in a source 815 document. For logging and debugging purposes.""" 816 817 prediction_requests : Generator[GlobalContextMessage | ProofState | CheckAlignmentMessage, 818 None | TacticPredictionsGraph | TacticPredictionsText | CheckAlignmentResponse, 819 None] 820 """A sub-generator that produces new requests from Coq that are based on or 821 extend the global context of the current message. Once the sub-generator 822 runs out, the parent generator continues."""
A message containing a new global context sent to Python from Coq, including all known definitions and available tactics.
An annotation representing the current position of Coq in a source document. For logging and debugging purposes.
A sub-generator that produces new requests from Coq that are based on or extend the global context of the current message. Once the sub-generator runs out, the parent generator continues.
824def capnp_message_generator_lowlevel(socket: socket.socket) -> ( 825 Generator[apic.PredictionProtocol_Request_Reader, 826 capnp.lib.capnp._DynamicStructBuilder, None]): 827 """A generator that facilitates communication between a prediction server and a Coq process. 828 829 Given a `socket`, this function creates a generator that yields messages of type 830 `pytact.graph_api_capnp_cython.PredictionProtocol_Request_Reader` after which a 831 `capnp.lib.capnp._DynamicStructBuilder` message needs to be `send` back. 832 """ 833 ...
A generator that facilitates communication between a prediction server and a Coq process.
Given a socket
, this function creates a generator that yields messages of type
pytact.graph_api_capnp_cython.PredictionProtocol_Request_Reader
after which a
capnp.lib.capnp._DynamicStructBuilder
message needs to be send
back.
835def capnp_message_generator_from_file_lowlevel( 836 message_file: BinaryIO, 837 check : Callable[[Any, Any, Any], None] | None = None) -> ( 838 Generator[apic.PredictionProtocol_Request_Reader, 839 capnp.lib.capnp._DynamicStructBuilder, None]): 840 """Replay and verify a pre-recorded communication sequence between Coq and a prediction server. 841 842 Lowlevel variant of `capnp_message_generator_from_file`. 843 844 Accepts a `message_file` containing a stream of Capt'n Proto messages as recorded using 845 `capnp_message_generator(s, record=message_file)`. The resulting generator acts just like the generator 846 created by `capnp_message_generator` except that it is not connected to the socket but just replays the 847 pre-recorded messages. 848 849 Arguments: 850 - `check` is an optional callable that can be used to compare the response of the server to the recorded 851 response. It accepts three arguments: The recorded message that was sent by Coq, the response of the server 852 and the recorded response. 853 """ 854 ...
Replay and verify a pre-recorded communication sequence between Coq and a prediction server.
Lowlevel variant of capnp_message_generator_from_file
.
Accepts a message_file
containing a stream of Capt'n Proto messages as recorded using
capnp_message_generator(s, record=message_file)
. The resulting generator acts just like the generator
created by capnp_message_generator
except that it is not connected to the socket but just replays the
pre-recorded messages.
Arguments:
check
is an optional callable that can be used to compare the response of the server to the recorded response. It accepts three arguments: The recorded message that was sent by Coq, the response of the server and the recorded response.
856def record_lowlevel_generator( 857 record_file: BinaryIO, 858 gen: Generator[apic.PredictionProtocol_Request_Reader, 859 capnp.lib.capnp._DynamicStructBuilder, None]) -> ( 860 Generator[apic.PredictionProtocol_Request_Reader, 861 capnp.lib.capnp._DynamicStructBuilder, None]): 862 """Record a trace of the full interaction of a lowlevel generator to a file 863 864 Wrap a lowlevel generator (such as from `capnp_message_generator_lowlevel`) and dump all exchanged messages 865 to the given file. The file can later be replayed with `capnp_message_generator_from_file_lowlevel`. 866 """ 867 ...
Record a trace of the full interaction of a lowlevel generator to a file
Wrap a lowlevel generator (such as from capnp_message_generator_lowlevel
) and dump all exchanged messages
to the given file. The file can later be replayed with capnp_message_generator_from_file_lowlevel
.
869def prediction_generator( 870 lgenerator: Generator[apic.PredictionProtocol_Request_Reader, 871 capnp.lib.capnp._DynamicStructBuilder, None], 872 defs: OnlineDefinitionsReader): 873 """Given the current global context stack `defs`, convert a low-level 874 generator to a high-level `GlobalContextMessage`""" 875 ...
Given the current global context stack defs
, convert a low-level
generator to a high-level GlobalContextMessage
877def capnp_message_generator(socket: socket.socket, record: BinaryIO | None = None) -> GlobalContextMessage: 878 """A generator that facilitates communication between a prediction server and a Coq process. 879 880 Given a `socket`, this function creates a `GlobalContextMessage` `context`. This message contains an 881 initially empty list of available tactics and definitions in the global context. Through 882 `context.prediction_requests` one can access a generator that yields prediction requests and expects 883 predictions to be sent in response. The possible messages are as follows: 884 - `GlobalContextMessage`: An additional, nested, global context message that amends the current context 885 with additional tactics and definitions. The prediction requests of this nested context need to be 886 exhausted before continuing with messages from the current context. 887 - `CheckAlignmentMessage`: A request to check which of Coq's current tactics and definitions the 888 prediction server currently "knows about". The generator expects a `CheckAlignmentResponse` to be 889 sent in response. 890 - `ProofState`: A request to make tactic predictions for a given proof state. Either a 891 `TacticPredictionsGraph` or a `TacticPredictionsText` message is expected in return. 892 893 When `record` is passed a file descriptor, all received and sent messages will be dumped into that file 894 descriptor. These messages can then be replayed later using `capnp_message_generator_from_file`. 895 """ 896 ...
A generator that facilitates communication between a prediction server and a Coq process.
Given a socket
, this function creates a GlobalContextMessage
context
. This message contains an
initially empty list of available tactics and definitions in the global context. Through
context.prediction_requests
one can access a generator that yields prediction requests and expects
predictions to be sent in response. The possible messages are as follows:
GlobalContextMessage
: An additional, nested, global context message that amends the current context with additional tactics and definitions. The prediction requests of this nested context need to be exhausted before continuing with messages from the current context.CheckAlignmentMessage
: A request to check which of Coq's current tactics and definitions the prediction server currently "knows about". The generator expects aCheckAlignmentResponse
to be sent in response.ProofState
: A request to make tactic predictions for a given proof state. Either aTacticPredictionsGraph
or aTacticPredictionsText
message is expected in return.
When record
is passed a file descriptor, all received and sent messages will be dumped into that file
descriptor. These messages can then be replayed later using capnp_message_generator_from_file
.
898def capnp_message_generator_from_file(message_file: BinaryIO, 899 check : Callable[[Any, Any, Any], None] | None = None, 900 record: BinaryIO | None = None) -> GlobalContextMessage: 901 """Replay and verify a pre-recorded communication sequence between Coq and a prediction server. 902 903 Highlevel variant of `capnp_message_generator_from_file_lowlevel`. 904 905 Accepts a `message_file` containing a stream of Capt'n Proto messages as recorded using 906 `capnp_message_generator(s, record=message_file)`. The resulting generator acts just like the generator 907 created by `capnp_message_generator` except that it is not connected to the socket but just replays the 908 pre-recorded messages. 909 910 Arguments: 911 - `check` is an optional callable that can be used to compare the response of the server to the recorded 912 response. It accepts three arguments: The recorded message that was sent by Coq, the response of the server 913 and the recorded response. 914 - `record` is an optional file that re-records the interaction with the current server 915 """ 916 ...
Replay and verify a pre-recorded communication sequence between Coq and a prediction server.
Highlevel variant of capnp_message_generator_from_file_lowlevel
.
Accepts a message_file
containing a stream of Capt'n Proto messages as recorded using
capnp_message_generator(s, record=message_file)
. The resulting generator acts just like the generator
created by capnp_message_generator
except that it is not connected to the socket but just replays the
pre-recorded messages.
Arguments:
check
is an optional callable that can be used to compare the response of the server to the recorded response. It accepts three arguments: The recorded message that was sent by Coq, the response of the server and the recorded response.record
is an optional file that re-records the interaction with the current server
918class GlobalContextSets: 919 """Lazily retrieve a the global context of a definition as a set, with memoization. 920 921 Because this class can allocate (large) amounts of memory, use it as a context-manager. To create a new 922 instance, and retrieve the context of a definition, use: 923 ``` 924 with GlobalContextSets.new_context() as gcs: 925 gcs.global_context_set(my_definition) 926 ``` 927 This context will be cached, as well as intermediate results (global contexts of other definitions) as 928 long as the context-set is in scope. Caching can be nested by using `sub_context`: 929 ``` 930 with GlobalContextSets.new_context() as gcs: 931 gcs.global_context_set(my_definition) 932 with gcs.sub_context(lambda d:is_file_representative) as gcs_sub: 933 # gcs_sub remembers anything in the case of gcs 934 # caching is propagated to the parent cache only if the provided lambda evaluates to true 935 gcs_sub.global_context_set(my_definition2) 936 ``` 937 """ 938 def __init__(self, cache, parent: GlobalContextSets | None, 939 should_propagate: Callable[[Definition], bool]): 940 """Do not call directly. Use `GlobalContextSets.new_context` and `GlobalContextSets.sub_context`.""" 941 ... 942 943 def global_context_set(self, d: Definition) -> Map: 944 """Retrieve the global context of a definition, caching the result, and intermediate results.""" 945 ... 946 947 @contextmanager 948 def sub_context(self, propagate: Callable[[Definition], bool]) -> Generator[GlobalContextSets, None, None]: 949 """Create a sub-context with a separate cache from it's parent, but sharing any info that was 950 already present in the parent's cache. 951 952 For any intermediate results for a definition `d` for which `propagate(d)` evaluates to true, 953 the result is propagated to the parent's cache.""" 954 ... 955 956 @staticmethod 957 def new_context() -> Generator[GlobalContextSets, None, None]: 958 """Crate a new caching context where global-context-set's can be retrieved and cached.""" 959 ...
Lazily retrieve a the global context of a definition as a set, with memoization.
Because this class can allocate (large) amounts of memory, use it as a context-manager. To create a new instance, and retrieve the context of a definition, use:
with GlobalContextSets.new_context() as gcs:
gcs.global_context_set(my_definition)
This context will be cached, as well as intermediate results (global contexts of other definitions) as
long as the context-set is in scope. Caching can be nested by using sub_context
:
with GlobalContextSets.new_context() as gcs:
gcs.global_context_set(my_definition)
with gcs.sub_context(lambda d:is_file_representative) as gcs_sub:
# gcs_sub remembers anything in the case of gcs
# caching is propagated to the parent cache only if the provided lambda evaluates to true
gcs_sub.global_context_set(my_definition2)
938 def __init__(self, cache, parent: GlobalContextSets | None, 939 should_propagate: Callable[[Definition], bool]): 940 """Do not call directly. Use `GlobalContextSets.new_context` and `GlobalContextSets.sub_context`.""" 941 ...
Do not call directly. Use GlobalContextSets.new_context
and GlobalContextSets.sub_context
.
943 def global_context_set(self, d: Definition) -> Map: 944 """Retrieve the global context of a definition, caching the result, and intermediate results.""" 945 ...
Retrieve the global context of a definition, caching the result, and intermediate results.
947 @contextmanager 948 def sub_context(self, propagate: Callable[[Definition], bool]) -> Generator[GlobalContextSets, None, None]: 949 """Create a sub-context with a separate cache from it's parent, but sharing any info that was 950 already present in the parent's cache. 951 952 For any intermediate results for a definition `d` for which `propagate(d)` evaluates to true, 953 the result is propagated to the parent's cache.""" 954 ...
Create a sub-context with a separate cache from it's parent, but sharing any info that was already present in the parent's cache.
For any intermediate results for a definition d
for which propagate(d)
evaluates to true,
the result is propagated to the parent's cache.
961def node_dependencies(n: Node, deps: set[Definition] | None = None) -> set[Definition]: 962 """Given a `Node` `n`, calculate the set of `Definition`'s that are directly reachable 963 from `n`. Transitively reachable definitions are not included. 964 """ 965 ...
Given a Node
n
, calculate the set of Definition
's that are directly reachable
from n
. Transitively reachable definitions are not included.
967def definition_dependencies(d: Definition) -> set[Definition]: 968 """Given a `Definition` `d`, calculate the set of `Definition`'s that are directly reachable for `d`. 969 Transitively reachable definitions are not included nor is `d` itself. 970 """ 971 ...
Given a Definition
d
, calculate the set of Definition
's that are directly reachable for d
.
Transitively reachable definitions are not included nor is d
itself.