diff --git a/Project.toml b/Project.toml index 7ca5f44e..4c532f4f 100644 --- a/Project.toml +++ b/Project.toml @@ -1,6 +1,6 @@ name = "ITensorNetworks" uuid = "2919e153-833c-4bdc-8836-1ea460a35fc7" -version = "0.19.6" +version = "0.19.7" authors = ["Matthew Fishman , Joseph Tindall and contributors"] [workspace] diff --git a/docs/make.jl b/docs/make.jl index 83200c84..18cf0162 100644 --- a/docs/make.jl +++ b/docs/make.jl @@ -42,6 +42,12 @@ makedocs(; "Computing Properties" => "computing_properties.md", "Solvers" => "solvers.md", ], + "Developer Reference" => [ + "Interface Methods" => "interface_methods.md", + "Developer Methods" => "developer_methods.md", + "Experimental Methods" => "experimental_methods.md", + "Deprecated Methods" => "deprecated_methods.md", + ], "API Reference" => "reference.md", ] ) diff --git a/docs/src/deprecated_methods.md b/docs/src/deprecated_methods.md new file mode 100644 index 00000000..1d8800dd --- /dev/null +++ b/docs/src/deprecated_methods.md @@ -0,0 +1,148 @@ +# Deprecated Methods + +Suggestions of methods which could be deleted. + +## ITensorNetwork Methods + +#### ITensorNetwork Constructors + +* Default constructor (`itensornetwork.jl`). + ```julia + ITensorNetwork{V}() + ``` + +* (Only actually deprecate / delete this function if the more generic constructor `ITensorNetwork(tensors)` can also handle this case.) + From a vector of `ITensor`s, with vertex labels auto-assigned to `eachindex(ts)`. + Edges are inferred from shared indices (`itensornetwork.jl`): + ```julia + ITensorNetwork(ts::AbstractVector{ITensor}) + ``` + +* From a collection of ITensorNetworks. Merges (Kronecker or tensor product) of input networks (`itensornetwork.jl`): + ```julia + ITensorNetwork(itns::Vector{ITensorNetwork}) + ``` + +* From a named graph, forwards to construction from `IndsNetwork` (`itensornetwork.jl`): + ```julia + ITensorNetwork{V}(g::NamedGraph) + ITensorNetwork(eltype::Type, undef::UndefInitializer, graph::AbstractNamedGraph; kws...) + ITensorNetwork(f, graph::AbstractNamedGraph; kwargs...) + ITensorNetwork(graph::AbstractNamedGraph; kwargs...) + ``` + +* From a simple graph, forwards to construction from `IndsNetwork` (`itensornetwork.jl`): + ```julia + ITensorNetwork(eltype::Type, undef::UndefInitializer, graph::AbstractSimpleGraph; kws...) + ITensorNetwork(f, graph::AbstractSimpleGraph; kwargs...) + ITensorNetwork(graph::AbstractSimpleGraph; kwargs...) + ``` + +* From a function over vertices or from a "value" (e.g. a string like `"Up"`, + an `Op`, an array, or a per-vertex dict/array) that is converted to a callable and used + to initialize each vertex tensor (`itensornetwork.jl`): + ```julia + ITensorNetwork(value, is::IndsNetwork; kwargs...) + ITensorNetwork(elt::Type, f, is::IndsNetwork; link_space = trivial_space(is), kws...) + ITensorNetwork(itensor_constructor::Function, is::IndsNetwork; link_space = trivial_space(is), kwargs...) + ``` + +* From a single `ITensor`. Wraps the tensor in a single-vertex network (`itensornetwork.jl`): + ```julia + ITensorNetwork(t::ITensor) + ``` + +* Construct an `ITensorNetwork` from an `IndsNetwork`. Initializes ITensors with `undef` storage on each vertex + of the `IndsNetwork` with the corresponding indices (`itensornetwork.jl`): + ```julia + ITensorNetwork(eltype::Type, undef::UndefInitializer, is::IndsNetwork; kwargs...) + ITensorNetwork(eltype::Type, is::IndsNetwork; kwargs...) + ITensorNetwork(undef::UndefInitializer, is::IndsNetwork; kwargs...) + ITensorNetwork(is::IndsNetwork; kwargs...) + ``` + +#### Local Operations on ITensorNetworks + +* Versions of `siteinds` taking a `vertex` argument. Each of these is just an alias for `uniqueinds`. Possibly the wrong design / implementation. (`abstractitensornetwork.jl`). + ```julia + siteinds(tn::AbstractITensorNetwork, vertex) # abstractitensornetwork.jl:288 + siteinds(tn::AbstractITensorNetwork, vertex::Int) # abstractitensornetwork.jl:292 + ``` + + +* Functions in `apply.jl` which are unused, even inside that file (`apply.jl`): + ```julia + _gate_vertices(o::ITensor, ψ) + _gate_vertices(o::AbstractEdge, ψ) + _contract_gate(o::ITensor, ψv1, Λ, ψv2) + _contract_gate(o::AbstractEdge, ψv1, Λ, ψv2) + ``` + +* Collection of tensors neighboring the given vertex (`abstractitensornetwork.jl`): + ```julia + neighbor_tensors(tn::AbstractITensorNetwork, vertex) + ``` + +* Iterate over the tensors at the given vertices, default all vertices (`abstractitensornetwork.jl`): + ```julia + eachtensor(tn::AbstractITensorNetwork, vertices = vertices(tn)) + ``` + +* Indices on the source tensor of `edge` that are not shared with the destination tensor. + (`abstractitensornetwork.jl`): + ```julia + uniqueinds(tn::AbstractITensorNetwork, edge::AbstractEdge) + uniqueinds(tn::AbstractITensorNetwork, edge::Pair) + ``` + +* Alias for `uniqueinds` (`abstractitensornetwork.jl`): + ```julia + siteinds(tn::AbstractITensorNetwork, vertex) + siteinds(tn::AbstractITensorNetwork, vertex::Int) + ``` + +* Indices common to the ITensors on the vertices connected by the edge (`abstractitensornetwork.jl`): + (Use a set function like `intersection` instead.) + ```julia + commoninds(tn::AbstractITensorNetwork, edge) + linkinds(tn::AbstractITensorNetwork, edge) + ``` + +* Indices on `tn[vertex]` that aren't shared with any neighbor, i.e. the external/site + indices of that vertex (`abstractitensornetwork.jl`). + (Use a set function like `setdiff` instead.) + ```julia + uniqueinds(tn::AbstractITensorNetwork, vertex) + ``` + +## Global Operations on ITensorNetworks + + +## TreeTensorNetwork Constructors + +* From `Op` and related types (`opsum_to_ttn.jl`): + ```julia + ttn(o::Op, s::IndsNetwork; kws...) + ttn(o::Scaled{C, Op}, s::IndsNetwork; kws...) + ttn(o::Sum{Op}, s::IndsNetwork; kws...) + ttn(o::Prod{Op}, s::IndsNetwork; kws...) + ttn(o::Scaled{C, Prod{Op}}, s::IndsNetwork; kws...) + ttn(o::Sum{Scaled{C, Op}}, s::IndsNetwork; kws...) + ``` + +## Miscellaneous Methods + +* Methods in `partitioneditensornetwork.jl`. + ```julia + linkinds(pitn::PartitionedGraph, edge::QuotientEdge) + ``` + To be revisited after Jack's work on NamedGraphs. + +* Methods in `graphs.jl`. + Just one methods which constructs a `SimpleGraph` from ITensors (`graphs.jl`). + ```julia + SimpleGraphs.SimpleGraph(itensors::Vector{ITensor}) + ``` + Not used anywhere in library. + +* Methods in `update_observer.jl`. Not used anywhere in library. diff --git a/docs/src/developer_methods.md b/docs/src/developer_methods.md new file mode 100644 index 00000000..0e132df0 --- /dev/null +++ b/docs/src/developer_methods.md @@ -0,0 +1,407 @@ +# Developer Methods + +## Form Networks + +#### AbstractFormNetwork + +* Required-to-implement abstract interface — each concrete `AbstractFormNetwork` subtype + defines these (`formnetworks/abstractformnetwork.jl`): + ```julia + dual_index_map(f::AbstractFormNetwork) + tensornetwork(f::AbstractFormNetwork) + copy(f::AbstractFormNetwork) + operator_vertex_suffix(f::AbstractFormNetwork) + bra_vertex_suffix(f::AbstractFormNetwork) + ket_vertex_suffix(f::AbstractFormNetwork) + ``` + +* Graph plumbing forwarded to the underlying tensor network (`formnetworks/abstractformnetwork.jl`): + ```julia + data_graph(f::AbstractFormNetwork) + data_graph_type(f::AbstractFormNetwork) + ``` + +* Lists of vertices in each role: those tagged with the operator/bra/ket suffix (`formnetworks/abstractformnetwork.jl`): + ```julia + operator_vertices(f::AbstractFormNetwork) + bra_vertices(f::AbstractFormNetwork) + ket_vertices(f::AbstractFormNetwork) + ``` + +* Vertex-renaming functions: closures `v -> (v, suffix)` that map an original-state + vertex to its operator/bra/ket-tagged counterpart (`formnetworks/abstractformnetwork.jl`): + ```julia + operator_vertex_map(f::AbstractFormNetwork) + bra_vertex_map(f::AbstractFormNetwork) + ket_vertex_map(f::AbstractFormNetwork) + ``` + +* Apply the corresponding vertex map to a single vertex `v` (`formnetworks/abstractformnetwork.jl`): + ```julia + operator_vertex(f::AbstractFormNetwork, v) + bra_vertex(f::AbstractFormNetwork, v) + ket_vertex(f::AbstractFormNetwork, v) + ``` + +#### LinearFormNetwork + +* Construct a `LinearFormNetwork` representing `⟨bra|ket⟩`. Optional suffix kwargs and + a `dual_link_index_map` (default `prime`) control how bra link indices are made + distinct from ket link indices (`formnetworks/linearformnetwork.jl`): + ```julia + LinearFormNetwork(bra::AbstractITensorNetwork, ket::AbstractITensorNetwork; bra_vertex_suffix, ket_vertex_suffix, dual_link_index_map) + ``` + +* Construct a `LinearFormNetwork` from an existing `BilinearFormNetwork` by absorbing + the operator into the bra side (`formnetworks/linearformnetwork.jl`): + ```julia + LinearFormNetwork(blf::BilinearFormNetwork) + ``` + +* Suffix and tensor-network accessors (`formnetworks/linearformnetwork.jl`): + ```julia + bra_vertex_suffix(lf::LinearFormNetwork) + ket_vertex_suffix(lf::LinearFormNetwork) + tensornetwork(lf::LinearFormNetwork) + ``` + +* Copy a `LinearFormNetwork` (deep-copies the underlying tensor network) (`formnetworks/linearformnetwork.jl`): + ```julia + copy(lf::LinearFormNetwork) + ``` + +* Replace the ket-side tensor at the original vertex `original_ket_state_vertex` with + `ket_state` (graph-preserving update) (`formnetworks/linearformnetwork.jl`): + ```julia + update(lf::LinearFormNetwork, original_ket_state_vertex, ket_state::ITensor) + ``` + +#### BilinearFormNetwork + +* Construct a `BilinearFormNetwork` representing `⟨bra|operator|ket⟩`. Optional suffix + kwargs and `dual_site_index_map` (default `prime`) / `dual_link_index_map` (default + `sim`) control how bra indices are distinguished from ket indices (`formnetworks/bilinearformnetwork.jl`): + ```julia + BilinearFormNetwork(operator::AbstractITensorNetwork, bra::AbstractITensorNetwork, ket::AbstractITensorNetwork; operator_vertex_suffix, bra_vertex_suffix, ket_vertex_suffix, dual_site_index_map, dual_link_index_map) + ``` + +* Construct from `bra` and `ket` only — the operator network is built automatically + as a per-vertex identity from `siteinds(ket)` to `dual_site_index_map(siteinds(ket))` (`formnetworks/bilinearformnetwork.jl`): + ```julia + BilinearFormNetwork(bra::AbstractITensorNetwork, ket::AbstractITensorNetwork; dual_site_index_map, kwargs...) + ``` + +* Build the identity ITensor mapping `first(i_pair) → last(i_pair)` for each pair, used + to assemble the auto-generated operator network (`formnetworks/bilinearformnetwork.jl`): + ```julia + itensor_identity_map(elt::Type, i_pairs::Vector) + itensor_identity_map(i_pairs::Vector) + ``` + +* Suffix and tensor-network accessors (`formnetworks/bilinearformnetwork.jl`): + ```julia + operator_vertex_suffix(blf::BilinearFormNetwork) + bra_vertex_suffix(blf::BilinearFormNetwork) + ket_vertex_suffix(blf::BilinearFormNetwork) + tensornetwork(blf::BilinearFormNetwork) + ``` + +* Copy a `BilinearFormNetwork` (`formnetworks/bilinearformnetwork.jl`): + ```julia + copy(blf::BilinearFormNetwork) + ``` + +* Replace the bra and ket tensors at the original vertices with `bra_state` and + `ket_state` (graph-preserving update) (`formnetworks/bilinearformnetwork.jl`): + ```julia + update(blf::BilinearFormNetwork, original_bra_state_vertex, original_ket_state_vertex, bra_state::ITensor, ket_state::ITensor) + ``` + +#### QuadraticFormNetwork + +* Construct a `QuadraticFormNetwork` representing `⟨ψ|operator|ψ⟩` (or `⟨ψ|ψ⟩` if the + operator is omitted). Internally wraps a `BilinearFormNetwork` whose bra is the dual + of `ket`. `dual_index_map` (default `prime`) / `dual_inv_index_map` (default `noprime`) + control how bra indices are produced from ket indices (`formnetworks/quadraticformnetwork.jl`): + ```julia + QuadraticFormNetwork(operator::AbstractITensorNetwork, ket::AbstractITensorNetwork; dual_index_map, dual_inv_index_map, kwargs...) + QuadraticFormNetwork(ket::AbstractITensorNetwork; dual_index_map, dual_inv_index_map, kwargs...) + ``` + +* Access the underlying `BilinearFormNetwork` and the index-map functions (`formnetworks/quadraticformnetwork.jl`): + ```julia + bilinear_formnetwork(qf::QuadraticFormNetwork) + dual_index_map(qf::QuadraticFormNetwork) + dual_inv_index_map(qf::QuadraticFormNetwork) + ``` + +* Forwarded accessors — these queries are answered by the inner `BilinearFormNetwork` (`formnetworks/quadraticformnetwork.jl`): + ```julia + operator_vertex_suffix(qf::QuadraticFormNetwork) + bra_vertex_suffix(qf::QuadraticFormNetwork) + ket_vertex_suffix(qf::QuadraticFormNetwork) + tensornetwork(qf::QuadraticFormNetwork) + data_graph(qf::QuadraticFormNetwork) + data_graph_type(qf::QuadraticFormNetwork) + ``` + +* Copy a `QuadraticFormNetwork` (deep-copies the inner bilinear form) (`formnetworks/quadraticformnetwork.jl`): + ```julia + copy(qf::QuadraticFormNetwork) + ``` + +* Replace the tensor at the original vertex with `ket_state` — the bra-side tensor is + generated automatically by applying `dual_index_map` to the dag of `ket_state` (`formnetworks/quadraticformnetwork.jl`): + ```julia + update(qf::QuadraticFormNetwork, original_state_vertex, ket_state::ITensor) + ``` + +## Caches for BP + +#### Edge Sequence Helpers + +* Build an edge traversal sequence over `g`, dispatched by `alg` (default `"forest_cover"`). + Directed graphs are handled by undirecting first (`edge_sequences.jl`): + ```julia + edge_sequence(g; alg, kwargs...) + edge_sequence(alg::Algorithm, g; kwargs...) + ``` + +* Tree-traversal sequence: cover `g` with a forest, then for each tree push a post-order + DFS sweep followed by its reverse — gives a back-and-forth sequence covering every edge (`edge_sequences.jl`): + ```julia + edge_sequence(::Algorithm"forest_cover", g; root_vertex = GraphsExtensions.default_root_vertex) + ``` + +* Parallel sequence: each edge (and its reverse) as its own one-edge group, suitable + for parallel BP updates (`edge_sequences.jl`): + ```julia + edge_sequence(::Algorithm"parallel", g) + ``` + +#### AbstractBeliefPropagationCache + +* Required-to-implement abstract interface — concrete subtypes must define these + (`caches/abstractbeliefpropagationcache.jl`): + ```julia + # How many of these are user-facing versus internal? + setindex!(bpc::AbstractBeliefPropagationCache, factor::ITensor, vertex) + partitioned_tensornetwork(bpc::AbstractBeliefPropagationCache) + messages(bpc::AbstractBeliefPropagationCache) + copy(bpc::AbstractBeliefPropagationCache) + partitions(bpc::AbstractBeliefPropagationCache) + quotientedges(bpc::AbstractBeliefPropagationCache) + partitioned_vertices(bpc::AbstractBeliefPropagationCache) + environment(bpc::AbstractBeliefPropagationCache, verts::Vector; kwargs...) + region_scalar(bpc::AbstractBeliefPropagationCache, pv::QuotientVertex; kwargs...) + region_scalar(bpc::AbstractBeliefPropagationCache, pe::QuotientEdge; kwargs...) + ``` + +* Forward type plumbing to the underlying tensor network and access the unpartitioned + network behind a cache (`caches/abstractbeliefpropagationcache.jl`): + ```julia + similar_type(bpc::AbstractBeliefPropagationCache) + data_graph_type(bpc::AbstractBeliefPropagationCache) + data_graph(bpc::AbstractBeliefPropagationCache) + tensornetwork(bpc::AbstractBeliefPropagationCache) + scalartype(bpc::AbstractBeliefPropagationCache) + ``` + +* Partition-graph queries forwarded to the underlying `PartitionedGraph` (`caches/abstractbeliefpropagationcache.jl`): + ```julia + vertices(bpc::AbstractBeliefPropagationCache) + quotient_graph(bpc::AbstractBeliefPropagationCache) + quotientedge(bpc::AbstractBeliefPropagationCache, edge::AbstractEdge) + quotientvertices(bpc::AbstractBeliefPropagationCache) + quotientvertices(bpc::AbstractBeliefPropagationCache, vs) + boundary_quotientedges(bpc::AbstractBeliefPropagationCache, quotientvertices; kwargs...) + boundary_quotientedges(bpc::AbstractBeliefPropagationCache, quotientvertex::QuotientVertex; kwargs...) + linkinds(bpc::AbstractBeliefPropagationCache, pe::QuotientEdge) + ``` + +* Vertex tensors (factors) at given vertices, or for all vertices in the given + partitions (`caches/abstractbeliefpropagationcache.jl`): + ```julia + factors(bpc::AbstractBeliefPropagationCache, verts::Vector) + factors(bpc::AbstractBeliefPropagationCache, partition_verts::Vector{<:QuotientVertex}) + factors(bpc::AbstractBeliefPropagationCache, partition_vertex::QuotientVertex) + ``` + +* Out-of-place factor updates — replace one or many vertex tensors, returning a new cache (`caches/abstractbeliefpropagationcache.jl`): + ```julia + update_factor(bpc, vertex, factor) + update_factors(bpc::AbstractBeliefPropagationCache, factors) + ``` + +* Apply a function to every (or a chosen subset of) factor tensors (`caches/abstractbeliefpropagationcache.jl`): + ```julia + map_factors(f, bpc::AbstractBeliefPropagationCache, vs = vertices(bpc)) + ``` + +* Read messages from the cache: a single message (with default fallback when missing), + or a vector of messages on the given edges (`caches/abstractbeliefpropagationcache.jl`): + ```julia + message(bpc::AbstractBeliefPropagationCache, edge::QuotientEdge; kwargs...) + messages(bpc::AbstractBeliefPropagationCache, edges; kwargs...) + ``` + +* Set messages — in-place (`!`) variants mutate the cache, the non-`!` variants return + a new cache (`caches/abstractbeliefpropagationcache.jl`): + ```julia + set_message!(bpc::AbstractBeliefPropagationCache, pe::QuotientEdge, message) + set_messages!(bpc::AbstractBeliefPropagationCache, quotientedges_messages) + set_message(bpc::AbstractBeliefPropagationCache, pe::QuotientEdge, message) + set_messages(bpc::AbstractBeliefPropagationCache, quotientedges_messages) + ``` + +* Delete messages on chosen edges (or all edges); same in-place vs out-of-place + convention as `set_message[s]` (`caches/abstractbeliefpropagationcache.jl`): + ```julia + delete_message!(bpc::AbstractBeliefPropagationCache, pe::QuotientEdge) + delete_messages!(bpc::AbstractBeliefPropagationCache, pes::Vector{<:QuotientEdge} = keys(messages(bpc))) + delete_message(bpc::AbstractBeliefPropagationCache, pe::QuotientEdge) + delete_messages(bpc::AbstractBeliefPropagationCache, pes::Vector{<:QuotientEdge} = keys(messages(bpc))) + ``` + +* Apply a function to every (or a chosen subset of) message tensors (`caches/abstractbeliefpropagationcache.jl`): + ```julia + map_messages(f, bpc::AbstractBeliefPropagationCache, pes = collect(keys(messages(bpc)))) + ``` + +* Collect the messages flowing into a partition vertex (or set of partition vertices), + optionally ignoring some edges (`caches/abstractbeliefpropagationcache.jl`): + ```julia + incoming_messages(bpc::AbstractBeliefPropagationCache, partition_vertices::Vector{<:QuotientVertex}; ignore_edges = ()) + incoming_messages(bpc::AbstractBeliefPropagationCache, partition_vertex::QuotientVertex; kwargs...) + ``` + +* Convergence proxy: `1 - |⟨a|b⟩|²` between two normalized contracted messages (`caches/abstractbeliefpropagationcache.jl`): + ```julia + message_diff(message_a::Vector{ITensor}, message_b::Vector{ITensor}) + ``` + +* Adapt support — propagate `adapt(to, ·)` over messages, factors, or both (used for + GPU/eltype migration) (`caches/abstractbeliefpropagationcache.jl`): + ```julia + adapt_messages(to, bpc::AbstractBeliefPropagationCache, args...) + adapt_factors(to, bpc::AbstractBeliefPropagationCache, args...) + adapt_structure(to, bpc::AbstractBeliefPropagationCache) + ``` + +* Region scalars per partition vertex / partition edge, and the convenient pair of + vectors used by `logscalar` (`caches/abstractbeliefpropagationcache.jl`): + ```julia + vertex_scalars(bpc::AbstractBeliefPropagationCache, pvs = partitions(bpc); kwargs...) + edge_scalars(bpc::AbstractBeliefPropagationCache, pes = quotientedges(bpc); kwargs...) + scalar_factors_quotient(bpc::AbstractBeliefPropagationCache) + ``` + +* The (log of the) BP estimate of the network scalar `⟨tn⟩` from current messages (`caches/abstractbeliefpropagationcache.jl`): + ```julia + logscalar(bpc::AbstractBeliefPropagationCache) + scalar(bpc::AbstractBeliefPropagationCache) + ``` + +* Compute an updated message on `edge` — either via straight contraction (with optional + normalization), via an `adapt`-then-update wrapper, or via the user-facing dispatcher + that fills in defaults (`caches/abstractbeliefpropagationcache.jl`): + ```julia + updated_message(alg::Algorithm"contract", bpc::AbstractBeliefPropagationCache, edge::QuotientEdge) + updated_message(alg::Algorithm"adapt_update", bpc::AbstractBeliefPropagationCache, edge::QuotientEdge) + updated_message(bpc::AbstractBeliefPropagationCache, edge::QuotientEdge; alg, kwargs...) + ``` + +* Compute the updated message and write it back into a copied cache (`caches/abstractbeliefpropagationcache.jl`): + ```julia + update_message(message_update_alg::Algorithm, bpc::AbstractBeliefPropagationCache, edge::QuotientEdge) + ``` + +* One BP iteration — sequential over a list of edges, or in parallel groups of edges, + with an optional accumulator for per-iteration message diffs (`caches/abstractbeliefpropagationcache.jl`): + ```julia + update_iteration(alg::Algorithm"bp", bpc::AbstractBeliefPropagationCache, edges::Vector; update_diff!) + update_iteration(alg::Algorithm"bp", bpc::AbstractBeliefPropagationCache, edge_groups::Vector{<:Vector{<:QuotientEdge}}; update_diff!) + ``` + +* Drive BP to convergence — either the algorithm-specialized core or the user-facing + dispatcher that fills in `maxiter`, `tol`, and the edge sequence (`caches/abstractbeliefpropagationcache.jl`): + ```julia + update(alg::Algorithm"bp", bpc::AbstractBeliefPropagationCache) + update(bpc::AbstractBeliefPropagationCache; alg, kwargs...) + ``` + +* Rescale messages on a single bond, on the given bonds, or on every bond, so that + `region_scalar` of the bond is 1 (`caches/abstractbeliefpropagationcache.jl`): + ```julia + rescale_messages(bp_cache::AbstractBeliefPropagationCache, quotientedge::QuotientEdge) + rescale_messages(bp_cache::AbstractBeliefPropagationCache, pes) + rescale_messages(bp_cache::AbstractBeliefPropagationCache) + ``` + +* Rescale the vertex tensors inside one partition, a list of partitions, or every + partition, so that the partition's region scalar is 1 (`caches/abstractbeliefpropagationcache.jl`): + ```julia + rescale_partition(bpc::AbstractBeliefPropagationCache, partition, args...; kwargs...) + rescale_partitions(bpc::AbstractBeliefPropagationCache, partitions::Vector; verts) + rescale_partitions(bpc::AbstractBeliefPropagationCache, args...; kwargs...) + ``` + +* Convenience — rescale messages and then partitions in one call (`caches/abstractbeliefpropagationcache.jl`): + ```julia + rescale(bpc::AbstractBeliefPropagationCache, args...; kwargs...) + ``` + +#### BeliefPropagationCache + +* Construct a `BeliefPropagationCache` from an + `AbstractITensorNetwork` plus a partitioning, or just a network (using a default + partition) (`caches/beliefpropagationcache.jl`): + ```julia + BeliefPropagationCache(tn::AbstractITensorNetwork, partitioned_vertices; kwargs...) + BeliefPropagationCache(tn::AbstractITensorNetwork; partitioned_vertices, kwargs...) + # Deprecate this version? + BeliefPropagationCache(ptn::PartitionedGraph; messages = default_messages(ptn)) + ``` + +* Given a tensor network, returns a `BeliefPropagationCache` (`caches/beliefpropagationcache.jl`): + ```julia + cache(alg::Algorithm"bp", tn; kwargs...) + ``` + +* Copy cache and access messages (`caches/beliefpropagationcache.jl`): + ```julia + copy(bp_cache::BeliefPropagationCache) + messages(bp_cache::BeliefPropagationCache) + setindex!(bpc::BeliefPropagationCache, factor::ITensor, vertex) + ``` + +* Partition-graph related queries — list partitions, quotient edges between partitions, and + the vertex-to-partition mapping (`caches/beliefpropagationcache.jl`): + ```julia + partitioned_tensornetwork(bp_cache::BeliefPropagationCache) + partitions(bpc::BeliefPropagationCache) + quotientedges(bpc::BeliefPropagationCache) + partitioned_vertices(bpc::BeliefPropagationCache) + ``` + +* Environment around `verts`: incoming BP messages plus the in-partition tensors not in + `verts`, suitable for local contractions (`caches/beliefpropagationcache.jl`): + ```julia + environment(bpc::BeliefPropagationCache, verts::Vector; kwargs...) + ``` + +* Scalar associated with a region — for a partition vertex it's the local state contracted + with incoming messages; for a partition edge it's the inner product of the two messages + on that bond (`caches/beliefpropagationcache.jl`): + ```julia + region_scalar(bp_cache::BeliefPropagationCache, pv::QuotientVertex) + region_scalar(bp_cache::BeliefPropagationCache, pe::QuotientEdge) + ``` + +* Return a copy of the cache with messages on `pes` rescaled to unit norm and + symmetrized so the bond region scalar is 1 (`caches/beliefpropagationcache.jl`): + ```julia + rescale_messages(bp_cache::BeliefPropagationCache, pes) + ``` + + diff --git a/docs/src/experimental_methods.md b/docs/src/experimental_methods.md new file mode 100644 index 00000000..79457f4d --- /dev/null +++ b/docs/src/experimental_methods.md @@ -0,0 +1,566 @@ +# Experimental Methods + +Methods which still need to be discussed, modified, or deprecated. + +## ITensorNetwork Methods + +* Combine (fuse) every link index of a tensor network, or a chosen set of edges, into + a single index per edge using `combiner` tensors. (`abstractitensornetwork.jl`). + Comment: it may be better to fold this into a more general interface `gauge_transform(f, tn::AbstractITensorNetwork)` that applies a gauge transformation $X\_e$ $X\_e^{-1}$ on each edge $e$. + ```julia + linkinds_combiners(tn::AbstractITensorNetwork; edges = edges(tn)) + combine_linkinds(tn::AbstractITensorNetwork, combiners) + combine_linkinds(tn::AbstractITensorNetwork; edges = edges(tn)) + ``` + +* Extract the `IndsNetwork` of a tensor network — site indices per vertex and link + indices per edge (`abstractitensornetwork.jl`): + ```julia + IndsNetwork(tn::AbstractITensorNetwork) + ``` + +* Collect all site indices (per-vertex) of a network as an `IndsNetwork` (`abstractitensornetwork.jl`): + ```julia + siteinds(tn::AbstractITensorNetwork) + ``` + +* Collect all link indices (per-edge) of a network as an `IndsNetwork` (`abstractitensornetwork.jl`): + ```julia + linkinds(tn::AbstractITensorNetwork) + ``` + +* Rewrite every index of a network according to a structural mapping `IndsNetwork => IndsNetwork` + (site indices per vertex, link indices per edge). The two `IndsNetwork`s must share the + same underlying graph (`abstractitensornetwork.jl`): + ```julia + replaceinds(tn::AbstractITensorNetwork, is_is′::Pair{<:IndsNetwork, <:IndsNetwork}) + ``` + +* "Split" an edge index by applying a map to each copy of it on the adjacent ITensors. + By default the `dst(edge)` copy is primed and the `src(edge)` copy is unchanged (`abstractitensornetwork.jl`): + ```julia + split_index(tn::AbstractITensorNetwork, edges_to_split; + src_ind_map::Function = identity, + dst_ind_map::Function = prime) + ``` + +* Collect all site indices (per-vertex) of a network as a flat vector (`abstractitensornetwork.jl`): + ```julia + flatten_siteinds(tn::AbstractITensorNetwork) + ``` + +* Collect all link indices (per-edge) of a network as a flat vector (`abstractitensornetwork.jl`): + ```julia + flatten_linkinds(tn::AbstractITensorNetwork) + ``` + + +## TreeTensorNetwork Types + +#### OpSum Constructors + +* From an `OpSum`, using `opsum_to_ttn.jl` code: + ```julia + ttn(os::OpSum, sites::IndsNetwork; kws...) + ``` + +* From `OpSum`, assuming path graph (`opsum_to_ttn.jl`): + ```julia + mpo(os::OpSum, external_inds::Vector; kws...) + mpo(os::OpSum, s::IndsNetwork; kws...) + ``` + +#### AbstractTreeTensorNetwork Type + +* Required-to-implement abstract interface — `TreeTensorNetwork` provides all three (`treetensornetworks/abstracttreetensornetwork.jl`): + ```julia + ITensorNetwork(tn::AbstractTTN) + ortho_region(tn::AbstractTTN) + set_ortho_region(tn::AbstractTTN, new_region) + ``` + +* Underlying-graph type forwarded to `data_graph_type` (`treetensornetworks/abstracttreetensornetwork.jl`): + ```julia + underlying_graph_type(G::Type{<:AbstractTTN}) + ``` + +* Gauge `tn` so its orthogonality center sits at `region`. `gauge` does the underlying + tree-traversal QRs; `orthogonalize` is the user-facing wrapper, with `tree_orthogonalize` + as an alias (`treetensornetworks/abstracttreetensornetwork.jl`): + ```julia + gauge(alg::Algorithm, ttn::AbstractTTN, region::Vector; kwargs...) + gauge(alg::Algorithm, ttn::AbstractTTN, region; kwargs...) + orthogonalize(ttn::AbstractTTN, region; kwargs...) + tree_orthogonalize(ttn::AbstractTTN, args...; kwargs...) + ``` + +* Sweep-based truncation. The whole-TTN form orthogonalizes towards `src(e)` before + each bond truncation; the edge form lifts `truncate` from the underlying `ITensorNetwork` (`treetensornetworks/abstracttreetensornetwork.jl`): + ```julia + truncate(tn::AbstractTTN; root_vertex = GraphsExtensions.default_root_vertex(tn), kwargs...) + truncate(tn::AbstractTTN, edge::AbstractEdge; kwargs...) + ``` + +* Contract the whole tree into a single `ITensor` via a reverse post-order DFS sequence (`treetensornetworks/abstracttreetensornetwork.jl`): + ```julia + contract(tn::AbstractTTN, root_vertex = GraphsExtensions.default_root_vertex(tn); kwargs...) + ``` + +* Inner product `⟨x|y⟩`, matrix element `⟨y|A|x⟩`, and four-network form `⟨B|y|A|x⟩`, + each contracted along a post-order DFS rooted at `root_vertex` (`treetensornetworks/abstracttreetensornetwork.jl`): + ```julia + inner(x::AbstractTTN, y::AbstractTTN; root_vertex) + inner(y::AbstractTTN, A::AbstractTTN, x::AbstractTTN; root_vertex) + inner(B::AbstractTTN, y::AbstractTTN, A::AbstractTTN, x::AbstractTTN; root_vertex) + ``` + +* Norm and `log(norm)` — fast paths when the gauge center is a single vertex (`treetensornetworks/abstracttreetensornetwork.jl`): + ```julia + norm(tn::AbstractTTN) + lognorm(tn::AbstractTTN) + ``` + +* In-place and out-of-place normalization, distributing the norm across the gauge + center (`treetensornetworks/abstracttreetensornetwork.jl`): + ```julia + normalize!(tn::AbstractTTN) + normalize(tn::AbstractTTN) + ``` + +* Numerically-stable `log(⟨tn1|tn2⟩)` along a post-order DFS, accumulating per-step + log-norms; `logdot` is an alias (`treetensornetworks/abstracttreetensornetwork.jl`): + ```julia + loginner(tn1::AbstractTTN, tn2::AbstractTTN; root_vertex) + logdot(tn1::AbstractTTN, tn2::AbstractTTN; kwargs...) + ``` + +* Scalar arithmetic — multiplies/divides the gauge-center tensor by `α`, with `rmul!` + as the in-place form (`treetensornetworks/abstracttreetensornetwork.jl`): + ```julia + *(tn::AbstractTTN, α::Number) + *(α::Number, tn::AbstractTTN) + /(tn::AbstractTTN, α::Number) + -(tn::AbstractTTN) + rmul!(tn::AbstractTTN, α::Number) + ``` + +* Add (or subtract) tree tensor networks by direct-summing bond indices. The result's + bond dimension is the sum of the inputs'; the `Algorithm"directsum"` form is the + current implementation. Use `truncate` afterward to compress (`treetensornetworks/abstracttreetensornetwork.jl`): + ```julia + +(::Algorithm"directsum", tns::AbstractTTN...; root_vertex) + +(tns::AbstractTTN...; alg = Algorithm"directsum"(), kwargs...) + +(tn::AbstractTTN) + -(tn1::AbstractTTN, tn2::AbstractTTN; kwargs...) + add(tns::AbstractTTN...; kwargs...) + add(tn1::AbstractTTN, tn2::AbstractTTN; kwargs...) + ``` + +* Approximate equality via `norm(x - y) ≤ max(atol, rtol * max(norm(x), norm(y)))` (`treetensornetworks/abstracttreetensornetwork.jl`): + ```julia + isapprox(x::AbstractTTN, y::AbstractTTN; atol, rtol) + ``` + +* Local expectation values for a named operator at the given vertices (default all + vertices), evaluated by successive orthogonalization (`treetensornetworks/abstracttreetensornetwork.jl`): + ```julia + expect(operator::String, state::AbstractTTN; vertices, root_vertex) + ``` + +#### TreeTensorNetwork Type + +* Get the underlying `ITensorNetwork` of a `TTN` (drops orthogonality metadata) (`treetensornetworks/treetensornetwork.jl`): + ```julia + ITensorNetwork(tn::TTN) + ``` + +* Get the current orthogonality region — the set of vertices forming the gauge center (`treetensornetworks/treetensornetwork.jl`): + ```julia + ortho_region(tn::TTN) + ``` + +* `AbstractITensorNetwork` interface, forwarded to the wrapped `ITensorNetwork` (`treetensornetworks/treetensornetwork.jl`): + ```julia + data_graph(tn::TTN) + data_graph_type(G::Type{<:TTN}) + copy(tn::TTN) + ``` + +* Low-level `ortho_region` update — only changes the metadata, performs no gauge + transformations (use `orthogonalize` to actually move the gauge center) (`treetensornetworks/treetensornetwork.jl`): + ```julia + set_ortho_region(tn::TTN, ortho_region) + ``` + +## IndsNetwork Type and Methods + +#### Site Index Helpers + +* Build an `IndsNetwork` of site indices on `g` from a value `x` — site-type string, + dimension, `Index`, or per-vertex dictionary (`sitetype.jl`): + ```julia + siteinds(x, g::AbstractGraph; kwargs...) + ``` + +* Same, on a length-`nv` path graph (`sitetype.jl`): + ```julia + siteinds(x, nv::Int; kwargs...) + ``` + +* Build an `IndsNetwork` by calling `f(v)` at each vertex (`sitetype.jl`): + ```julia + siteinds(f::Function, g::AbstractGraph; kwargs...) + ``` + +#### AbstractIndsNetwork + +* Required-to-implement abstract interface — concrete subtypes must define + `data_graph`; `is_directed` defaults to `false` and may be overloaded (`abstractindsnetwork.jl`): + ```julia + data_graph(graph::AbstractIndsNetwork) + is_directed(::Type{<:AbstractIndsNetwork}) + ``` + +* Vertex/edge data forwarded from the underlying `DataGraph`, plus the eltype + declaration `Vector{I}` (`abstractindsnetwork.jl`): + ```julia + vertex_data(graph::AbstractIndsNetwork, args...) + edge_data(graph::AbstractIndsNetwork, args...) + edge_data_eltype(::Type{<:AbstractIndsNetwork{V, I}}) where {V, I} + ``` + +* Indices "unique" to one side of an edge — for `edge`, returns the indices on + `src(edge)` together with all of its other incident-edge link indices (`abstractindsnetwork.jl`): + ```julia + uniqueinds(is::AbstractIndsNetwork, edge::AbstractEdge) + uniqueinds(is::AbstractIndsNetwork, edge::Pair) + ``` + +* Merge two `AbstractIndsNetwork`s, returning an `IndsNetwork` over the merged graph (`abstractindsnetwork.jl`): + ```julia + union(is1::AbstractIndsNetwork, is2::AbstractIndsNetwork; kwargs...) + ``` + +* Rename every vertex `v` to `f(v)` (`abstractindsnetwork.jl`): + ```julia + rename_vertices(f::Function, tn::AbstractIndsNetwork) + ``` + +* Promoted index type across all site and link indices in the network (`abstractindsnetwork.jl`): + ```julia + promote_indtypeof(is::AbstractIndsNetwork) + ``` + +* Build an `IndsNetwork` whose site/link indices at each vertex/edge are the union + of the corresponding indices from each input network (graphs must match) (`abstractindsnetwork.jl`): + ```julia + union_all_inds(is_in::AbstractIndsNetwork...) + ``` + +* Insert a default link index on every edge of `indsnetwork` that doesn't already + have one — `link_space` controls the default bond dimension (`abstractindsnetwork.jl`): + ```julia + insert_linkinds(indsnetwork::AbstractIndsNetwork, edges = edges(indsnetwork); link_space = trivial_space(indsnetwork)) + ``` + +#### IndsNetwork + +* Type-parameter accessors and graph-type metadata (`indsnetwork.jl`): + ```julia + indtype(inds_network::IndsNetwork) + indtype(::Type{<:IndsNetwork{V, I}}) where {V, I} + data_graph(is::IndsNetwork) + underlying_graph(is::IndsNetwork) + vertextype(::Type{<:IndsNetwork{V}}) where {V} + underlying_graph_type(G::Type{<:IndsNetwork}) + is_directed(::Type{<:IndsNetwork}) + ``` + +* Construct an `IndsNetwork` from a pre-built `DataGraph` (`indsnetwork.jl`): + ```julia + IndsNetwork{V, I}(data_graph::DataGraph) + IndsNetwork{V}(data_graph::DataGraph) + IndsNetwork(data_graph::DataGraph) + ``` + +* Construct from an underlying graph plus link- and site-space specs (positional + or as `link_space` / `site_space` kwargs). Each spec may be an integer, a `Vector{Int}`, + an `Index`, a `Vector{<:Index}`, or a per-edge / per-vertex `Dictionary` of any of + those. `nothing` leaves it empty (`indsnetwork.jl`): + ```julia + IndsNetwork{V, I}(g::AbstractNamedGraph, link_space, site_space) + IndsNetwork{V, I}(g::AbstractSimpleGraph, link_space, site_space) + IndsNetwork{V}(g, link_space, site_space) + IndsNetwork(g, link_space, site_space) + IndsNetwork{V, I}(g; link_space, site_space) + IndsNetwork{V}(g; link_space, site_space) + IndsNetwork(g; kwargs...) + ``` + +* Core constructor — takes pre-built `Dictionary` link- and site-space maps and + populates the underlying `DataGraph` directly (`indsnetwork.jl`): + ```julia + IndsNetwork{V, I}(g::AbstractNamedGraph, link_space::Dictionary, site_space::Dictionary) + IndsNetwork{V, I}(g::AbstractSimpleGraph, link_space::Dictionary, site_space::Dictionary) + ``` + +* Build an `IndsNetwork` on a path graph from a vector of external (site) indices + per vertex, or one index per vertex (`indsnetwork.jl`): + ```julia + path_indsnetwork(external_inds::Vector{<:Vector{<:Index}}) + path_indsnetwork(external_inds::Vector{<:Index}) + ``` + +* Normalize a user-supplied link-space spec into a `Dictionary{edgetype, Vector{I}}`, + building fresh edge-tagged `Index` objects from raw integer dimensions when needed. + Accepts an integer, a `Vector{Int}`, a `Dictionary` of integers / vectors of integers / + `Index` / `Vector{<:Index}`, or `nothing` (`indsnetwork.jl`): + ```julia + link_space_map(V::Type, I::Type{<:Index}, g, link_space) + ``` + +* Same for site spaces, normalizing into `Dictionary{V, Vector{I}}` (`indsnetwork.jl`): + ```julia + site_space_map(V::Type, I::Type{<:Index}, g, site_space) + ``` + +* Copy an `IndsNetwork` (deep-copies the underlying `DataGraph`) (`indsnetwork.jl`): + ```julia + copy(is::IndsNetwork) + ``` + +* Apply an index-label transformation `f` to every site index (`sites` kwarg) and/or + link index (`links` kwarg) of the network (`indsnetwork.jl`): + ```julia + map_inds(f, is::IndsNetwork, args...; sites = nothing, links = nothing, kwargs...) + ``` + +* Visualize an `IndsNetwork` by wrapping it in a default `ITensorNetwork` (`indsnetwork.jl`): + ```julia + visualize(is::IndsNetwork, args...; kwargs...) + ``` + + +## ProjTTN System + +#### AbstractProjTTN + +* Required-to-implement abstract interface — each concrete `AbstractProjTTN` subtype + defines these (`treetensornetworks/projttns/abstractprojttn.jl`): + ```julia + environments(::AbstractProjTTN) + operator(::AbstractProjTTN) + pos(::AbstractProjTTN) + underlying_graph(P::AbstractProjTTN) + copy(::AbstractProjTTN) + set_nsite(::AbstractProjTTN, nsite) + shift_position(::AbstractProjTTN, pos) + set_environments(p::AbstractProjTTN, environments) + set_environment(p::AbstractProjTTN, edge, environment) + make_environment!(P::AbstractProjTTN, psi, e) + make_environment(P::AbstractProjTTN, psi, e) + projected_operator_tensors(P::AbstractProjTTN) + ``` + +* Position queries — whether the projection currently sits on an edge, the number + and list of "sites" of the projection, and the corresponding incident / internal + edges of the underlying graph (`treetensornetworks/projttns/abstractprojttn.jl`): + ```julia + edgetype(P::AbstractProjTTN) + on_edge(P::AbstractProjTTN) + nsite(P::AbstractProjTTN) + sites(P::AbstractProjTTN) + incident_edges(P::AbstractProjTTN) + internal_edges(P::AbstractProjTTN) + ``` + +* Look up a single environment tensor by edge (`treetensornetworks/projttns/abstractprojttn.jl`): + ```julia + environment(P::AbstractProjTTN, edge::AbstractEdge) + environment(P::AbstractProjTTN, edge::Pair) + ``` + +* Apply the projection to a vector — `contract(P, v)` does this in a literal way; + `product(P, v)` adds a `noprime` and an order check; + `(P)(v)` is the callable form (`treetensornetworks/projttns/abstractprojttn.jl`): + ```julia + contract(P::AbstractProjTTN, v::ITensor) + product(P::AbstractProjTTN, v::ITensor) + (P::AbstractProjTTN)(v::ITensor) + ``` + +* Eltype / vertextype / dim queries — `size` returns `(d, d)` from primed indices + on environments and operator tensors (`treetensornetworks/projttns/abstractprojttn.jl`): + ```julia + eltype(P::AbstractProjTTN) + vertextype(::Type{<:AbstractProjTTN{V}}) where {V} + vertextype(p::AbstractProjTTN) + size(P::AbstractProjTTN) + ``` + +* Move the projection to a new `pos`: shifts position, drops now-internal-edge + environments, and rebuilds the missing ones from `psi` (`treetensornetworks/projttns/abstractprojttn.jl`): + ```julia + position(P::AbstractProjTTN, psi::AbstractTTN, pos) + ``` + +* Drop one or all internal-edge environments after a position change, and rebuild + every incident-edge environment from `psi` (`treetensornetworks/projttns/abstractprojttn.jl`): + ```julia + invalidate_environment(P::AbstractProjTTN, e::AbstractEdge) + invalidate_environments(P::AbstractProjTTN) + make_environments(P::AbstractProjTTN, psi::AbstractTTN) + ``` + +#### ProjTTN + +* Construct a `ProjTTN` from an operator `TTN`. The two-argument form lets you specify + position and pre-built environments; the one-argument form starts with empty + environments and `pos = vertices(operator)` (`treetensornetworks/projttns/projttn.jl`): + ```julia + ProjTTN(pos, operator::TTN, environments::Dictionary) + ProjTTN(operator::TTN) + ``` + +* Field accessors and `copy` (`treetensornetworks/projttns/projttn.jl`): + ```julia + environments(p::ProjTTN) + operator(p::ProjTTN) + underlying_graph(P::ProjTTN) + pos(P::ProjTTN) + copy(P::ProjTTN) + ``` + +* Position-management interface (`set_nsite` is a no-op for trees) (`treetensornetworks/projttns/projttn.jl`): + ```julia + set_nsite(P::ProjTTN, nsite) + shift_position(P::ProjTTN, pos) + ``` + +* Environment dictionary updates — out-of-place `set_environment` returns a copy + with the bond's environment replaced; `set_environment!` is the in-place form (`treetensornetworks/projttns/projttn.jl`): + ```julia + set_environments(p::ProjTTN, environments) + set_environment(p::ProjTTN, edge, env) + set_environment!(p::ProjTTN, edge, env) + ``` + +* Build the environment on edge `e` from `state` (`treetensornetworks/projttns/projttn.jl`): + ```julia + make_environment(P::ProjTTN, state::AbstractTTN, e::AbstractEdge) + ``` + +* Assemble the ITensor list that defines the projection: incident-edge environments + plus operator tensors at each site (`treetensornetworks/projttns/projttn.jl`): + ```julia + projected_operator_tensors(P::ProjTTN) + ``` + +#### ProjTTNSum + +* Construct a weighted sum of `AbstractProjTTN` terms, or a sum of `AbstractTTN` + operators (which are wrapped via `ProjTTN.(operators)`). The two-argument form lets + you specify per-term scalar factors (`treetensornetworks/projttns/projttnsum.jl`): + ```julia + ProjTTNSum(terms::Vector{<:AbstractProjTTN}, factors::Vector{<:Number}) + ProjTTNSum(operators::Vector{<:AbstractProjTTN}) + ProjTTNSum(operators::Vector{<:AbstractTTN}) + ``` + +* Field accessors and `copy` (`treetensornetworks/projttns/projttnsum.jl`): + ```julia + terms(P::ProjTTNSum) + factors(P::ProjTTNSum) + copy(P::ProjTTNSum) + ``` + +* Position queries forwarded to the first term (`treetensornetworks/projttns/projttnsum.jl`): + ```julia + on_edge(P::ProjTTNSum) + nsite(P::ProjTTNSum) + underlying_graph(P::ProjTTNSum) + length(P::ProjTTNSum) + sites(P::ProjTTNSum) + incident_edges(P::ProjTTNSum) + internal_edges(P::ProjTTNSum) + ``` + +* Update the position parameter on every term while preserving the factors (`treetensornetworks/projttns/projttnsum.jl`): + ```julia + set_nsite(Ps::ProjTTNSum, nsite) + ``` + +* Apply the sum to a vector — `contract` builds `Σ fᵢ·contract(termᵢ, v)`, + `product` adds the standard `noprime`, and `(P)(v)` is the callable form (`treetensornetworks/projttns/projttnsum.jl`): + ```julia + contract(P::ProjTTNSum, v::ITensor) + product(P::ProjTTNSum, v::ITensor) + (P::ProjTTNSum)(v::ITensor) + ``` + +* Apply the sum without the bra side, used by ket-only projections like outer products (`treetensornetworks/projttns/projttnsum.jl`): + ```julia + contract_ket(P::ProjTTNSum, v::ITensor) + ``` + +* Element type (promoted across terms) and `size` (taken from the first term) (`treetensornetworks/projttns/projttnsum.jl`): + ```julia + eltype(P::ProjTTNSum) + size(P::ProjTTNSum) + ``` + +* Move every term to a new `pos`, returning a fresh `ProjTTNSum` (`treetensornetworks/projttns/projttnsum.jl`): + ```julia + position(P::ProjTTNSum, psi::AbstractTTN, pos) + ``` + +#### ProjOuterProdTTN + +* Construct a `ProjOuterProdTTN` from an internal-state `TTN` and an operator `TTN`, + starting at empty position with empty environments (`treetensornetworks/projttns/projouterprodttn.jl`): + ```julia + ProjOuterProdTTN(internal_state::AbstractTTN, operator::AbstractTTN) + ``` + +* Field accessors and `copy` (`treetensornetworks/projttns/projouterprodttn.jl`): + ```julia + environments(p::ProjOuterProdTTN) + operator(p::ProjOuterProdTTN) + underlying_graph(p::ProjOuterProdTTN) + pos(p::ProjOuterProdTTN) + internal_state(p::ProjOuterProdTTN) + copy(P::ProjOuterProdTTN) + ``` + +* Position-management interface (`set_nsite` is a no-op) (`treetensornetworks/projttns/projouterprodttn.jl`): + ```julia + set_nsite(P::ProjOuterProdTTN, nsite) + shift_position(P::ProjOuterProdTTN, pos) + ``` + +* Environment dictionary updates — same pattern as `ProjTTN` (`treetensornetworks/projttns/projouterprodttn.jl`): + ```julia + set_environments(p::ProjOuterProdTTN, environments) + set_environment(p::ProjOuterProdTTN, edge, env) + set_environment!(p::ProjOuterProdTTN, edge, env) + ``` + +* Build the environment on edge `e` from `state` — like `ProjTTN`'s version but + uses the unprimed `internal_state` instead of priming `state` (`treetensornetworks/projttns/projouterprodttn.jl`): + ```julia + make_environment(P::ProjOuterProdTTN, state::AbstractTTN, e::AbstractEdge) + ``` + +* Assemble the ITensor list that defines the projection — interleaves + `internal_state`, operator, and environment tensors (`treetensornetworks/projttns/projouterprodttn.jl`): + ```julia + projected_operator_tensors(P::ProjOuterProdTTN) + ``` + +* Apply the operator-with-internal-state combination to a vector. `contract_ket` + performs the half-contraction with `internal_state`; `contract` returns + `(dag(ket) · x) · ket` for outer-product evaluation (`treetensornetworks/projttns/projouterprodttn.jl`): + ```julia + contract_ket(P::ProjOuterProdTTN, v::ITensor) + contract(P::ProjOuterProdTTN, x::ITensor) + ``` diff --git a/docs/src/interface_methods.md b/docs/src/interface_methods.md new file mode 100644 index 00000000..c0e40c0e --- /dev/null +++ b/docs/src/interface_methods.md @@ -0,0 +1,325 @@ +# Interface Methods + +Recommended methods for building applications on top of ITensorNetworks. + +## ITensorNetwork Constructors + +These ITensorNetwork constructor interfaces are foundational to other constructors: + +* From dictionary-like objects, including other `ITensorNetwork` objects, or a `Dict` + from vertices to `ITensor`. The `tensors` can be a collection of `ITensor`s in which case + the vertex labels are auto-assigned to `eachindex(tensors)` and edges are inferred + from shared indices between the `ITensor`s. + ```julia + # `keys(tensors)` are vertices, `values(tensors)` are tensors on those vertices + ITensorNetwork(tensors) + ITensorNetwork{V}(tensors) + ``` + +* From collections of vertices and tensors. E.g. a `Vector{Int}` and a `Vector{ITensor}`. + ```julia + ITensorNetwork(vertices, tensors) + ITensorNetwork{V}(vertices, tensors) + ``` + + +## Analyzing ITensorNetworks + + +* Tags on the link index (or indices) associated with `edge` (`abstractitensornetwork.jl`): + ```julia + tags(tn::AbstractITensorNetwork, edge) + ``` + +* Bond dimension of a single edge, of every edge (as a `DataGraph`), and the maximum + bond dimension over all edges (`abstractitensornetwork.jl`): + ```julia + linkdim(tn::AbstractITensorNetwork{V}, edge::AbstractEdge{V}) where {V} + linkdims(tn::AbstractITensorNetwork{V}) where {V} + maxlinkdim(tn::AbstractITensorNetwork) + ``` + +## Local Operations on ITensorNetworks + +* Contract the tensors at vertices `src(edge)` and `dst(edge)` and store the result in + `merged_vertex` (which defaults to `dst(edge)`), removing the other vertex (defaults to `src(edge)`) (`abstractitensornetwork.jl`): + ```julia + contract(tn::AbstractITensorNetwork, edge::AbstractEdge; merged_vertex = dst(edge)) + contract(tn::AbstractITensorNetwork, edge::Pair; kws...) + ``` + +* Factorize the bond on `edge` using the default factorization (`abstractitensornetwork.jl`): + ```julia + factorize(tn::AbstractITensorNetwork, edge::AbstractEdge; kws...) + factorize(tn::AbstractITensorNetwork, edge::Pair; kws...) + ``` + +* QR-factorize across `edge`, placing the orthogonal factor on `src(edge)` and the remainder + on `dst(edge)` (`abstractitensornetwork.jl`): + ```julia + qr(tn::AbstractITensorNetwork, edge::AbstractEdge; kws...) + ``` + +* SVD-factorize across `edge` (`abstractitensornetwork.jl`): + ```julia + svd(tn::AbstractITensorNetwork, edge::AbstractEdge; kws...) + ``` + +* Truncate the bond on `edge` via SVD; forwards `cutoff`, `maxdim`, `mindim` kwargs (`abstractitensornetwork.jl`): + ```julia + truncate(tn::AbstractITensorNetwork, edge::AbstractEdge; kws...) + ``` + +## Global Operations on ITensorNetworks + +* Scale tensors at chosen vertices by per-vertex weights, either out-of-place or in-place (`abstractitensornetwork.jl`). Comment: should probably be renamed to `scale_tensors`. + ```julia + scale(tn::AbstractITensorNetwork, vertices_weights::Dictionary; kwargs...) + scale(weight_function::Function, tn; kwargs...) + scale!(tn::AbstractITensorNetwork, vertices_weights::Dictionary) + scale!(weight_function::Function, tn::AbstractITensorNetwork; kwargs...) + ``` + +* Tensor product (disjoint union) of two ITensorNetworks (`abstractitensornetwork.jl`): + ```julia + ⊗(tn1::AbstractITensorNetwork, tn2::AbstractITensorNetwork) + union(tn1::AbstractITensorNetwork, tn2::AbstractITensorNetwork; kwargs...) + ``` + +* Contract every tensor in the network into a single `ITensor`. Default `alg = "exact"` + contracts via a contraction sequence (built from the network if not given) (`contract.jl`): + ```julia + contract(tn::AbstractITensorNetwork; alg, kwargs...) + contract(alg::Algorithm"exact", tn::AbstractITensorNetwork; sequence, contraction_sequence_kwargs, kwargs...) + ``` + +* Scalar value of a fully-contracted network. The `Algorithm"exact"` form contracts and + unwraps; the generic `Algorithm` form goes through `logscalar`/`exp` for stability (`contract.jl`): + ```julia + scalar(tn::AbstractITensorNetwork; alg, kwargs...) + scalar(alg::Algorithm"exact", tn::AbstractITensorNetwork; kwargs...) + scalar(alg::Algorithm, tn::AbstractITensorNetwork; kwargs...) + ``` + +* `log` of the network scalar. The `Algorithm"exact"` form contracts and takes a log + (promoting to complex when negative); the generic `Algorithm` form goes through a + cache (e.g. BP) using `cache!` / `update_cache` (`contract.jl`): + ```julia + logscalar(tn::AbstractITensorNetwork; alg, kwargs...) + logscalar(alg::Algorithm"exact", tn::AbstractITensorNetwork; kwargs...) + logscalar(alg::Algorithm, tn::AbstractITensorNetwork; cache!, update_cache, kwargs...) + ``` + +* Obtain contraction sequence for a tensor network (`contraction_sequences.jl`). + Can offer different backends through package extensions. + ```julia + contraction_sequence(tn::ITensorList; alg = "optimal", kwargs...) + contraction_sequence(alg::Algorithm, tn::ITensorList) + contraction_sequence(tn::AbstractITensorNetwork; kwargs...) + ``` + +* Elementwise complex conjugation of every tensor in the network (`abstractitensornetwork.jl`): + ```julia + conj(tn::AbstractITensorNetwork) + ``` + +* Dagger: conjugate every tensor and prime the appropriate indices (`abstractitensornetwork.jl`): + ```julia + dag(tn::AbstractITensorNetwork) + ``` + +* Approximate equality of two ITensorNetworks (`abstractitensornetwork.jl`): + ```julia + isapprox(tn1::AbstractITensorNetwork, tn2::AbstractITensorNetwork; kws...) + ``` + +* Multiply every-vertex tensors by a scalar, multiplied into the first vertex (`abstractitensornetwork.jl`): + ```julia + *(c::Number, ψ::AbstractITensorNetwork) + ``` + +* Add two ITensorNetworks defined over the same graph; result has summed bond dimensions (`abstractitensornetwork.jl`): + ```julia + +(tn1::AbstractITensorNetwork, tn2::AbstractITensorNetwork) + add(tn1::AbstractITensorNetwork, tn2::AbstractITensorNetwork) + ``` + +* Adjoint: prime all indices of the network (`abstractitensornetwork.jl`): + ```julia + adjoint(tn::AbstractITensorNetwork) + ``` + +* Rename every vertex `v` of `tn` to `f(v)` (`abstractitensornetwork.jl`): + ```julia + rename_vertices(f::Function, tn::AbstractITensorNetwork) + ``` + +* Element-type queries and conversions over the whole network (`abstractitensornetwork.jl`): + ```julia + scalartype(tn::AbstractITensorNetwork) + convert_scalartype(eltype::Type{<:Number}, tn::AbstractITensorNetwork) + complex(tn::AbstractITensorNetwork) + ``` + +* Inner product `⟨ϕ|ψ⟩`. Default `alg = "bp"`; `"exact"` builds the bra-ket network and contracts via a sequence (`inner.jl`): + ```julia + inner(ϕ::AbstractITensorNetwork, ψ::AbstractITensorNetwork; alg, kwargs...) + inner(alg::Algorithm, ϕ::AbstractITensorNetwork, ψ::AbstractITensorNetwork; kwargs...) + inner(alg::Algorithm"exact", ϕ::AbstractITensorNetwork, ψ::AbstractITensorNetwork; sequence, kwargs...) + ``` + +* Matrix element `⟨ϕ|A|ψ⟩` for an operator network `A` (`inner.jl`): + ```julia + inner(ϕ::AbstractITensorNetwork, A::AbstractITensorNetwork, ψ::AbstractITensorNetwork; alg, kwargs...) + inner(alg::Algorithm, ϕ::AbstractITensorNetwork, A::AbstractITensorNetwork, ψ::AbstractITensorNetwork; kwargs...) + inner(alg::Algorithm"exact", ϕ::AbstractITensorNetwork, A::AbstractITensorNetwork, ψ::AbstractITensorNetwork; sequence, kwargs...) + ``` + +* Numerically-stable `log(⟨ϕ|ψ⟩)` and `log(⟨ϕ|A|ψ⟩)` (`inner.jl`): + ```julia + loginner(ϕ::AbstractITensorNetwork, ψ::AbstractITensorNetwork; alg, kwargs...) + loginner(ϕ::AbstractITensorNetwork, A::AbstractITensorNetwork, ψ::AbstractITensorNetwork; alg, kwargs...) + loginner(alg::Algorithm, ϕ::AbstractITensorNetwork, ψ::AbstractITensorNetwork; kwargs...) + loginner(alg::Algorithm, ϕ::AbstractITensorNetwork, A::AbstractITensorNetwork, ψ::AbstractITensorNetwork; kwargs...) + loginner(alg::Algorithm"exact", ϕ::AbstractITensorNetwork, ψ::AbstractITensorNetwork; kwargs...) + loginner(alg::Algorithm"exact", ϕ::AbstractITensorNetwork, A::AbstractITensorNetwork, ψ::AbstractITensorNetwork; kwargs...) + ``` + +* Squared norm `⟨ψ|ψ⟩` and norm `√|⟨ψ|ψ⟩|` (`inner.jl`): + ```julia + norm_sqr(ψ::AbstractITensorNetwork; kwargs...) + norm(ψ::AbstractITensorNetwork; kwargs...) + ``` + +* Expectation value `⟨ψ|op|ψ⟩ / ⟨ψ|ψ⟩` for a single `Op` (`expect.jl`): + ```julia + expect(ψ::AbstractITensorNetwork, op::Op; alg, kwargs...) + ``` + +* Local expectation values for the named operator `op` at the given vertices, or at every + vertex of `ψ`. Returns a `Dictionary` mapping vertex to expectation value (`expect.jl`): + ```julia + expect(ψ::AbstractITensorNetwork, op::String, vertices; alg, kwargs...) + expect(ψ::AbstractITensorNetwork, op::String; alg, kwargs...) + ``` + +* Algorithm-specialized dispatches that build a `QuadraticFormNetwork` and either + share/update a BP cache or contract exactly (`expect.jl`): + ```julia + expect(alg::Algorithm, ψ::AbstractITensorNetwork, ops; cache!, update_cache, kwargs...) + expect(alg::Algorithm"exact", ψ::AbstractITensorNetwork, ops; kwargs...) + ``` + +* Single-op evaluator on a pre-built form network, used by the dispatches above (`expect.jl`): + ```julia + expect(ψIψ::AbstractFormNetwork, op::Op; kwargs...) + ``` + +* Return a copy of `tn` rescaled so that `norm(tn) ≈ 1`, with the rescaling distributed + evenly across all vertex tensors (`normalize.jl`): + ```julia + normalize(tn::AbstractITensorNetwork; alg, kwargs...) + ``` + +* Algorithm-specialized dispatches: `"exact"` contracts `⟨ψ|ψ⟩` directly; the generic + `Algorithm` form uses a cached contraction (e.g. BP) on the inner-product network (`normalize.jl`): + ```julia + normalize(alg::Algorithm"exact", tn::AbstractITensorNetwork; kwargs...) + normalize(alg::Algorithm, tn::AbstractITensorNetwork; cache!, update_cache, kwargs...) + ``` + +* Tensors making up the environment of `vertices` in `tn`. Default `alg = "bp"` (`environment.jl`): + ```julia + environment(tn::AbstractITensorNetwork, vertices::Vector; alg, kwargs...) + ``` + +* Algorithm-specialized dispatches: `"exact"` returns the single ITensor obtained by + contracting all other vertices; the generic `Algorithm` form partitions the network + (or accepts a `PartitionedGraph`) and pulls the environment from a BP-style cache (`environment.jl`): + ```julia + environment(::Algorithm"exact", tn::AbstractITensorNetwork, verts::Vector; kwargs...) + environment(alg::Algorithm, tn::AbstractITensorNetwork, vertices::Vector; partitioned_vertices, kwargs...) + environment(alg::Algorithm, ptn::PartitionedGraph, vertices::Vector; cache!, update_cache, kwargs...) + ``` + +## Index Manipulation + +* Apply an index-label transformation `f` to every index in the network. Used to implement + the prime/tag family below (`abstractitensornetwork.jl`): + ```julia + map_inds(f, tn::AbstractITensorNetwork, args...; kwargs...) + ``` + +* Prime/tag family — apply the corresponding ITensors index-label operation to every + index of the network (`abstractitensornetwork.jl`): + ```julia + prime(tn::AbstractITensorNetwork, args...; kwargs...) + setprime(tn::AbstractITensorNetwork, args...; kwargs...) + noprime(tn::AbstractITensorNetwork, args...; kwargs...) + replaceprime(tn::AbstractITensorNetwork, args...; kwargs...) + swapprime(tn::AbstractITensorNetwork, args...; kwargs...) + addtags(tn::AbstractITensorNetwork, args...; kwargs...) + removetags(tn::AbstractITensorNetwork, args...; kwargs...) + replacetags(tn::AbstractITensorNetwork, args...; kwargs...) + settags(tn::AbstractITensorNetwork, args...; kwargs...) + swaptags(tn::AbstractITensorNetwork, args...; kwargs...) + sim(tn::AbstractITensorNetwork, args...; kwargs...) + ``` + +## TEBD and Apply Algorithms + +* Run TEBD given a set of Hamiltonian terms (`tebd.jl`): + ```julia + tebd( + ℋ::Sum, + ψ::AbstractITensorNetwork; + β, + Δβ, + maxdim, + cutoff, + print_frequency = 10, + ortho = false, + kwargs... + ) + ``` + +* Apply a set of gates to an ITensorNetwork (`apply.jl`): + ```julia + ITensors.apply(o::Union{NamedEdge, ITensor},ψ::AbstractITensorNetwork; kws...) + ITensors.apply(o⃗::Union{Vector{NamedEdge}, Vector{ITensor}}, ψ::AbstractITensorNetwork; kws...) + ITensors.apply(o⃗::Scaled,ψ::AbstractITensorNetwork; kws...) + ITensors.apply(o⃗::Prod, ψ::AbstractITensorNetwork; kws...) + ITensors.apply(o::Op, ψ::AbstractITensorNetwork; kws...) + ``` + +## Visualization System + +* Visualization of an ITensorNetwork via `ITensorVisualizationCore` (`abstractitensornetwork.jl`): + ```julia + visualize(tn::AbstractITensorNetwork, args...; kwargs...) + ``` + + +## Solvers System + +* Find the lowest eigenvalue / eigenvector of `operator` via a DMRG-style sweep on a + `TreeTensorNetwork`. `dmrg` is an alias for `eigsolve` (`solvers/eigsolve.jl`): + ```julia + eigsolve(operator, init_state; nsweeps, nsites = 1, factorize_kwargs, sweep_callback, sweep_kwargs...) + dmrg(operator, init_state; kwargs...) + ``` + +* Apply `exp(exponents[i])·operator` to `init_state` along a sequence of exponent + values, using a sweep-based local solver (Runge–Kutta by default). The + pre-built-problem form lets a caller drive `applyexp` from a custom `AbstractProblem` (`solvers/applyexp.jl`): + ```julia + applyexp(operator, exponents, init_state; sweep_callback, order, nsites, sweep_kwargs...) + applyexp(init_prob::AbstractProblem, exponents; sweep_callback, order, nsites, sweep_kwargs...) + ``` + +* Time-evolve `init_state` under `operator` using TDVP — wraps `applyexp` with + `exponents = -im .* time_points`. Supports real and complex `time_points` (`solvers/applyexp.jl`): + ```julia + time_evolve(operator, time_points, init_state; sweep_kwargs...) + ``` +