diff --git a/doc/user/utilities/external_interface.rst b/doc/user/utilities/external_interface.rst index 8fe2118d05..c08e38a143 100644 --- a/doc/user/utilities/external_interface.rst +++ b/doc/user/utilities/external_interface.rst @@ -1,4 +1,4 @@ -External interface +External Interface ================== The external interface is supposed to allow interfacing with SeQuant from the outside, without having to write a C++ program that links to the SeQuant @@ -8,142 +8,46 @@ contains instructions for what you want SeQuant to do. .. _extint-input: -Input format +Input Format ------------ -See :ref:`io-Serialization`. +See :ref:`io-Serialization` for the format in which the input equations are expected to be. .. note:: It is assumed that the input always specifies a result. That is, it is of the format :code:`lhs = rhs`. Furthermore, every input file may only contain a single result. -Driver file + +Driver File ----------- -The top-level entry in the JSON file specifies what action SeQuant should take. At the moment, only code-generation into the ITF format is supported. -Hence, every driver file currently has to start like this: +There currently are two mostly independent implementations of the external interface available. Which version you want to use is determined by the +:code:`driver_format_version` key in the JSON driver. If you set it to a value of :code:`1`, you will get the old/legacy version of the interface. The +rest of the JSON file is expected to follow the syntax described in :ref:`external_interface_v1`. If you set it to :code:`2`, you will be using the +new, modular external interface. Its driver syntax is described in :ref:`external_interface_v2`. If the field is unset, the code defaults to :code:`1` +for reasons of backwards compatibility. -.. code-block:: json - { - "code_generation": { - "output_format": "itf", - ... - } - } +The main difference between the two versions is that the newer version is much more modular and flexible. Therefore, it is recommended that you use +that for all new tasks. .. note:: All paths specified in the driver file are understood to be relative to the JSON file's location (unless absolute paths are used, of course). -Beyond :code:`output_format`, the following top-level fields exist: - -* :code:`output_path` (required): The path to the file the generated code is written to -* :code:`default_options` (optional): Allows specification of default processing options -* :code:`code_blocks` (required): Specifies a list of code blocks (groups of expressions) - -Code block -^^^^^^^^^^ -Every code block has to have a :code:`name` and a list of :code:`results`. The former is effectively the name of the to-be-generated function that -computes the individual results (expressions), whereas the latter is a list of expressions that shall be computed. - -Every result has these mandatory fields: - -* :code:`name`: The name of the tensor/scalar variable that shall hold the result of the computed expression -* :code:`equation_file`: Path to the file containing the input expression (cmp :ref:`extint-input`) - -Additionally, the following *processing options* may be given. All of them may also be specified as part of the :code:`default_options` block in which -case those values are used, unless explicitly overwritten. - -* :code:`density_fitting`: Whether to perform the density-fitting decomposition of the two-electron integral -* :code:`term_by_term`: Whether to split sums into individual summands for processing and code-generation. This yields to more readable but less - performant code. -* :code:`optimize`: Whether to factorize the equations into a series of binary contractions -* :code:`subexpression_elimination`: Whether to eliminate common subexpressions (only possible when factorizing into binary contractions) -* :code:`expand_symmetrizer`: Whether to explicitly expand (write out) symmetrization operators -* :code:`spintracing`: What kind of spintracing to perform (if any). Possible options are - - * :code:`none`: Don't perform spintracing - * :code:`closed_shell`: Apply spintracing using an algorithm suitable for closed-shell systems - * :code:`rigorous`: Apply spintracing using an algorithm that should work for all cases, but is less efficient than :code:`closed_shell` - -* :code:`projection`: What kind of projection/transformation to perform with the final result - - * :code:`primitive`: Don't do anything - * :code:`biorthogonal`: Transform the result into a biorthogonal basis (only applicable to non-scalar results) - - -Index space specification -^^^^^^^^^^^^^^^^^^^^^^^^^ - -Every driver file has to contain the definition of index spaces that are used in expressions. This definition lives under the :code:`index_spaces` -element. Every specification has to provide the following attributes: - -* :code:`name`: Name of the index space -* :code:`tag`: Tag for this index space (if any). Tags are used to encode the spaces of a tensor's indices in its name. May be empty. -* :code:`label`: Label used in expressions for indices in this space, e.g. in :code:`i1` the label is :code:`i`. -* :code:`size`: The size/dimension of indices in this index space. This affects factorization into binary contractions. - -Example -^^^^^^^ - -.. code-block:: json - - { - "code_generation": { - "output_format": "itf", - "default_options": { - "density_fitting": false, - "term_by_term": false, - "spintracing": "closed_shell", - "projection": "biorthogonal" - }, - "output_path": "something.itfaa", - "code_blocks": [ - { - "name": "First", - "results": [ - { - "name": "One", - "equation_file": "first.inp", - "projection": "primitive" - } - ] - }, - { - "name": "Second", - "results": [ - { - "name": "Two", - "equation_file": "second.inp", - "projection": "primitive" - }, - { - "name": "Three", - "equation_file": "third.inp", - "spintracing": "rigorous" - } - ] - }, - ] - }, - "index_spaces": [ - { - "name": "virtual", - "tag": "e", - "label": "a", - "size": 100 - }, - { - "name": "active", - "tag": "a", - "label": "u", - "size": 5 - }, - { - "name": "occupied", - "tag": "c", - "label": "i", - "size": 10 - } - ] - } + +Common Syntax +^^^^^^^^^^^^^ + +.. _external_interface_idx_space: + +Index Space Specification +""""""""""""""""""""""""" + +Every driver file has to contain the definition of index spaces that are used in expressions. It lives under the top-level key :code:`index_spaces` +and is expected to be an array of objects. These objects can have the following properties + +* :code:`label` (required, String): Label used in expressions for indices in this space, e.g. in :code:`i1` the label is :code:`i`. +* :code:`size` (required, Integer): The (approximate) size/dimension of indices in this index space. This affects things like factorization into + binary contractions. +* :code:`real_valued` (Boolean): Whether the field used in this index space is real- rather than complex-valued. This affects for instance tensors + with hermitian braket symmetry. diff --git a/doc/user/utilities/external_interface_v1.rst b/doc/user/utilities/external_interface_v1.rst new file mode 100644 index 0000000000..c4dc22b54d --- /dev/null +++ b/doc/user/utilities/external_interface_v1.rst @@ -0,0 +1,125 @@ +.. _external_interface_v1: + +Driver File v1 +============== + +The top-level entry in the JSON file specifies what action SeQuant should take. At the moment, only code-generation into the ITF format is supported. +Hence, every driver file currently has to start like this: + +.. code-block:: json + { + "code_generation": { + "output_format": "itf", + ... + } + } + +Beyond :code:`output_format`, the following top-level fields exist: + +* :code:`output_path` (required): The path to the file the generated code is written to +* :code:`default_options` (optional): Allows specification of default processing options +* :code:`code_blocks` (required): Specifies a list of code blocks (groups of expressions) + +Code Block +---------- +Every code block has to have a :code:`name` and a list of :code:`results`. The former is effectively the name of the to-be-generated function that +computes the individual results (expressions), whereas the latter is a list of expressions that shall be computed. + +Every result has these mandatory fields: + +* :code:`name`: The name of the tensor/scalar variable that shall hold the result of the computed expression +* :code:`equation_file`: Path to the file containing the input expression (cmp :ref:`extint-input`) + +Additionally, the following *processing options* may be given. All of them may also be specified as part of the :code:`default_options` block in which +case those values are used, unless explicitly overwritten. + +* :code:`density_fitting`: Whether to perform the density-fitting decomposition of the two-electron integral +* :code:`term_by_term`: Whether to split sums into individual summands for processing and code-generation. This yields to more readable but less + performant code. +* :code:`optimize`: Whether to factorize the equations into a series of binary contractions +* :code:`subexpression_elimination`: Whether to eliminate common subexpressions (only possible when factorizing into binary contractions) +* :code:`expand_symmetrizer`: Whether to explicitly expand (write out) symmetrization operators +* :code:`spintracing`: What kind of spintracing to perform (if any). Possible options are + + * :code:`none`: Don't perform spintracing + * :code:`closed_shell`: Apply spintracing using an algorithm suitable for closed-shell systems + * :code:`rigorous`: Apply spintracing using an algorithm that should work for all cases, but is less efficient than :code:`closed_shell` + +* :code:`projection`: What kind of projection/transformation to perform with the final result + + * :code:`primitive`: Don't do anything + * :code:`biorthogonal`: Transform the result into a biorthogonal basis (only applicable to non-scalar results) + + +Index Space Specification +------------------------- + +See :ref:`external_interface_idx_space`. Additionally, the following properties are **required**: + +* :code:`name` (String): Name of the index space +* :code:`tag` (String): Tag for this index space (if any). Tags are used to encode the spaces of a tensor's indices in its name. May be empty. + +Example +------- + +.. code-block:: json + + { + "code_generation": { + "output_format": "itf", + "default_options": { + "density_fitting": false, + "term_by_term": false, + "spintracing": "closed_shell", + "projection": "biorthogonal" + }, + "output_path": "something.itfaa", + "code_blocks": [ + { + "name": "First", + "results": [ + { + "name": "One", + "equation_file": "first.inp", + "projection": "primitive" + } + ] + }, + { + "name": "Second", + "results": [ + { + "name": "Two", + "equation_file": "second.inp", + "projection": "primitive" + }, + { + "name": "Three", + "equation_file": "third.inp", + "spintracing": "rigorous" + } + ] + }, + ] + }, + "index_spaces": [ + { + "name": "virtual", + "tag": "e", + "label": "a", + "size": 100 + }, + { + "name": "active", + "tag": "a", + "label": "u", + "size": 5 + }, + { + "name": "occupied", + "tag": "c", + "label": "i", + "size": 10 + } + ] + } diff --git a/doc/user/utilities/external_interface_v2.rst b/doc/user/utilities/external_interface_v2.rst new file mode 100644 index 0000000000..d8e2a4b2fb --- /dev/null +++ b/doc/user/utilities/external_interface_v2.rst @@ -0,0 +1,307 @@ +.. _external_interface_v2: + +Driver File v2 +============== + + +The external interface implementation provides a series of individual processing steps that can be selected and chained by means of the JSON driver +file. Within this file, each processing step is represented as a JSON object with the following properties: + +* :code:`kind` (required, String): This is a unique identifier for every different kind of steps and therefore determines what this step will do when + exectuted. +* :code:`id` (String): Unique identifier for this particular step. This can be used to refer to (the output of) other steps. +* :code:`options` (Object): Set of options to tune the behavior of the step as needed. Some steps don't have options, whereas others require you to + specify them. For most steps, options are optional. The properties of the options object depend on the step's kind - see + :ref:`external_interface_step_kinds`. +* :code:`outputs` (Object): This can be used to give human-readable names to individual outputs of the current step in form of name-output pairs. See + :ref:`external_interface_outputs` - the step ID in this case is implicitly the current step's ID and must not be included explicitly. These names + are automatically propagated through the processing chain (for most kinds of steps). +* :code:`inputs` (String or Array of Strings): Specifies the inputs of this step, which must be outputs of other steps. See + :ref:`external_interface_outputs`. + + +The different steps are listed objects in the top-level :code:`steps` array. Steps are processed in order according to their order in this array. + + +.. _external_interface_outputs: + +Referencing Outputs +------------------- + +Outputs can be referenced by means of their IDs. An ID has the general format :code:`.`. :code:`` must refer to the +:code:`id` of one of the steps that have been executed before. :code:`` can be the human-readable names specified via a step's +:code:`outputs` property or an integer. In the latter case, the integer refers to the index of the output. Outputs are indexed starting from zero in +the order they are produced. + +:code:`` can also be an expression enclosed in square brackets in order to refer to multiple outputs at once. This can be a comma-delimited +(no spaces!) list of output names or indices, or a range of indices which are of the form :code:`-` like :code:`0-5`. + +Examples of output IDs: + +* :code:`my_step.0` +* :code:`my_step.some_name` +* :code:`my_step.[0-2]` +* :code:`my_step.[0-2,some_name,5]` + +Finally, to refer to all outputs of a given step, just use the step's ID without anything appended to it. That is, `my_step` would automatically refer +to all outputs of the respective step. + + +.. external_interface_step_kinds: + +Available Processing Step Kinds +------------------------------- + + +canonicalize +^^^^^^^^^^^^ + +Canonicalizes the input expressions. + + +cse +^^^ + +Performs common-subexpression elimination (CSE). + + +density_fitting +^^^^^^^^^^^^^^^ + +Inserts the density-fitting decomposition of the two-electron integrals. + + +export +^^^^^^ + +Exports the given expressions as code. + + +index_batching +^^^^^^^^^^^^^^ + +Configures the computation of results to happen in batches over certain result indices. + + +optimize +^^^^^^^^ + +Symbolically rewrites the expressions for an improved numerical evaluation. Most prominently, this factors tensor contractions into a series of binary +tensor contractions. + + +output +^^^^^^ + +Outputs expressions in the chosen markup style. Mainly intended for debugging purposes. + + +project +^^^^^^^ + +Performs the chosen projection with the inputs. + + +read_input +^^^^^^^^^^ + +Reads and parses expressions from files. + + +simplify +^^^^^^^^ + +Simplifies the given expressions. + + +spintracing +^^^^^^^^^^^ + +Spintraces the given expressions. That is, it performs spin-integration and potentially also spin-summation. + + +substitute +^^^^^^^^^^ + +Makes substitutions in the given expressions + + +to_export_tree +^^^^^^^^^^^^^^ + +Converts the given expressions into a tree data structure suitable for exports. + + +validate +^^^^^^^^ + +Validates the given expressions + + + +Examples +-------- + +.. code-block:: json + + { + "driver_format_version": 2, + "index_spaces": [ + { + "label": "a", + "size": 1000, + "real_valued": true + }, + { + "label": "u", + "size": 5, + "real_valued": true + }, + { + "label": "i", + "size": 80, + "real_valued": true + }, + { + "label": "F", + "size": 1500, + "real_valued": true + } + ], + "steps": [ + { + "id": "input", + "kind": "read_input", + "options": { + "file_path": [ + "nevpt2/nevpt2_en0.inp", + "nevpt2/nevpt2_en.inp", + + "nevpt2/nevpt2_res1_i1.inp", + "nevpt2/nevpt2_res1_s0.inp", + "nevpt2/nevpt2_res2_s1_singles.inp", + "nevpt2/nevpt2_res1_s1.inp", + + "nevpt2/nevpt2_res2_p0.inp", + "nevpt2/nevpt2_res2_p2.inp", + "nevpt2/nevpt2_res2_i2.inp", + "nevpt2/nevpt2_res2_p1.inp", + "nevpt2/nevpt2_res2_s1.inp", + "nevpt2/nevpt2_res2_s2.inp" + ], + "default_symmetry": "antisymmetric" + }, + "outputs": { + "ecc0": "0", + "ecc": "1", + "en": "0-1", + "res1": "2-5", + "res1_i1": "2", + "res1_s0": "3", + "res2_s1_singles": "4", + "res1_s1": "5", + "res2": "6-11", + "res2_p0": "6", + "res2_p2": "7", + "res2_i2": "8", + "res2_p1": "9", + "res2_s1": "10", + "res2_s2": "11", + "res": "2-11" + } + }, + { + "kind": "validate", + "inputs": "input" + }, + { + "id": "DF", + "kind": "density_fitting", + "inputs": "input", + "options": { + "auxiliary_space": "F" + } + }, + { + "id": "traced", + "kind": "spintracing", + "inputs": "DF", + "options": { + "algorithm": "closed_shell" + } + }, + { + "id": "biorth", + "kind": "project", + "inputs": "traced.res", + "options": { + "method": "biorthogonal" + } + }, + { + "id": "opt", + "kind": "optimize", + "inputs": [ + "traced.en", + "biorth" + ] + }, + { + "id": "treeify", + "kind": "to_export_tree", + "inputs": "opt" + }, + { + "kind": "export", + "inputs": "treeify", + "options": { + "language": "itf", + "optimize": true, + "output": "nevpt2_v2.itfaa", + "grouping": { + "Energy0": "ecc0", + "Energy": "ecc", + "Residual": "res" + }, + "relative_order": [ + "ecc0", + "ecc", + "res1_i1", + "res1_s0", + "res2_s1_singles", + "res1_s1", + "res2_p0", + "res2_p2", + "res2_i2", + "res2_p1", + "res2_s1", + "res2_s2" + ], + "imports": { + "R2{a1;i1}": "R2:ec" + }, + "meta": { + "index_spaces": { + "a": { + "name": "External", + "tag": "e" + }, + "u": { + "name": "Active", + "tag": "a" + }, + "i": { + "name": "Closed", + "tag": "c" + }, + "F": { + "name": "BasisMp2Fit", + "tag": "F" + } + }, + "min_index_id": 1 + } + } + } + } +