Tptp.Unit (Tptp v0.1.0)

Copy Markdown View Source

A root file together with everything its include directives reach.

Tptp.from_file/2 reads a single file. This reads a problem: the root and the axiom sets it includes, with every span identifying the file it originates in, so that a diagnostic concerning a symbol declared in an axiom file and used in the problem can refer to both.

{:ok, unit, diagnostics} =
  Tptp.Unit.from_file("Problems/PUZ/PUZ001+1.p", resolver: Tptp.Resolver.Fs)

Tptp.Unit.statements(unit)   # [{file_id, statement}], includes expanded in place
unit.files[unit.root]        # the root %Tptp.File{}

Resolution is explicit

The default resolver is Tptp.Resolver.None, which records each directive and reads nothing. Resolution reads files the caller did not name and, under Tptp.Resolver.Http, performs network access, so the resolver is supplied by the caller rather than defaulted.

Two representations

files is the set of files, each read once even where a diamond in the graph reaches it twice. statements/1 is the sequence, with each include expanded in position, which is what textual inclusion denotes and what a prover observes. A file read once may therefore occur twice in the sequence.

Formula selection

include('big.ax', [key_lemma]) retains only the named formulae, and the filter applies to the whole subtree beneath that directive rather than to big.ax alone. The TPTP standard does not define the meaning of a selection when the selected file has includes of its own; this reading makes include(f, [x]) denote the formula x wherever it occurs beneath the directive. A name occurring nowhere beneath it produces a TPTP0603 warning.

Summary

Types

Options accepted by the entry points.

t()

A root file and everything reachable from it through include, with the resolutions that got there.

Functions

Whether anything error-severity was found, in any file.

The file a span or id belongs to.

Every diagnostic, rendered one per line against the file it belongs to.

Every annotated formula, include directives expanded and filtered by selection.

Read a file from disk and everything it includes.

Read a file and everything it includes, raising Tptp.Error on any error.

Read a file the resolver knows by name, and everything it includes.

Read a file and everything it includes.

Every statement, with include directives expanded where they stand.

The bytes a span names, wherever in the unit it points.

Types

option()

@type option() ::
  Tptp.option()
  | {:resolver, Tptp.Resolver.t()}
  | {:max_depth, pos_integer()}
  | {:max_concurrency, pos_integer()}

Options accepted by the entry points.

Everything Tptp.option/0 accepts, plus:

  • :resolver — how an include name becomes bytes. Defaults to Tptp.Resolver.None, which follows nothing.
  • :max_concurrency — how many sibling includes are parsed at once. Defaults to System.schedulers_online(); set it to 1 for a strictly sequential walk, which is what a caller running under its own max_heap_size needs, since that ceiling is not inherited by the processes Tptp.Include spawns.
  • :max_depth — how deep the include graph may nest before the walk stops and says so. Defaults to 64.

t()

@type t() :: %Tptp.Unit{
  diagnostics: [Tptp.Diagnostic.t()],
  files: %{required(Tptp.Span.file_id()) => Tptp.File.t()},
  resolutions: %{
    required({Tptp.Span.file_id(), non_neg_integer()}) => Tptp.Span.file_id()
  },
  root: Tptp.Span.file_id()
}

A root file and everything reachable from it through include, with the resolutions that got there.

Functions

any_errors?(unit)

@spec any_errors?(t()) :: boolean()

Whether anything error-severity was found, in any file.

file(unit, id)

@spec file(t(), Tptp.Span.file_id() | Tptp.Span.t()) :: Tptp.File.t() | nil

The file a span or id belongs to.

format_diagnostics(unit)

@spec format_diagnostics(t()) :: [binary()]

Every diagnostic, rendered one per line against the file it belongs to.

formulae(unit)

@spec formulae(t()) :: [{Tptp.Span.file_id(), Tptp.Statement.Annotated.t()}]

Every annotated formula, include directives expanded and filtered by selection.

from_file(path, options \\ [])

@spec from_file(Path.t(), [option()]) ::
  {:ok, t(), [Tptp.Diagnostic.t()]} | {:error, [Tptp.Diagnostic.t()]}

Read a file from disk and everything it includes.

Fails only when the root file cannot be read; an include that cannot be resolved is a diagnostic on an otherwise usable unit.

from_file!(path, options \\ [])

@spec from_file!(Path.t(), [option()]) :: t()

Read a file and everything it includes, raising Tptp.Error on any error.

from_name(name, options \\ [])

@spec from_name(binary(), [option()]) ::
  {:ok, t(), [Tptp.Diagnostic.t()]} | {:error, [Tptp.Diagnostic.t()]}

Read a file the resolver knows by name, and everything it includes.

The entry point for a caller who has a TPTP name rather than a path — from a problem list, a benchmark set, or a user typing PUZ001+1.p. The root goes through the same resolver as its includes, so pointing $TPTP_ROOT at a local library or passing Tptp.Resolver.Http changes where everything comes from at once.

Tptp.Unit.from_name("Problems/PUZ/PUZ001+1.p", resolver: Tptp.Resolver.Fs)

from_string(source, options \\ [])

@spec from_string(binary(), [option()]) :: {:ok, t(), [Tptp.Diagnostic.t()]}

Read a file and everything it includes.

iex> resolver = {Tptp.Resolver.Map, files: %{"a.ax" => "fof(a, axiom, p)."}}
iex> {:ok, unit, []} = Tptp.Unit.from_string("include('a.ax'). fof(b, conjecture, p).", resolver: resolver)
iex> unit |> Tptp.Unit.statements() |> Enum.map(fn {_id, statement} -> statement.name.text end)
["a", "b"]

statements(unit)

@spec statements(t()) :: [{Tptp.Span.file_id(), Tptp.Statement.t()}]

Every statement, with include directives expanded where they stand.

Each element is {file_id, statement}, because the statement itself carries only offsets — the file it belongs to is what turns those into a position. The directives themselves are not in the result; they have been replaced by what they name. An unresolved directive contributes nothing, and said so at read time.

text(unit, span)

@spec text(t(), Tptp.Span.t()) :: binary() | nil

The bytes a span names, wherever in the unit it points.