From ab20e9b5dfb3195c16ce64083c6de35cd266fe7b Mon Sep 17 00:00:00 2001 From: Michael Weinold <23102087+michaelweinold@users.noreply.github.com> Date: Thu, 2 May 2024 12:38:05 +0200 Subject: [PATCH 1/2] major changes --- .readthedocs.yaml | 4 +- CHANGES.md | 2 +- README.md | 15 +- bw_graph_tools/graph_traversal.py | 4 +- docs/conf.py | 44 +- .../api/bw_graph_tools/errors/index.rst | 19 + .../bw_graph_tools/graph_traversal/index.rst | 464 ++++++++++++++++++ .../graph_traversal_utils/index.rst | 45 ++ docs/content/api/bw_graph_tools/index.rst | 67 +++ .../api/bw_graph_tools/matrix_tools/index.rst | 86 ++++ .../bw_graph_tools/shortest_path/index.rst | 127 +++++ .../api/bw_graph_tools/testing/index.rst | 34 ++ .../api/bw_graph_tools/utils/index.rst | 22 + docs/content/api/index.rst | 11 + docs/{pages => content}/changelog.md | 0 docs/{pages => content}/codeofconduct.md | 0 docs/{pages => content}/contributing.md | 0 docs/{pages => content}/license.md | 0 docs/content/usage.md | 18 + docs/environment.yaml | 20 + docs/environment.yml | 15 - docs/index.md | 32 +- docs/pages/usage.md | 7 - 23 files changed, 968 insertions(+), 68 deletions(-) create mode 100644 docs/content/api/bw_graph_tools/errors/index.rst create mode 100644 docs/content/api/bw_graph_tools/graph_traversal/index.rst create mode 100644 docs/content/api/bw_graph_tools/graph_traversal_utils/index.rst create mode 100644 docs/content/api/bw_graph_tools/index.rst create mode 100644 docs/content/api/bw_graph_tools/matrix_tools/index.rst create mode 100644 docs/content/api/bw_graph_tools/shortest_path/index.rst create mode 100644 docs/content/api/bw_graph_tools/testing/index.rst create mode 100644 docs/content/api/bw_graph_tools/utils/index.rst create mode 100644 docs/content/api/index.rst rename docs/{pages => content}/changelog.md (100%) rename docs/{pages => content}/codeofconduct.md (100%) rename docs/{pages => content}/contributing.md (100%) rename docs/{pages => content}/license.md (100%) create mode 100644 docs/content/usage.md create mode 100644 docs/environment.yaml delete mode 100644 docs/environment.yml delete mode 100644 docs/pages/usage.md diff --git a/.readthedocs.yaml b/.readthedocs.yaml index 7c61239..898df34 100644 --- a/.readthedocs.yaml +++ b/.readthedocs.yaml @@ -15,6 +15,6 @@ submodules: include: all build: - os: ubuntu-22.04 # https://docs.readthedocs.io/en/stable/config-file/v2.html#build-os + os: "ubuntu-lts-latest" # https://docs.readthedocs.io/en/stable/config-file/v2.html#build-os tools: - python: "mambaforge-4.10" # https://docs.readthedocs.io/en/stable/config-file/v2.html#build-tools-python, mamba instead of conda for better build performance \ No newline at end of file + python: "mambaforge-latest" # https://docs.readthedocs.io/en/stable/config-file/v2.html#build-tools-python, mamba instead of conda for better build performance \ No newline at end of file diff --git a/CHANGES.md b/CHANGES.md index 10deba2..88bb2bf 100644 --- a/CHANGES.md +++ b/CHANGES.md @@ -1,4 +1,4 @@ -# bw_graph_tools Changelog +# `bw_graph_tools` Changelog All notable changes to this project will be documented in this file. diff --git a/README.md b/README.md index e8baad0..49244f0 100644 --- a/README.md +++ b/README.md @@ -44,7 +44,6 @@ Normally we construct matrices and solve the resulting set of linear equations t If we add temporal information using `bw_temporalis`, then the same node can occur at different times depending on how the temporal dynamics its preceding path. For example: - ## Contributing Contributions are very welcome. @@ -62,15 +61,9 @@ please [file an issue] along with a detailed description. ## Documentation -1. Install the `sphinx-furo` conda environment from the file `.docs/environment.yml`. -2. Build the documentation locally by running +1. Install the conda environment from the file `.docs/environment.yml` +2. Build the documentation locally by running: -``` +```bash sphinx-autobuild docs _build/html -a -j auto --open-browser -``` - - - -[command-line reference]: https://bw_graph_tools.readthedocs.io/en/latest/usage.html -[license]: https://github.com/brightway-lca/bw_graph_tools/blob/main/LICENSE -[contributor guide]: https://github.com/brightway-lca/bw_graph_tools/blob/main/CONTRIBUTING.md +``` \ No newline at end of file diff --git a/bw_graph_tools/graph_traversal.py b/bw_graph_tools/graph_traversal.py index bc6f04b..9cb3537 100644 --- a/bw_graph_tools/graph_traversal.py +++ b/bw_graph_tools/graph_traversal.py @@ -240,8 +240,8 @@ def calculate( traverse functional_unit_unique_id : int An integer id we can use for the functional unit virtual activity. - Shouldn't overlap any other activity ids. Don't change unless you r - eally know what you are doing. + Shouldn't overlap any other activity ids. Don't change unless you + really know what you are doing. Returns ------- diff --git a/docs/conf.py b/docs/conf.py index 7413ef6..c16e534 100644 --- a/docs/conf.py +++ b/docs/conf.py @@ -1,23 +1,15 @@ ### import setup ################################################################################## import datetime -import importlib.metadata -import os -import shutil -from sphinx.ext import apidoc ### project information ########################################################################### -project = "bw_graph_tools" -author = "Chris Mutel" -copyright = datetime.date.today().strftime("%Y") + ' Chris Mutel' +project = "Brightway Graph Tools" +author = "Brightway Developers" +copyright = datetime.date.today().strftime("%Y") + ' Brightway Developers' ### project configuration ######################################################################### -needs_sphinx = '5.3.0' - -# Add any Sphinx extension module names here, as strings. They can be extensions -# coming with Sphinx (named 'sphinx.ext.*') or your custom ones. extensions = [ # native extensions 'sphinx.ext.autodoc', @@ -27,10 +19,16 @@ 'sphinx.ext.intersphinx', 'sphinx.ext.extlinks', 'sphinx.ext.napoleon', + # theme + 'sphinx_rtd_theme', # Markdown support 'myst_parser', # API documentation support 'autoapi', + # responsive web component support + 'sphinx_design', + # copy button on code blocks + "sphinx_copybutton", ] exclude_patterns = ['_build'] @@ -38,6 +36,27 @@ # The master toctree document. master_doc = 'index' +### theme configuration ############################################################################ + +html_theme = "sphinx_rtd_theme" +html_title = "Brightway Graph Tools" +html_show_sphinx = False + +html_theme_options = { + 'logo_only': False, + 'display_version': True, + 'prev_next_buttons_location': 'bottom', + # Toc options + 'collapse_navigation': True, + 'sticky_navigation': True, + 'navigation_depth': 4, + 'includehidden': True, + 'titles_only': False +} + +html_logo = 'https://raw.githubusercontent.com/brightway-lca/brightway-documentation/main/source/_static/logo/BW_all_white_transparent_landscape_wide.svg' +html_favicon = 'https://github.com/brightway-lca/brightway-documentation/blob/main/source/_static/logo/BW_favicon_500x500.png' + ### extension configuration ######################################################################## ## myst_parser configuration ############################################ @@ -67,12 +86,11 @@ 'show-module-summary', #'special-members', #'imported-members', - 'show-inheritance-diagram' ] autoapi_python_class_content = 'both' autoapi_member_order = 'groupwise' -autoapi_root = 'pages/api' +autoapi_root = 'content/api' autoapi_keep_files = False autoapi_dirs = [ diff --git a/docs/content/api/bw_graph_tools/errors/index.rst b/docs/content/api/bw_graph_tools/errors/index.rst new file mode 100644 index 0000000..22bb802 --- /dev/null +++ b/docs/content/api/bw_graph_tools/errors/index.rst @@ -0,0 +1,19 @@ +:py:mod:`bw_graph_tools.errors` +=============================== + +.. py:module:: bw_graph_tools.errors + + +Module Contents +--------------- + +.. py:exception:: UnclearProductionExchange + + + Bases: :py:obj:`Exception` + + Can't guess the production exchange row and column indices + + Initialize self. See help(type(self)) for accurate signature. + + diff --git a/docs/content/api/bw_graph_tools/graph_traversal/index.rst b/docs/content/api/bw_graph_tools/graph_traversal/index.rst new file mode 100644 index 0000000..361c9fa --- /dev/null +++ b/docs/content/api/bw_graph_tools/graph_traversal/index.rst @@ -0,0 +1,464 @@ +:py:mod:`bw_graph_tools.graph_traversal` +======================================== + +.. py:module:: bw_graph_tools.graph_traversal + + +Module Contents +--------------- + +Classes +~~~~~~~ + +.. autoapisummary:: + + bw_graph_tools.graph_traversal.AssumedDiagonalGraphTraversal + bw_graph_tools.graph_traversal.CachingSolver + bw_graph_tools.graph_traversal.Counter + bw_graph_tools.graph_traversal.Edge + bw_graph_tools.graph_traversal.Flow + bw_graph_tools.graph_traversal.NewNodeEachVisitGraphTraversal + bw_graph_tools.graph_traversal.Node + + + + +Attributes +~~~~~~~~~~ + +.. autoapisummary:: + + bw_graph_tools.graph_traversal.databases + + +.. py:class:: AssumedDiagonalGraphTraversal + + + Bases: :py:obj:`NewNodeEachVisitGraphTraversal` + + Traverse a supply chain, following paths of greatest impact. + + This implementation uses a queue of datasets to assess. As the supply chain is traversed, activities are added to a list sorted by LCA score. Each activity in the sorted list is assessed, and added to the supply chain graph, as long as its impact is above a certain threshold, and the maximum number of calculations has not been exceeded. + + Because the next dataset assessed is chosen by its impact, not its position in the graph, this is neither a breadth-first nor a depth-first search, but rather "importance-first". + + This class is written in a functional style, and the class serves mainly to collect methods which belong together. There are only `classmethods` and no state is stored on the class itself. + + Should be used by calling the ``calculate`` method. All other functions should be considered an internal API. + + .. warning:: Graph traversal with multioutput processes only works when other inputs are substituted (see `Multioutput processes in LCA `__ for a description of multiputput process math in LCA). + + + .. py:method:: get_production_exchanges(mapped_matrix: matrix_utils.MappedMatrix) -> (numpy.ndarray, numpy.ndarray) + :classmethod: + + Assume production exchanges are always on the diagonal instead of + examining matrix structure and input data. + + :param mapped_matrix: A matrix and mapping data (from database ids to matrix indices) + from the ``matrix_utils`` library. Normally built automatically by + an ``LCA`` class. Should be the ``technosphere_matrix`` or + equivalent. + :type mapped_matrix: matrix_utils.MappedMatrix + + :returns: The matrix row and column indices of the production exchanges. + :rtype: (numpy.array, numpy.array) + + + +.. py:class:: CachingSolver(lca: bw2calc.LCA) + + + Class which caches expensive linear algebra solution vectors. + + .. py:method:: calculate(index: int) -> numpy.ndarray + + Compute cumulative LCA score for one unit of a given activity + + + +.. py:class:: Counter + + + Custom counter to have easy access to current value + + +.. py:class:: Edge + + + An edge between two *activities*. The `amount` is the amount of the product demanded by the `consumer`. + + :param consumer_index: The matrix column index of the consuming activity + :type consumer_index: int + :param consumer_unique_id: The traversal-specific unique id of the consuming activity + :type consumer_unique_id: int + :param producer_index: The matrix column index of the producing activity + :type producer_index: int + :param producer_unique_id: The traversal-specific unique id of the producing activity + :type producer_unique_id: int + :param product_index: The matrix row index of the consumed product + :type product_index: int + :param amount: The amount of the product demanded by the consumer. Not scaled to producer production amount. + :type amount: float + + .. py:attribute:: amount + :type: float + + + + .. py:attribute:: consumer_index + :type: int + + + + .. py:attribute:: consumer_unique_id + :type: int + + + + .. py:attribute:: producer_index + :type: int + + + + .. py:attribute:: producer_unique_id + :type: int + + + + .. py:attribute:: product_index + :type: int + + + + +.. py:class:: Flow + + + A characterized biosphere flow associated with a given `Node` instance. + + :param flow_datapackage_id: The id that identifies the biosphere flow in the datapackage + :type flow_datapackage_id: int + :param flow_index: The matrix row index of the biosphere flow + :type flow_index: int + :param activity_unique_id: The `Node.unique_id` of this instance of the emitting activity + :type activity_unique_id: int + :param activity_id: The id that identifies the emitting activity in the datapackage + :type activity_id: int + :param activity_index: The matrix column index of the emitting activity + :type activity_index: int + :param amount: The amount of the biosphere flow being emitting by this activity instance + :type amount: float + :param score: The LCIA score for `amount` of this biosphere flow + :type score: float + + .. py:attribute:: activity_id + :type: int + + + + .. py:attribute:: activity_index + :type: int + + + + .. py:attribute:: activity_unique_id + :type: int + + + + .. py:attribute:: amount + :type: float + + + + .. py:attribute:: flow_datapackage_id + :type: int + + + + .. py:attribute:: flow_index + :type: int + + + + .. py:attribute:: score + :type: float + + + + +.. py:class:: NewNodeEachVisitGraphTraversal + + + Traverse a supply chain, following paths of greatest impact. + + This implementation uses a queue of datasets to assess. As the supply chain is traversed, activities are added to a list sorted by LCA score. Each activity in the sorted list is assessed, and added to the supply chain graph, as long as its impact is above a certain threshold, and the maximum number of calculations has not been exceeded. + + Because the next dataset assessed is chosen by its impact, not its position in the graph, this is neither a breadth-first nor a depth-first search, but rather "importance-first". + + This class is written in a functional style, and the class serves mainly to collect methods which belong together. There are only `classmethods` and no state is stored on the class itself. + + Should be used by calling the ``calculate`` method. All other functions should be considered an internal API. + + .. warning:: Graph traversal with multioutput processes only works when other inputs are substituted (see `Multioutput processes in LCA `__ for a description of multiputput process math in LCA). + + + .. py:method:: add_biosphere_flows(flows: list[Flow], matrix: scipy.sparse.spmatrix, lca: bw2calc.LCA, node: Node, biosphere_cutoff_score: float) -> None + :classmethod: + + Add individual biosphere flows as `Flow` instances to `flow` if their score is above `biosphere_cutoff_score`. + + :param flows: List of existing `Flow` instances + :type flows: list + :param matrix: Pre-calculated characterization times biosphere matrix + :type matrix: scipy.sparse.spmatrix + :param lca: LCA class instance + :type lca: bw2calc.LCA + :param node: Node whose direct biosphere flows we are examining + :type node: `Node` + :param biosphere_cutoff_score: Score below which individual characterized biosphere flows are ignored + :type biosphere_cutoff_score: float + + :returns: Modifies `flows` by adding new `Flow` instances + :rtype: `None` + + + .. py:method:: calculate(lca_object: bw2calc.LCA, cutoff: float | None = 0.005, biosphere_cutoff: float | None = 0.0001, max_calc: int | None = 100000.0, skip_coproducts: bool | None = False, separate_biosphere_flows: bool | None = True, static_activity_indices: set[int] | None = set(), functional_unit_unique_id: int | None = -1) -> dict + :classmethod: + + Priority-first traversal (i.e. follow the past of highest score) of the supply chain graph. This class unrolls + the graph, i.e. every time it arrives at a given activity, it treats + it as a separate node in the graph. + + In contrast with previous graph traversal implementations, we do not assume reference production exchanges are on the diagonal. It should also correctly handle the following: + + * Functional unit has more than one link to a given product + * Non-unitary reference production amounts + * Negative reference production amounts + * Co-production edge traversal, if desired. Requires co-products to be substituted (can be implicit substitution). + + You must provide an `lca_object` which is already instantiated, and for which you have already done LCI and LCIA calculations. The `lca_object` does not have to be an instance of `bw2calc.LCA`, but it needs to support the following methods and attributes: + + * `technosphere_matrix` + * `technosphere_mm` + * `solve_linear_system()` + * `demand` + * `demand_array` + + You can subclass `NewNodeEachVisitGraphTraversal` and redefine `get_characterized_biosphere` if your LCA class does not have a traditional `characterization_matrix` and `biosphere_matrix`. + + The return object is a dictionary with four values. The `nodes` is a dictionary of visited **activities**; the keys in this dictionary are unique increasing integer ids (not related to any other ids or indices), and values are instances of the `Node` dataclass. Each `Node` has a `unique_id`, as every time we arrive at an activity (even if we have seen it before via another branch of the supply chain), we create a new `Node` object with a unique id. See the `Node` documentation for its other attributes. + + edges + + flows + + Finally, `calculation_count` gives the total number of inventory calculations performed. + + Without further manipulation, the results will have double counting if you add all scores together. Specifically, each `Node` has both a `cumulative_score` and a `direct_emissions_score`; the direct emissions are counted in both scores. Use XXX to subtract `direct_emissions_score` from `cumulative_score`. Moreover, the `direct_emissions_score` includes all characterized flows, but important flows can also be listed separately as `Flow` objects. Use XXX to subtract specific `Flows` from the `direct_emissions_score`. + + :param lca_object: Already instantiated `LCA` object with inventory and impact + assessment calculated. + :type lca_object: bw2calc.LCA + :param cutoff: Cutoff value used to stop graph traversal. Fraction of total score, + should be in `(0, 1)` + :type cutoff: float + :param biosphere_cutoff: Cutoff value used to determine if a separate biosphere node is + added. Fraction of total score. + :type biosphere_cutoff: float + :param max_calc: Maximum number of inventory calculations to perform + :type max_calc: int + :param skip_coproducts: Don't traverse co-production edges, i.e. production edges other + than the reference product + :type skip_coproducts: bool + :param separate_biosphere_flows: Add separate `Flow` nodes for important individual biosphere + emissions + :type separate_biosphere_flows: bool + :param static_activity_indices: A set of activity matrix indices which we don't want the graph to + traverse + :type static_activity_indices: set + :param functional_unit_unique_id: An integer id we can use for the functional unit virtual activity. + Shouldn't overlap any other activity ids. Don't change unless you + really know what you are doing. + :type functional_unit_unique_id: int + + :returns: Dictionary with keys `nodes`, `edges`, `flows`, `calculation_counter` + :rtype: dict + + + .. py:method:: get_characterized_biosphere(lca: bw2calc.LCA) -> scipy.sparse.spmatrix + :classmethod: + + Pre-calculate the characterized biosphere matrix. + + Broken out as a separate method because subclasses like regionalized + LCA could have more complicated characterization. + + :param lca: LCA class instance + :type lca: bw2calc.LCA + + :returns: Unmapped matrix of biosphere flows by activities. + :rtype: scipy.sparse.spmatrix + + + .. py:method:: get_demand_vector_for_activity(node: Node, skip_coproducts: bool, matrix: scipy.sparse.spmatrix) -> (list[int], list[float]) + :classmethod: + + Get input matrix indices and amounts for a given activity. Ignores the reference production exchanges and optionally other co-production exchanges. + + :param node: Activity whose inputs we are iterating over + :type node: `Node` + :param skip_coproducts: Whether or not to ignore positive production exchanges other than the reference product, which is always ignored + :type skip_coproducts: bool + :param matrix: Technosphere matrix + :type matrix: scipy.sparse.spmatrix + + :returns: * **row indices** (*list*) -- Integer row indices for products consumed by `Node` + * **amounts** (*list*) -- The amount of each product consumed, scaled to `Node.supply_amount`. Same order as row indices. + + + .. py:method:: get_production_exchanges(mapped_matrix: matrix_utils.MappedMatrix) -> (numpy.array, numpy.array) + :classmethod: + + Get matrix row and column indices of productions exchanges by trying a + series of heuristics. See documentation for + ``guess_production_exchanges``. + + Broken out as a separate method because subclasses could change this logic. + + :param mapped_matrix: A matrix and mapping data (from database ids to matrix indices) + from the ``matrix_utils`` library. Normally built automatically by + an ``LCA`` class. Should be the ``technosphere_matrix`` or + equivalent. + :type mapped_matrix: matrix_utils.MappedMatrix + + :returns: The matrix row and column indices of the production exchanges. + :rtype: (numpy.array, numpy.array) + + + .. py:method:: traverse(heap: list, nodes: dict[Node], edges: list[Edge], flows: list[Flow], max_calc: int, cutoff_score: float, characterized_biosphere: scipy.sparse.spmatrix, calculation_count: Counter, static_activity_indices: set, production_exchange_mapping: dict[int, int], technosphere_matrix: scipy.sparse.spmatrix, lca: bw2calc.LCA, caching_solver: CachingSolver, skip_coproducts: bool, separate_biosphere_flows: bool, biosphere_cutoff_score: float) -> None + :classmethod: + + Perform the graph traversal from the initial functional unit edges. + + :param heap: The `heapq` list of nodes to traverse + :type heap: list + :param nodes: Dictionary of already visited `Nodes` + :type nodes: dict + :param edges: List of visited `Edges` + :type edges: list + :param flows: List of significant seen `Flows` + :type flows: list + :param max_calc: Maximum number of inventory calculations to perform + :type max_calc: int + :param cutoff_score: Score below which graph edges are ignored. We always consider the absolute value of edges scores. + :type cutoff_score: float + :param characterized_biosphere: The pre-calculated characterization time biosphere matrix + :type characterized_biosphere: spmatrix + :param calculation_count: Counter object tracking number of lci calculations + :type calculation_count: `Counter` + :param static_activity_indices: A set of activity matrix indices which we don't want the graph to + traverse + :type static_activity_indices: set + :param production_exchange_mapping: Mapping of product matrix row indices to the activity matrix column indices for which they are reference products + :type production_exchange_mapping: dict + :param technosphere_matrix: LCA technosphere matrix + :type technosphere_matrix: scipy.sparse.spmatrix + :param lca: Already instantiated `LCA` object with inventory and impact + assessment calculated. + :type lca: bw2calc.LCA + :param caching_solver: Solver which caches solutions to linear algebra problems + :type caching_solver: `CachingSolver` + :param skip_coproducts: Don't traverse co-production edges, i.e. production edges other + than the reference product + :type skip_coproducts: bool + :param separate_biosphere_flows: Add separate `Flow` nodes for important individual biosphere + emissions + :type separate_biosphere_flows: bool + :param biosphere_cutoff_score: Score below which individual biosphere flows are not added to `flows` + :type biosphere_cutoff_score: float + + :returns: Modifies `heap`, `nodes`, `edges`, and `flows` in-place + :rtype: `None` + + + .. py:method:: traverse_edges(consumer_index: int, consumer_unique_id: int, product_indices: list[int], product_amounts: list[float], lca: bw2calc.LCA, calculation_count: Counter, characterized_biosphere: scipy.sparse.spmatrix, matrix: scipy.sparse.spmatrix, edges: list[Edge], flows: list[Flow], nodes: list[Node], heap: list, production_exchange_mapping: dict[int, int], static_activity_indices: set[int], separate_biosphere_flows: bool, caching_solver: CachingSolver, biosphere_cutoff_score: float, cutoff_score: float) -> None + :classmethod: + + + +.. py:class:: Node + + + A visited activity in a supply chain graph. Although our graph is cyclic, we treat each activity as a separate node every time we visit it. + + :param unique_id: A unique integer id for this visit to this activity node + :type unique_id: int + :param activity_datapackage_id: The id that identifies this activity in the datapackage, and hence in the database + :type activity_datapackage_id: int + :param activity_index: The technosphere matrix column index of this activity + :type activity_index: int + :param reference_product_datapackage_id: The id that identifies the reference product of this activity in the datapackage + :type reference_product_datapackage_id: int + :param reference_product_index: The technosphere matrix row index of this activity's reference product + :type reference_product_index: int + :param reference_product_production_amount: The *net* production amount of this activity's reference product + :type reference_product_production_amount: float + :param supply_amount: The amount of the *activity* (not reference product!) needed to supply the demand from the requesting supply chain edge. + :type supply_amount: float + :param cumulative_score: Total LCIA score attributed to `supply_amount` of this activity. Includes direct emissions unless explicitly removed. + :type cumulative_score: float + :param direct_emissions_score: Total LCIA score attributed only to the direct characterized biosphere flows of `supply_amount` of this activity. + :type direct_emissions_score: float + + .. py:attribute:: activity_datapackage_id + :type: int + + + + .. py:attribute:: activity_index + :type: int + + + + .. py:attribute:: cumulative_score + :type: float + + + + .. py:attribute:: direct_emissions_score + :type: float + + + + .. py:attribute:: reference_product_datapackage_id + :type: int + + + + .. py:attribute:: reference_product_index + :type: int + + + + .. py:attribute:: reference_product_production_amount + :type: float + + + + .. py:attribute:: supply_amount + :type: float + + + + .. py:attribute:: unique_id + :type: int + + + + +.. py:data:: databases + + + diff --git a/docs/content/api/bw_graph_tools/graph_traversal_utils/index.rst b/docs/content/api/bw_graph_tools/graph_traversal_utils/index.rst new file mode 100644 index 0000000..006a94c --- /dev/null +++ b/docs/content/api/bw_graph_tools/graph_traversal_utils/index.rst @@ -0,0 +1,45 @@ +:py:mod:`bw_graph_tools.graph_traversal_utils` +============================================== + +.. py:module:: bw_graph_tools.graph_traversal_utils + + +Module Contents +--------------- + + +Functions +~~~~~~~~~ + +.. autoapisummary:: + + bw_graph_tools.graph_traversal_utils.get_path_from_matrix + bw_graph_tools.graph_traversal_utils.path_as_brightway_objects + + + +Attributes +~~~~~~~~~~ + +.. autoapisummary:: + + bw_graph_tools.graph_traversal_utils.brightway_available + + +.. py:function:: get_path_from_matrix(matrix: scipy.sparse.spmatrix, source: int, target: int, algorithm: str = 'BF') -> List + + Get the path with the most mass or energetic flow from ``source`` (the function unit) to ``target`` (something deep in the supply chain). Both ``source`` and ``target`` are integer matrix indices. + + ``algorithm`` should be either ``BF`` (Bellman-Ford) or ``J`` (Johnson). Dijkstra is not recommended as we have negative weights. + + Returns a list like ``[source, int, int, int, target]``. + + +.. py:function:: path_as_brightway_objects(source_node: bw2data.Node, target_node: bw2data.Node, lca: Optional[bw2calc.LCA] = None) -> List[bw2data.Edge] + + +.. py:data:: brightway_available + :value: True + + + diff --git a/docs/content/api/bw_graph_tools/index.rst b/docs/content/api/bw_graph_tools/index.rst new file mode 100644 index 0000000..93b65d3 --- /dev/null +++ b/docs/content/api/bw_graph_tools/index.rst @@ -0,0 +1,67 @@ +:py:mod:`bw_graph_tools` +======================== + +.. py:module:: bw_graph_tools + + +Submodules +---------- +.. toctree:: + :titlesonly: + :maxdepth: 1 + + errors/index.rst + graph_traversal/index.rst + graph_traversal_utils/index.rst + matrix_tools/index.rst + shortest_path/index.rst + testing/index.rst + utils/index.rst + + +Package Contents +---------------- + +Classes +~~~~~~~ + +.. autoapisummary:: + + bw_graph_tools.AssumedDiagonalGraphTraversal + bw_graph_tools.Edge + bw_graph_tools.Flow + bw_graph_tools.NewNodeEachVisitGraphTraversal + bw_graph_tools.Node + + + +Functions +~~~~~~~~~ + +.. autoapisummary:: + + bw_graph_tools.get_path_from_matrix + bw_graph_tools.guess_production_exchanges + bw_graph_tools.path_as_brightway_objects + bw_graph_tools.to_normalized_adjacency_matrix + + + +Attributes +~~~~~~~~~~ + +.. autoapisummary:: + + bw_graph_tools.__version__ + + + + + + + + + + + + diff --git a/docs/content/api/bw_graph_tools/matrix_tools/index.rst b/docs/content/api/bw_graph_tools/matrix_tools/index.rst new file mode 100644 index 0000000..5eedf54 --- /dev/null +++ b/docs/content/api/bw_graph_tools/matrix_tools/index.rst @@ -0,0 +1,86 @@ +:py:mod:`bw_graph_tools.matrix_tools` +===================================== + +.. py:module:: bw_graph_tools.matrix_tools + + +Module Contents +--------------- + + +Functions +~~~~~~~~~ + +.. autoapisummary:: + + bw_graph_tools.matrix_tools.gpe_first_heuristic + bw_graph_tools.matrix_tools.gpe_second_heuristic + bw_graph_tools.matrix_tools.gpe_third_heuristic + bw_graph_tools.matrix_tools.guess_production_exchanges + bw_graph_tools.matrix_tools.reorder_mapped_matrix + bw_graph_tools.matrix_tools.to_normalized_adjacency_matrix + + + +.. py:function:: gpe_first_heuristic(mm: matrix_utils.MappedMatrix) -> Tuple[numpy.ndarray, numpy.ndarray] + + Use first heuristic (same input and output ids) to find production exchange indices. + + If we treat activities and products the same, then an exchange with the row and column id + is definitely a production exchange location. We don't care if there are duplicates (e.g. + production and some loss), we will return unique pairs. + + If activities have different ids than products, this won't find anything. + + Returns a tuple of numpy integer matrix indices, rows by columns. + + +.. py:function:: gpe_second_heuristic(mm: matrix_utils.MappedMatrix, row_existing: numpy.ndarray, col_existing: numpy.ndarray) -> Tuple[numpy.ndarray, numpy.ndarray] + + +.. py:function:: gpe_third_heuristic(mm: matrix_utils.MappedMatrix, row_existing: numpy.ndarray, col_existing: numpy.ndarray) -> Tuple[numpy.ndarray, numpy.ndarray] + + +.. py:function:: guess_production_exchanges(mm: matrix_utils.MappedMatrix) -> Tuple[numpy.ndarray, numpy.ndarray] + + Try to guess productions exchanges in a mapped technosphere matrix using heuristics from the input data packages. + + Try the following in order per activity (column): + + * Same input and output index + * Single value where ``flip`` is negative + * Single positive value + + Raises ``UnclearProductionExchange`` if these conditions are not met for any activity. + + Returns integer arrays of the matrix row and column indices where production exchanges were found. + + + +.. py:function:: reorder_mapped_matrix(matrix: matrix_utils.MappedMatrix) -> scipy.sparse.csr_matrix + + +.. py:function:: to_normalized_adjacency_matrix(matrix: scipy.sparse.spmatrix, log_transform: bool = True) -> scipy.sparse.csr_matrix + + Take a technosphere matrix constructed with Brightway conventions, and return a normalized adjacency matrix. + + In the adjacency matrix A, `A[i,j]` indicates a directed edge **from** row `i` **to** column `j`. However, + this is the opposite of what we normally want, which is to find a path from the functional activity to + somewhere in its supply chain. In a Brightway technosphere matrix, `A[i,j]` means **activity** `j` consumes + the output of activity `i`. To go down the supply chain, however, we would need to go from ``j`` to ``i``. + Therefore, we take the transpose of the technosphere matrix. + + Normalization is done to remove the effect of activities which don't produce one unit of their reference product. + For example, if activity `foo` produces two units of `bar` and consumes two units of `baz`, the weight of the + `baz` edge should be :math:`2 / 2 = 1`. + + In addition to this normalization, we subtract the diagonal and flip the signs of all matrix values. Flipping + the sign is needed because we want to use a shortest path algorithm, but actually want the longest path. The + longest path is the path with the highest weight, i.e. the path where the most consumption occurs on. + + By default, we also take the natural log of the data values. This is because our supply chain is multiplicative, + not additive, and :math:`a \cdot b = e^{\ln(a) + \ln(b)}`. The idea of using the log was borrowed from `David Richardby on Stack Overflow `__. + + Assumes that production amounts are on the diagonal. + + diff --git a/docs/content/api/bw_graph_tools/shortest_path/index.rst b/docs/content/api/bw_graph_tools/shortest_path/index.rst new file mode 100644 index 0000000..27993dd --- /dev/null +++ b/docs/content/api/bw_graph_tools/shortest_path/index.rst @@ -0,0 +1,127 @@ +:py:mod:`bw_graph_tools.shortest_path` +====================================== + +.. py:module:: bw_graph_tools.shortest_path + +.. autoapi-nested-parse:: + + Created on November 12, 2019 + @author: Quentin Lutz + From scikit-network version 0.30 + + BSD License + + Copyright (c) 2018, Scikit-network Developers + Bertrand Charpentier + Thomas Bonald + All rights reserved. + + Redistribution and use in source and binary forms, with or without modification, + are permitted provided that the following conditions are met: + + * Redistributions of source code must retain the above copyright notice, this + list of conditions and the following disclaimer. + + * Redistributions in binary form must reproduce the above copyright notice, this + list of conditions and the following disclaimer in the documentation and/or + other materials provided with the distribution. + + * Neither the name of the copyright holder nor the names of its + contributors may be used to endorse or promote products derived from this + software without specific prior written permission. + + THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND + ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. + IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, + INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, + BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY + OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE + OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED + OF THE POSSIBILITY OF SUCH DAMAGE. + + + +Module Contents +--------------- + + +Functions +~~~~~~~~~ + +.. autoapisummary:: + + bw_graph_tools.shortest_path.get_distances + bw_graph_tools.shortest_path.get_shortest_path + + + +.. py:function:: get_distances(adjacency: scipy.sparse.csr_matrix, sources: Optional[Union[int, Iterable]] = None, method: str = 'D', return_predecessors: bool = False, unweighted: bool = False, n_jobs: Optional[int] = None) + + Compute distances between nodes. + + * Graphs + * Digraphs + + + Based on SciPy (scipy.sparse.csgraph.shortest_path) + + :param adjacency: The adjacency matrix of the graph + :param sources: If specified, only compute the paths for the points at the given indices. Will not work with ``method =='FW'``. + :param method: The method to be used. + + * ``'D'`` (Dijkstra), + * ``'BF'`` (Bellman-Ford), + * ``'J'`` (Johnson). + :param return_predecessors: If ``True``, the size predecessor matrix is returned + :param unweighted: If ``True``, the weights of the edges are ignored + :param n_jobs: If an integer value is given, denotes the number of workers to use (-1 means the maximum number will be used). + If ``None``, no parallel computations are made. + + :returns: * **dist_matrix** (*np.ndarray*) -- Matrix of distances between nodes. ``dist_matrix[i,j]`` gives the shortest + distance from the ``i``-th source to node ``j`` in the graph (infinite if no path exists + from the ``i``-th source to node ``j``). + * **predecessors** (*np.ndarray, optional*) -- Returned only if ``return_predecessors == True``. The matrix of predecessors, which can be used to reconstruct + the shortest paths. Row ``i`` of the predecessor matrix contains information on the shortest paths from the + ``i``-th source: each entry ``predecessors[i, j]`` gives the index of the previous node in the path from + the ``i``-th source to node ``j`` (-1 if no path exists from the ``i``-th source to node ``j``). + + +.. py:function:: get_shortest_path(adjacency: scipy.sparse.csr_matrix, sources: Union[int, Iterable], targets: Union[int, Iterable], method: str = 'D', unweighted: bool = False, n_jobs: Optional[int] = None) + + Compute the shortest paths in the graph. + + :param adjacency: The adjacency matrix of the graph + :param sources: Sources nodes. + :type sources: int or iterable + :param targets: Target nodes. + :type targets: int or iterable + :param method: The method to be used. + + * ``'D'`` (Dijkstra), + * ``'BF'`` (Bellman-Ford), + * ``'J'`` (Johnson). + :param unweighted: If ``True``, the weights of the edges are ignored + :param n_jobs: If an integer value is given, denotes the number of workers to use (-1 means the maximum number will be used). + If ``None``, no parallel computations are made. + + :returns: **paths** -- If single source and single target, return a list containing the nodes on the path from source to target. + If multiple sources or multiple targets, return a list of paths as lists. + An empty list means that the path does not exist. + :rtype: list + + .. rubric:: Examples + + >>> from sknetwork.data import linear_digraph + >>> adjacency = linear_digraph(3) + >>> get_shortest_path(adjacency, 0, 2) + [0, 1, 2] + >>> get_shortest_path(adjacency, 2, 0) + [] + >>> get_shortest_path(adjacency, 0, [1, 2]) + [[0, 1], [0, 1, 2]] + >>> get_shortest_path(adjacency, [0, 1], 2) + [[0, 1, 2], [1, 2]] + + diff --git a/docs/content/api/bw_graph_tools/testing/index.rst b/docs/content/api/bw_graph_tools/testing/index.rst new file mode 100644 index 0000000..1b16d1a --- /dev/null +++ b/docs/content/api/bw_graph_tools/testing/index.rst @@ -0,0 +1,34 @@ +:py:mod:`bw_graph_tools.testing` +================================ + +.. py:module:: bw_graph_tools.testing + + +Module Contents +--------------- + + +Functions +~~~~~~~~~ + +.. autoapisummary:: + + bw_graph_tools.testing.edge_equal_dict + bw_graph_tools.testing.equal_dict + bw_graph_tools.testing.flow_equal_dict + bw_graph_tools.testing.node_equal_dict + + + +.. py:function:: edge_equal_dict(a: bw_graph_tools.Edge, b: dict) + + +.. py:function:: equal_dict(a: bw_graph_tools.Node | bw_graph_tools.Edge | bw_graph_tools.Flow, b: dict, fields: list[str]) + + +.. py:function:: flow_equal_dict(a: bw_graph_tools.Flow, b: dict) + + +.. py:function:: node_equal_dict(a: bw_graph_tools.Node, b: dict) + + diff --git a/docs/content/api/bw_graph_tools/utils/index.rst b/docs/content/api/bw_graph_tools/utils/index.rst new file mode 100644 index 0000000..a30f69d --- /dev/null +++ b/docs/content/api/bw_graph_tools/utils/index.rst @@ -0,0 +1,22 @@ +:py:mod:`bw_graph_tools.utils` +============================== + +.. py:module:: bw_graph_tools.utils + + +Module Contents +--------------- + + +Functions +~~~~~~~~~ + +.. autoapisummary:: + + bw_graph_tools.utils.get_version_tuple + + + +.. py:function:: get_version_tuple() -> tuple + + diff --git a/docs/content/api/index.rst b/docs/content/api/index.rst new file mode 100644 index 0000000..4e0628b --- /dev/null +++ b/docs/content/api/index.rst @@ -0,0 +1,11 @@ +API Reference +============= + +This page contains auto-generated API reference documentation [#f1]_. + +.. toctree:: + :titlesonly: + + /content/api/bw_graph_tools/index + +.. [#f1] Created with `sphinx-autoapi `_ \ No newline at end of file diff --git a/docs/pages/changelog.md b/docs/content/changelog.md similarity index 100% rename from docs/pages/changelog.md rename to docs/content/changelog.md diff --git a/docs/pages/codeofconduct.md b/docs/content/codeofconduct.md similarity index 100% rename from docs/pages/codeofconduct.md rename to docs/content/codeofconduct.md diff --git a/docs/pages/contributing.md b/docs/content/contributing.md similarity index 100% rename from docs/pages/contributing.md rename to docs/content/contributing.md diff --git a/docs/pages/license.md b/docs/content/license.md similarity index 100% rename from docs/pages/license.md rename to docs/content/license.md diff --git a/docs/content/usage.md b/docs/content/usage.md new file mode 100644 index 0000000..b0e7a7e --- /dev/null +++ b/docs/content/usage.md @@ -0,0 +1,18 @@ +# Usage + +`bw_graph_tools` has three main components: A graph traversal class `NewNodeEachVisitGraphTraversal`; a function to guess production exchanges using only `bw_processing` datapackages `guess_production_exchanges`; and a function to find the path from node `A` to node `B` with the largest amount of the reference product of `A`, `get_path_from_matrix` and it's sister `path_as_brightway_objects`. + +### `NewNodeEachVisitGraphTraversal` + +Normally we construct matrices and solve the resulting set of linear equations to get a life cycle inventory or impact assessment result. The matrix approach is elegant, in that it simultaneously solves all equations and handles cycles in the graph, and much faster than graph traversal. However, in some cases we want to actually traverse the supply chain graph and calculate the individual impact of visiting nodes at that point in the graph. Graph traversal's use cases include: + +* Distinguishing between different paths to the same object +* Convolving temporal distributions + +If we add temporal information using `bw_temporalis`, then the same node can occur at different times depending on how the temporal dynamics its preceding path. For example: + +## Some Examples + +- [`1 - Spatiotemporal calculations.ipynb`](https://github.com/brightway-lca/from-the-ground-up/blob/327e2af95249135a71a57cfb3eb0c7d73f6e5239/spatiotemporal/1%20-%20Spatiotemporal%20calculations.ipynb#L16) +- [`1 - Introduction.ipynb`](https://github.com/brightway-lca/from-the-ground-up/blob/327e2af95249135a71a57cfb3eb0c7d73f6e5239/temporal/1%20-%20Introduction.ipynb#L215) +- [`Example usage.ipynb`](https://github.com/brightway-lca/bw_temporalis/blob/911a7729d5ac065bbae862df5c1381aa1058cf48/dev/Example%20usage.ipynb#L17) diff --git a/docs/environment.yaml b/docs/environment.yaml new file mode 100644 index 0000000..51d27bc --- /dev/null +++ b/docs/environment.yaml @@ -0,0 +1,20 @@ +name: sphinx_bw_graph_tools +channels: + - conda-forge + - nodefaults +dependencies: + # core functionality + - python + - ipython + # sphinx + - sphinx # core builder # https://anaconda.org/conda-forge/sphinx/files + # theme and extensions + - sphinx_rtd_theme # theme # https://anaconda.org/conda-forge/sphinx_rtd_theme/files + - myst-parser # Markdown support # https://anaconda.org/conda-forge/myst-parser/files + - sphinx-design # responsive web component support # https://anaconda.org/conda-forge/sphinx-design/files + - sphinx-copybutton # for copy button in code blocks # https://anaconda.org/conda-forge/sphinx-copybutton/files + - sphinx-autoapi # to build docs from source code instead of package import # https://anaconda.org/conda-forge/sphinx-autoapi/files + - sphinx-notfound-page # custom 404 page # https://anaconda.org/conda-forge/sphinx-notfound-page/files + - sphinx-copybutton # for copy button in code blocks # https://anaconda.org/conda-forge/sphinx-copybutton/files + # build process + - sphinx-autobuild # live-html support # https://anaconda.org/conda-forge/sphinx-autobuild/files \ No newline at end of file diff --git a/docs/environment.yml b/docs/environment.yml deleted file mode 100644 index d3b014f..0000000 --- a/docs/environment.yml +++ /dev/null @@ -1,15 +0,0 @@ -name: sphinx_furo -channels: - - conda-forge - - nodefaults -dependencies: - # core functionality - - python=3.11 - - ipython - # sphinx - - sphinx=5.3.0 # sphinx-design currently requires sphinx[version>=2,<5] - - furo=2023.3.27 # website theme - - myst-parser=0.19.1 # Markdown support - - sphinx-autobuild=2021.3.14 # live-html support - - sphinx-autoapi=2.1.0 # to build docs from source code instead of package import - - sphinx-click==4.1.0 # to build docs from click command line interface \ No newline at end of file diff --git a/docs/index.md b/docs/index.md index c25a708..3124b07 100644 --- a/docs/index.md +++ b/docs/index.md @@ -1,24 +1,22 @@ -```{include} ../README.md ---- -end-before: ---- -``` +# Brightway Graph Tools -[license]: license -[contributor guide]: contributing -[command-line reference]: usage -[changelog]: changelog +:::{card} Brightway Graph Tools is a specialized Package of the Brightway Software Framework + +```{button-link} [banana](https://docs.brightway.dev) +:color: info +:expand: +:click-parent: +``` ```{toctree} --- hidden: maxdepth: 1 --- - -pages/usage -Reference -pages/contributing -Code of Conduct -License -Changelog -``` +content/usage +content/api +content/changelog +content/contributing +content/codeofconduct +content/license +``` \ No newline at end of file diff --git a/docs/pages/usage.md b/docs/pages/usage.md deleted file mode 100644 index 3b8614c..0000000 --- a/docs/pages/usage.md +++ /dev/null @@ -1,7 +0,0 @@ -# Usage - -```{eval-rst} -.. click:: bw_graph_tools.cli:run - :prog: bw_graph_tools - :nested: full -``` From 90a3d53b293f4fa72c64146d9444f3c72c525647 Mon Sep 17 00:00:00 2001 From: Michael Weinold <23102087+michaelweinold@users.noreply.github.com> Date: Thu, 2 May 2024 12:50:12 +0200 Subject: [PATCH 2/2] minor edit --- .../api/bw_graph_tools/errors/index.rst | 19 - .../bw_graph_tools/graph_traversal/index.rst | 464 ------------------ .../graph_traversal_utils/index.rst | 45 -- docs/content/api/bw_graph_tools/index.rst | 67 --- .../api/bw_graph_tools/matrix_tools/index.rst | 86 ---- .../bw_graph_tools/shortest_path/index.rst | 127 ----- .../api/bw_graph_tools/testing/index.rst | 34 -- .../api/bw_graph_tools/utils/index.rst | 22 - docs/content/api/index.rst | 11 - docs/index.md | 6 +- 10 files changed, 3 insertions(+), 878 deletions(-) delete mode 100644 docs/content/api/bw_graph_tools/errors/index.rst delete mode 100644 docs/content/api/bw_graph_tools/graph_traversal/index.rst delete mode 100644 docs/content/api/bw_graph_tools/graph_traversal_utils/index.rst delete mode 100644 docs/content/api/bw_graph_tools/index.rst delete mode 100644 docs/content/api/bw_graph_tools/matrix_tools/index.rst delete mode 100644 docs/content/api/bw_graph_tools/shortest_path/index.rst delete mode 100644 docs/content/api/bw_graph_tools/testing/index.rst delete mode 100644 docs/content/api/bw_graph_tools/utils/index.rst delete mode 100644 docs/content/api/index.rst diff --git a/docs/content/api/bw_graph_tools/errors/index.rst b/docs/content/api/bw_graph_tools/errors/index.rst deleted file mode 100644 index 22bb802..0000000 --- a/docs/content/api/bw_graph_tools/errors/index.rst +++ /dev/null @@ -1,19 +0,0 @@ -:py:mod:`bw_graph_tools.errors` -=============================== - -.. py:module:: bw_graph_tools.errors - - -Module Contents ---------------- - -.. py:exception:: UnclearProductionExchange - - - Bases: :py:obj:`Exception` - - Can't guess the production exchange row and column indices - - Initialize self. See help(type(self)) for accurate signature. - - diff --git a/docs/content/api/bw_graph_tools/graph_traversal/index.rst b/docs/content/api/bw_graph_tools/graph_traversal/index.rst deleted file mode 100644 index 361c9fa..0000000 --- a/docs/content/api/bw_graph_tools/graph_traversal/index.rst +++ /dev/null @@ -1,464 +0,0 @@ -:py:mod:`bw_graph_tools.graph_traversal` -======================================== - -.. py:module:: bw_graph_tools.graph_traversal - - -Module Contents ---------------- - -Classes -~~~~~~~ - -.. autoapisummary:: - - bw_graph_tools.graph_traversal.AssumedDiagonalGraphTraversal - bw_graph_tools.graph_traversal.CachingSolver - bw_graph_tools.graph_traversal.Counter - bw_graph_tools.graph_traversal.Edge - bw_graph_tools.graph_traversal.Flow - bw_graph_tools.graph_traversal.NewNodeEachVisitGraphTraversal - bw_graph_tools.graph_traversal.Node - - - - -Attributes -~~~~~~~~~~ - -.. autoapisummary:: - - bw_graph_tools.graph_traversal.databases - - -.. py:class:: AssumedDiagonalGraphTraversal - - - Bases: :py:obj:`NewNodeEachVisitGraphTraversal` - - Traverse a supply chain, following paths of greatest impact. - - This implementation uses a queue of datasets to assess. As the supply chain is traversed, activities are added to a list sorted by LCA score. Each activity in the sorted list is assessed, and added to the supply chain graph, as long as its impact is above a certain threshold, and the maximum number of calculations has not been exceeded. - - Because the next dataset assessed is chosen by its impact, not its position in the graph, this is neither a breadth-first nor a depth-first search, but rather "importance-first". - - This class is written in a functional style, and the class serves mainly to collect methods which belong together. There are only `classmethods` and no state is stored on the class itself. - - Should be used by calling the ``calculate`` method. All other functions should be considered an internal API. - - .. warning:: Graph traversal with multioutput processes only works when other inputs are substituted (see `Multioutput processes in LCA `__ for a description of multiputput process math in LCA). - - - .. py:method:: get_production_exchanges(mapped_matrix: matrix_utils.MappedMatrix) -> (numpy.ndarray, numpy.ndarray) - :classmethod: - - Assume production exchanges are always on the diagonal instead of - examining matrix structure and input data. - - :param mapped_matrix: A matrix and mapping data (from database ids to matrix indices) - from the ``matrix_utils`` library. Normally built automatically by - an ``LCA`` class. Should be the ``technosphere_matrix`` or - equivalent. - :type mapped_matrix: matrix_utils.MappedMatrix - - :returns: The matrix row and column indices of the production exchanges. - :rtype: (numpy.array, numpy.array) - - - -.. py:class:: CachingSolver(lca: bw2calc.LCA) - - - Class which caches expensive linear algebra solution vectors. - - .. py:method:: calculate(index: int) -> numpy.ndarray - - Compute cumulative LCA score for one unit of a given activity - - - -.. py:class:: Counter - - - Custom counter to have easy access to current value - - -.. py:class:: Edge - - - An edge between two *activities*. The `amount` is the amount of the product demanded by the `consumer`. - - :param consumer_index: The matrix column index of the consuming activity - :type consumer_index: int - :param consumer_unique_id: The traversal-specific unique id of the consuming activity - :type consumer_unique_id: int - :param producer_index: The matrix column index of the producing activity - :type producer_index: int - :param producer_unique_id: The traversal-specific unique id of the producing activity - :type producer_unique_id: int - :param product_index: The matrix row index of the consumed product - :type product_index: int - :param amount: The amount of the product demanded by the consumer. Not scaled to producer production amount. - :type amount: float - - .. py:attribute:: amount - :type: float - - - - .. py:attribute:: consumer_index - :type: int - - - - .. py:attribute:: consumer_unique_id - :type: int - - - - .. py:attribute:: producer_index - :type: int - - - - .. py:attribute:: producer_unique_id - :type: int - - - - .. py:attribute:: product_index - :type: int - - - - -.. py:class:: Flow - - - A characterized biosphere flow associated with a given `Node` instance. - - :param flow_datapackage_id: The id that identifies the biosphere flow in the datapackage - :type flow_datapackage_id: int - :param flow_index: The matrix row index of the biosphere flow - :type flow_index: int - :param activity_unique_id: The `Node.unique_id` of this instance of the emitting activity - :type activity_unique_id: int - :param activity_id: The id that identifies the emitting activity in the datapackage - :type activity_id: int - :param activity_index: The matrix column index of the emitting activity - :type activity_index: int - :param amount: The amount of the biosphere flow being emitting by this activity instance - :type amount: float - :param score: The LCIA score for `amount` of this biosphere flow - :type score: float - - .. py:attribute:: activity_id - :type: int - - - - .. py:attribute:: activity_index - :type: int - - - - .. py:attribute:: activity_unique_id - :type: int - - - - .. py:attribute:: amount - :type: float - - - - .. py:attribute:: flow_datapackage_id - :type: int - - - - .. py:attribute:: flow_index - :type: int - - - - .. py:attribute:: score - :type: float - - - - -.. py:class:: NewNodeEachVisitGraphTraversal - - - Traverse a supply chain, following paths of greatest impact. - - This implementation uses a queue of datasets to assess. As the supply chain is traversed, activities are added to a list sorted by LCA score. Each activity in the sorted list is assessed, and added to the supply chain graph, as long as its impact is above a certain threshold, and the maximum number of calculations has not been exceeded. - - Because the next dataset assessed is chosen by its impact, not its position in the graph, this is neither a breadth-first nor a depth-first search, but rather "importance-first". - - This class is written in a functional style, and the class serves mainly to collect methods which belong together. There are only `classmethods` and no state is stored on the class itself. - - Should be used by calling the ``calculate`` method. All other functions should be considered an internal API. - - .. warning:: Graph traversal with multioutput processes only works when other inputs are substituted (see `Multioutput processes in LCA `__ for a description of multiputput process math in LCA). - - - .. py:method:: add_biosphere_flows(flows: list[Flow], matrix: scipy.sparse.spmatrix, lca: bw2calc.LCA, node: Node, biosphere_cutoff_score: float) -> None - :classmethod: - - Add individual biosphere flows as `Flow` instances to `flow` if their score is above `biosphere_cutoff_score`. - - :param flows: List of existing `Flow` instances - :type flows: list - :param matrix: Pre-calculated characterization times biosphere matrix - :type matrix: scipy.sparse.spmatrix - :param lca: LCA class instance - :type lca: bw2calc.LCA - :param node: Node whose direct biosphere flows we are examining - :type node: `Node` - :param biosphere_cutoff_score: Score below which individual characterized biosphere flows are ignored - :type biosphere_cutoff_score: float - - :returns: Modifies `flows` by adding new `Flow` instances - :rtype: `None` - - - .. py:method:: calculate(lca_object: bw2calc.LCA, cutoff: float | None = 0.005, biosphere_cutoff: float | None = 0.0001, max_calc: int | None = 100000.0, skip_coproducts: bool | None = False, separate_biosphere_flows: bool | None = True, static_activity_indices: set[int] | None = set(), functional_unit_unique_id: int | None = -1) -> dict - :classmethod: - - Priority-first traversal (i.e. follow the past of highest score) of the supply chain graph. This class unrolls - the graph, i.e. every time it arrives at a given activity, it treats - it as a separate node in the graph. - - In contrast with previous graph traversal implementations, we do not assume reference production exchanges are on the diagonal. It should also correctly handle the following: - - * Functional unit has more than one link to a given product - * Non-unitary reference production amounts - * Negative reference production amounts - * Co-production edge traversal, if desired. Requires co-products to be substituted (can be implicit substitution). - - You must provide an `lca_object` which is already instantiated, and for which you have already done LCI and LCIA calculations. The `lca_object` does not have to be an instance of `bw2calc.LCA`, but it needs to support the following methods and attributes: - - * `technosphere_matrix` - * `technosphere_mm` - * `solve_linear_system()` - * `demand` - * `demand_array` - - You can subclass `NewNodeEachVisitGraphTraversal` and redefine `get_characterized_biosphere` if your LCA class does not have a traditional `characterization_matrix` and `biosphere_matrix`. - - The return object is a dictionary with four values. The `nodes` is a dictionary of visited **activities**; the keys in this dictionary are unique increasing integer ids (not related to any other ids or indices), and values are instances of the `Node` dataclass. Each `Node` has a `unique_id`, as every time we arrive at an activity (even if we have seen it before via another branch of the supply chain), we create a new `Node` object with a unique id. See the `Node` documentation for its other attributes. - - edges - - flows - - Finally, `calculation_count` gives the total number of inventory calculations performed. - - Without further manipulation, the results will have double counting if you add all scores together. Specifically, each `Node` has both a `cumulative_score` and a `direct_emissions_score`; the direct emissions are counted in both scores. Use XXX to subtract `direct_emissions_score` from `cumulative_score`. Moreover, the `direct_emissions_score` includes all characterized flows, but important flows can also be listed separately as `Flow` objects. Use XXX to subtract specific `Flows` from the `direct_emissions_score`. - - :param lca_object: Already instantiated `LCA` object with inventory and impact - assessment calculated. - :type lca_object: bw2calc.LCA - :param cutoff: Cutoff value used to stop graph traversal. Fraction of total score, - should be in `(0, 1)` - :type cutoff: float - :param biosphere_cutoff: Cutoff value used to determine if a separate biosphere node is - added. Fraction of total score. - :type biosphere_cutoff: float - :param max_calc: Maximum number of inventory calculations to perform - :type max_calc: int - :param skip_coproducts: Don't traverse co-production edges, i.e. production edges other - than the reference product - :type skip_coproducts: bool - :param separate_biosphere_flows: Add separate `Flow` nodes for important individual biosphere - emissions - :type separate_biosphere_flows: bool - :param static_activity_indices: A set of activity matrix indices which we don't want the graph to - traverse - :type static_activity_indices: set - :param functional_unit_unique_id: An integer id we can use for the functional unit virtual activity. - Shouldn't overlap any other activity ids. Don't change unless you - really know what you are doing. - :type functional_unit_unique_id: int - - :returns: Dictionary with keys `nodes`, `edges`, `flows`, `calculation_counter` - :rtype: dict - - - .. py:method:: get_characterized_biosphere(lca: bw2calc.LCA) -> scipy.sparse.spmatrix - :classmethod: - - Pre-calculate the characterized biosphere matrix. - - Broken out as a separate method because subclasses like regionalized - LCA could have more complicated characterization. - - :param lca: LCA class instance - :type lca: bw2calc.LCA - - :returns: Unmapped matrix of biosphere flows by activities. - :rtype: scipy.sparse.spmatrix - - - .. py:method:: get_demand_vector_for_activity(node: Node, skip_coproducts: bool, matrix: scipy.sparse.spmatrix) -> (list[int], list[float]) - :classmethod: - - Get input matrix indices and amounts for a given activity. Ignores the reference production exchanges and optionally other co-production exchanges. - - :param node: Activity whose inputs we are iterating over - :type node: `Node` - :param skip_coproducts: Whether or not to ignore positive production exchanges other than the reference product, which is always ignored - :type skip_coproducts: bool - :param matrix: Technosphere matrix - :type matrix: scipy.sparse.spmatrix - - :returns: * **row indices** (*list*) -- Integer row indices for products consumed by `Node` - * **amounts** (*list*) -- The amount of each product consumed, scaled to `Node.supply_amount`. Same order as row indices. - - - .. py:method:: get_production_exchanges(mapped_matrix: matrix_utils.MappedMatrix) -> (numpy.array, numpy.array) - :classmethod: - - Get matrix row and column indices of productions exchanges by trying a - series of heuristics. See documentation for - ``guess_production_exchanges``. - - Broken out as a separate method because subclasses could change this logic. - - :param mapped_matrix: A matrix and mapping data (from database ids to matrix indices) - from the ``matrix_utils`` library. Normally built automatically by - an ``LCA`` class. Should be the ``technosphere_matrix`` or - equivalent. - :type mapped_matrix: matrix_utils.MappedMatrix - - :returns: The matrix row and column indices of the production exchanges. - :rtype: (numpy.array, numpy.array) - - - .. py:method:: traverse(heap: list, nodes: dict[Node], edges: list[Edge], flows: list[Flow], max_calc: int, cutoff_score: float, characterized_biosphere: scipy.sparse.spmatrix, calculation_count: Counter, static_activity_indices: set, production_exchange_mapping: dict[int, int], technosphere_matrix: scipy.sparse.spmatrix, lca: bw2calc.LCA, caching_solver: CachingSolver, skip_coproducts: bool, separate_biosphere_flows: bool, biosphere_cutoff_score: float) -> None - :classmethod: - - Perform the graph traversal from the initial functional unit edges. - - :param heap: The `heapq` list of nodes to traverse - :type heap: list - :param nodes: Dictionary of already visited `Nodes` - :type nodes: dict - :param edges: List of visited `Edges` - :type edges: list - :param flows: List of significant seen `Flows` - :type flows: list - :param max_calc: Maximum number of inventory calculations to perform - :type max_calc: int - :param cutoff_score: Score below which graph edges are ignored. We always consider the absolute value of edges scores. - :type cutoff_score: float - :param characterized_biosphere: The pre-calculated characterization time biosphere matrix - :type characterized_biosphere: spmatrix - :param calculation_count: Counter object tracking number of lci calculations - :type calculation_count: `Counter` - :param static_activity_indices: A set of activity matrix indices which we don't want the graph to - traverse - :type static_activity_indices: set - :param production_exchange_mapping: Mapping of product matrix row indices to the activity matrix column indices for which they are reference products - :type production_exchange_mapping: dict - :param technosphere_matrix: LCA technosphere matrix - :type technosphere_matrix: scipy.sparse.spmatrix - :param lca: Already instantiated `LCA` object with inventory and impact - assessment calculated. - :type lca: bw2calc.LCA - :param caching_solver: Solver which caches solutions to linear algebra problems - :type caching_solver: `CachingSolver` - :param skip_coproducts: Don't traverse co-production edges, i.e. production edges other - than the reference product - :type skip_coproducts: bool - :param separate_biosphere_flows: Add separate `Flow` nodes for important individual biosphere - emissions - :type separate_biosphere_flows: bool - :param biosphere_cutoff_score: Score below which individual biosphere flows are not added to `flows` - :type biosphere_cutoff_score: float - - :returns: Modifies `heap`, `nodes`, `edges`, and `flows` in-place - :rtype: `None` - - - .. py:method:: traverse_edges(consumer_index: int, consumer_unique_id: int, product_indices: list[int], product_amounts: list[float], lca: bw2calc.LCA, calculation_count: Counter, characterized_biosphere: scipy.sparse.spmatrix, matrix: scipy.sparse.spmatrix, edges: list[Edge], flows: list[Flow], nodes: list[Node], heap: list, production_exchange_mapping: dict[int, int], static_activity_indices: set[int], separate_biosphere_flows: bool, caching_solver: CachingSolver, biosphere_cutoff_score: float, cutoff_score: float) -> None - :classmethod: - - - -.. py:class:: Node - - - A visited activity in a supply chain graph. Although our graph is cyclic, we treat each activity as a separate node every time we visit it. - - :param unique_id: A unique integer id for this visit to this activity node - :type unique_id: int - :param activity_datapackage_id: The id that identifies this activity in the datapackage, and hence in the database - :type activity_datapackage_id: int - :param activity_index: The technosphere matrix column index of this activity - :type activity_index: int - :param reference_product_datapackage_id: The id that identifies the reference product of this activity in the datapackage - :type reference_product_datapackage_id: int - :param reference_product_index: The technosphere matrix row index of this activity's reference product - :type reference_product_index: int - :param reference_product_production_amount: The *net* production amount of this activity's reference product - :type reference_product_production_amount: float - :param supply_amount: The amount of the *activity* (not reference product!) needed to supply the demand from the requesting supply chain edge. - :type supply_amount: float - :param cumulative_score: Total LCIA score attributed to `supply_amount` of this activity. Includes direct emissions unless explicitly removed. - :type cumulative_score: float - :param direct_emissions_score: Total LCIA score attributed only to the direct characterized biosphere flows of `supply_amount` of this activity. - :type direct_emissions_score: float - - .. py:attribute:: activity_datapackage_id - :type: int - - - - .. py:attribute:: activity_index - :type: int - - - - .. py:attribute:: cumulative_score - :type: float - - - - .. py:attribute:: direct_emissions_score - :type: float - - - - .. py:attribute:: reference_product_datapackage_id - :type: int - - - - .. py:attribute:: reference_product_index - :type: int - - - - .. py:attribute:: reference_product_production_amount - :type: float - - - - .. py:attribute:: supply_amount - :type: float - - - - .. py:attribute:: unique_id - :type: int - - - - -.. py:data:: databases - - - diff --git a/docs/content/api/bw_graph_tools/graph_traversal_utils/index.rst b/docs/content/api/bw_graph_tools/graph_traversal_utils/index.rst deleted file mode 100644 index 006a94c..0000000 --- a/docs/content/api/bw_graph_tools/graph_traversal_utils/index.rst +++ /dev/null @@ -1,45 +0,0 @@ -:py:mod:`bw_graph_tools.graph_traversal_utils` -============================================== - -.. py:module:: bw_graph_tools.graph_traversal_utils - - -Module Contents ---------------- - - -Functions -~~~~~~~~~ - -.. autoapisummary:: - - bw_graph_tools.graph_traversal_utils.get_path_from_matrix - bw_graph_tools.graph_traversal_utils.path_as_brightway_objects - - - -Attributes -~~~~~~~~~~ - -.. autoapisummary:: - - bw_graph_tools.graph_traversal_utils.brightway_available - - -.. py:function:: get_path_from_matrix(matrix: scipy.sparse.spmatrix, source: int, target: int, algorithm: str = 'BF') -> List - - Get the path with the most mass or energetic flow from ``source`` (the function unit) to ``target`` (something deep in the supply chain). Both ``source`` and ``target`` are integer matrix indices. - - ``algorithm`` should be either ``BF`` (Bellman-Ford) or ``J`` (Johnson). Dijkstra is not recommended as we have negative weights. - - Returns a list like ``[source, int, int, int, target]``. - - -.. py:function:: path_as_brightway_objects(source_node: bw2data.Node, target_node: bw2data.Node, lca: Optional[bw2calc.LCA] = None) -> List[bw2data.Edge] - - -.. py:data:: brightway_available - :value: True - - - diff --git a/docs/content/api/bw_graph_tools/index.rst b/docs/content/api/bw_graph_tools/index.rst deleted file mode 100644 index 93b65d3..0000000 --- a/docs/content/api/bw_graph_tools/index.rst +++ /dev/null @@ -1,67 +0,0 @@ -:py:mod:`bw_graph_tools` -======================== - -.. py:module:: bw_graph_tools - - -Submodules ----------- -.. toctree:: - :titlesonly: - :maxdepth: 1 - - errors/index.rst - graph_traversal/index.rst - graph_traversal_utils/index.rst - matrix_tools/index.rst - shortest_path/index.rst - testing/index.rst - utils/index.rst - - -Package Contents ----------------- - -Classes -~~~~~~~ - -.. autoapisummary:: - - bw_graph_tools.AssumedDiagonalGraphTraversal - bw_graph_tools.Edge - bw_graph_tools.Flow - bw_graph_tools.NewNodeEachVisitGraphTraversal - bw_graph_tools.Node - - - -Functions -~~~~~~~~~ - -.. autoapisummary:: - - bw_graph_tools.get_path_from_matrix - bw_graph_tools.guess_production_exchanges - bw_graph_tools.path_as_brightway_objects - bw_graph_tools.to_normalized_adjacency_matrix - - - -Attributes -~~~~~~~~~~ - -.. autoapisummary:: - - bw_graph_tools.__version__ - - - - - - - - - - - - diff --git a/docs/content/api/bw_graph_tools/matrix_tools/index.rst b/docs/content/api/bw_graph_tools/matrix_tools/index.rst deleted file mode 100644 index 5eedf54..0000000 --- a/docs/content/api/bw_graph_tools/matrix_tools/index.rst +++ /dev/null @@ -1,86 +0,0 @@ -:py:mod:`bw_graph_tools.matrix_tools` -===================================== - -.. py:module:: bw_graph_tools.matrix_tools - - -Module Contents ---------------- - - -Functions -~~~~~~~~~ - -.. autoapisummary:: - - bw_graph_tools.matrix_tools.gpe_first_heuristic - bw_graph_tools.matrix_tools.gpe_second_heuristic - bw_graph_tools.matrix_tools.gpe_third_heuristic - bw_graph_tools.matrix_tools.guess_production_exchanges - bw_graph_tools.matrix_tools.reorder_mapped_matrix - bw_graph_tools.matrix_tools.to_normalized_adjacency_matrix - - - -.. py:function:: gpe_first_heuristic(mm: matrix_utils.MappedMatrix) -> Tuple[numpy.ndarray, numpy.ndarray] - - Use first heuristic (same input and output ids) to find production exchange indices. - - If we treat activities and products the same, then an exchange with the row and column id - is definitely a production exchange location. We don't care if there are duplicates (e.g. - production and some loss), we will return unique pairs. - - If activities have different ids than products, this won't find anything. - - Returns a tuple of numpy integer matrix indices, rows by columns. - - -.. py:function:: gpe_second_heuristic(mm: matrix_utils.MappedMatrix, row_existing: numpy.ndarray, col_existing: numpy.ndarray) -> Tuple[numpy.ndarray, numpy.ndarray] - - -.. py:function:: gpe_third_heuristic(mm: matrix_utils.MappedMatrix, row_existing: numpy.ndarray, col_existing: numpy.ndarray) -> Tuple[numpy.ndarray, numpy.ndarray] - - -.. py:function:: guess_production_exchanges(mm: matrix_utils.MappedMatrix) -> Tuple[numpy.ndarray, numpy.ndarray] - - Try to guess productions exchanges in a mapped technosphere matrix using heuristics from the input data packages. - - Try the following in order per activity (column): - - * Same input and output index - * Single value where ``flip`` is negative - * Single positive value - - Raises ``UnclearProductionExchange`` if these conditions are not met for any activity. - - Returns integer arrays of the matrix row and column indices where production exchanges were found. - - - -.. py:function:: reorder_mapped_matrix(matrix: matrix_utils.MappedMatrix) -> scipy.sparse.csr_matrix - - -.. py:function:: to_normalized_adjacency_matrix(matrix: scipy.sparse.spmatrix, log_transform: bool = True) -> scipy.sparse.csr_matrix - - Take a technosphere matrix constructed with Brightway conventions, and return a normalized adjacency matrix. - - In the adjacency matrix A, `A[i,j]` indicates a directed edge **from** row `i` **to** column `j`. However, - this is the opposite of what we normally want, which is to find a path from the functional activity to - somewhere in its supply chain. In a Brightway technosphere matrix, `A[i,j]` means **activity** `j` consumes - the output of activity `i`. To go down the supply chain, however, we would need to go from ``j`` to ``i``. - Therefore, we take the transpose of the technosphere matrix. - - Normalization is done to remove the effect of activities which don't produce one unit of their reference product. - For example, if activity `foo` produces two units of `bar` and consumes two units of `baz`, the weight of the - `baz` edge should be :math:`2 / 2 = 1`. - - In addition to this normalization, we subtract the diagonal and flip the signs of all matrix values. Flipping - the sign is needed because we want to use a shortest path algorithm, but actually want the longest path. The - longest path is the path with the highest weight, i.e. the path where the most consumption occurs on. - - By default, we also take the natural log of the data values. This is because our supply chain is multiplicative, - not additive, and :math:`a \cdot b = e^{\ln(a) + \ln(b)}`. The idea of using the log was borrowed from `David Richardby on Stack Overflow `__. - - Assumes that production amounts are on the diagonal. - - diff --git a/docs/content/api/bw_graph_tools/shortest_path/index.rst b/docs/content/api/bw_graph_tools/shortest_path/index.rst deleted file mode 100644 index 27993dd..0000000 --- a/docs/content/api/bw_graph_tools/shortest_path/index.rst +++ /dev/null @@ -1,127 +0,0 @@ -:py:mod:`bw_graph_tools.shortest_path` -====================================== - -.. py:module:: bw_graph_tools.shortest_path - -.. autoapi-nested-parse:: - - Created on November 12, 2019 - @author: Quentin Lutz - From scikit-network version 0.30 - - BSD License - - Copyright (c) 2018, Scikit-network Developers - Bertrand Charpentier - Thomas Bonald - All rights reserved. - - Redistribution and use in source and binary forms, with or without modification, - are permitted provided that the following conditions are met: - - * Redistributions of source code must retain the above copyright notice, this - list of conditions and the following disclaimer. - - * Redistributions in binary form must reproduce the above copyright notice, this - list of conditions and the following disclaimer in the documentation and/or - other materials provided with the distribution. - - * Neither the name of the copyright holder nor the names of its - contributors may be used to endorse or promote products derived from this - software without specific prior written permission. - - THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND - ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED - WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. - IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, - INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, - BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, - DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY - OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE - OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED - OF THE POSSIBILITY OF SUCH DAMAGE. - - - -Module Contents ---------------- - - -Functions -~~~~~~~~~ - -.. autoapisummary:: - - bw_graph_tools.shortest_path.get_distances - bw_graph_tools.shortest_path.get_shortest_path - - - -.. py:function:: get_distances(adjacency: scipy.sparse.csr_matrix, sources: Optional[Union[int, Iterable]] = None, method: str = 'D', return_predecessors: bool = False, unweighted: bool = False, n_jobs: Optional[int] = None) - - Compute distances between nodes. - - * Graphs - * Digraphs - - - Based on SciPy (scipy.sparse.csgraph.shortest_path) - - :param adjacency: The adjacency matrix of the graph - :param sources: If specified, only compute the paths for the points at the given indices. Will not work with ``method =='FW'``. - :param method: The method to be used. - - * ``'D'`` (Dijkstra), - * ``'BF'`` (Bellman-Ford), - * ``'J'`` (Johnson). - :param return_predecessors: If ``True``, the size predecessor matrix is returned - :param unweighted: If ``True``, the weights of the edges are ignored - :param n_jobs: If an integer value is given, denotes the number of workers to use (-1 means the maximum number will be used). - If ``None``, no parallel computations are made. - - :returns: * **dist_matrix** (*np.ndarray*) -- Matrix of distances between nodes. ``dist_matrix[i,j]`` gives the shortest - distance from the ``i``-th source to node ``j`` in the graph (infinite if no path exists - from the ``i``-th source to node ``j``). - * **predecessors** (*np.ndarray, optional*) -- Returned only if ``return_predecessors == True``. The matrix of predecessors, which can be used to reconstruct - the shortest paths. Row ``i`` of the predecessor matrix contains information on the shortest paths from the - ``i``-th source: each entry ``predecessors[i, j]`` gives the index of the previous node in the path from - the ``i``-th source to node ``j`` (-1 if no path exists from the ``i``-th source to node ``j``). - - -.. py:function:: get_shortest_path(adjacency: scipy.sparse.csr_matrix, sources: Union[int, Iterable], targets: Union[int, Iterable], method: str = 'D', unweighted: bool = False, n_jobs: Optional[int] = None) - - Compute the shortest paths in the graph. - - :param adjacency: The adjacency matrix of the graph - :param sources: Sources nodes. - :type sources: int or iterable - :param targets: Target nodes. - :type targets: int or iterable - :param method: The method to be used. - - * ``'D'`` (Dijkstra), - * ``'BF'`` (Bellman-Ford), - * ``'J'`` (Johnson). - :param unweighted: If ``True``, the weights of the edges are ignored - :param n_jobs: If an integer value is given, denotes the number of workers to use (-1 means the maximum number will be used). - If ``None``, no parallel computations are made. - - :returns: **paths** -- If single source and single target, return a list containing the nodes on the path from source to target. - If multiple sources or multiple targets, return a list of paths as lists. - An empty list means that the path does not exist. - :rtype: list - - .. rubric:: Examples - - >>> from sknetwork.data import linear_digraph - >>> adjacency = linear_digraph(3) - >>> get_shortest_path(adjacency, 0, 2) - [0, 1, 2] - >>> get_shortest_path(adjacency, 2, 0) - [] - >>> get_shortest_path(adjacency, 0, [1, 2]) - [[0, 1], [0, 1, 2]] - >>> get_shortest_path(adjacency, [0, 1], 2) - [[0, 1, 2], [1, 2]] - - diff --git a/docs/content/api/bw_graph_tools/testing/index.rst b/docs/content/api/bw_graph_tools/testing/index.rst deleted file mode 100644 index 1b16d1a..0000000 --- a/docs/content/api/bw_graph_tools/testing/index.rst +++ /dev/null @@ -1,34 +0,0 @@ -:py:mod:`bw_graph_tools.testing` -================================ - -.. py:module:: bw_graph_tools.testing - - -Module Contents ---------------- - - -Functions -~~~~~~~~~ - -.. autoapisummary:: - - bw_graph_tools.testing.edge_equal_dict - bw_graph_tools.testing.equal_dict - bw_graph_tools.testing.flow_equal_dict - bw_graph_tools.testing.node_equal_dict - - - -.. py:function:: edge_equal_dict(a: bw_graph_tools.Edge, b: dict) - - -.. py:function:: equal_dict(a: bw_graph_tools.Node | bw_graph_tools.Edge | bw_graph_tools.Flow, b: dict, fields: list[str]) - - -.. py:function:: flow_equal_dict(a: bw_graph_tools.Flow, b: dict) - - -.. py:function:: node_equal_dict(a: bw_graph_tools.Node, b: dict) - - diff --git a/docs/content/api/bw_graph_tools/utils/index.rst b/docs/content/api/bw_graph_tools/utils/index.rst deleted file mode 100644 index a30f69d..0000000 --- a/docs/content/api/bw_graph_tools/utils/index.rst +++ /dev/null @@ -1,22 +0,0 @@ -:py:mod:`bw_graph_tools.utils` -============================== - -.. py:module:: bw_graph_tools.utils - - -Module Contents ---------------- - - -Functions -~~~~~~~~~ - -.. autoapisummary:: - - bw_graph_tools.utils.get_version_tuple - - - -.. py:function:: get_version_tuple() -> tuple - - diff --git a/docs/content/api/index.rst b/docs/content/api/index.rst deleted file mode 100644 index 4e0628b..0000000 --- a/docs/content/api/index.rst +++ /dev/null @@ -1,11 +0,0 @@ -API Reference -============= - -This page contains auto-generated API reference documentation [#f1]_. - -.. toctree:: - :titlesonly: - - /content/api/bw_graph_tools/index - -.. [#f1] Created with `sphinx-autoapi `_ \ No newline at end of file diff --git a/docs/index.md b/docs/index.md index 3124b07..65adda7 100644 --- a/docs/index.md +++ b/docs/index.md @@ -1,11 +1,10 @@ # Brightway Graph Tools -:::{card} Brightway Graph Tools is a specialized Package of the Brightway Software Framework - -```{button-link} [banana](https://docs.brightway.dev) +```{button-link} https://docs.brightway.dev :color: info :expand: :click-parent: +{octicon}`light-bulb;1em` Brightway Graph Tools is a specialized package of the Brightway Software Framework ``` ```{toctree} @@ -13,6 +12,7 @@ hidden: maxdepth: 1 --- +self content/usage content/api content/changelog