{"id":16890931,"url":"https://github.com/alandefreitas/pareto","last_synced_at":"2025-07-22T17:35:12.071Z","repository":{"id":38401144,"uuid":"263446185","full_name":"alandefreitas/pareto","owner":"alandefreitas","description":"Spatial Containers, Pareto Fronts, and Pareto Archives","archived":false,"fork":false,"pushed_at":"2024-06-11T09:44:26.000Z","size":13669,"stargazers_count":97,"open_issues_count":3,"forks_count":8,"subscribers_count":3,"default_branch":"master","last_synced_at":"2025-04-11T14:12:42.942Z","etag":null,"topics":["decision-making","dimensional-fronts","dominance","multiobjective-optimization","optimization","pareto-archives","pareto-front","spatial-data"],"latest_commit_sha":null,"homepage":"https://alandefreitas.github.io/pareto/","language":"C++","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"mit","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/alandefreitas.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":".github/FUNDING.yml","license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null},"funding":{"github":null,"patreon":"modernhpc","open_collective":null,"ko_fi":null,"tidelift":null,"community_bridge":null,"liberapay":null,"issuehunt":null,"otechie":null,"custom":null}},"created_at":"2020-05-12T20:34:41.000Z","updated_at":"2025-02-13T16:11:31.000Z","dependencies_parsed_at":"2024-10-27T12:13:12.179Z","dependency_job_id":"58ade911-5bf0-4efd-a70d-d119eb2bad0a","html_url":"https://github.com/alandefreitas/pareto","commit_stats":null,"previous_names":[],"tags_count":3,"template":false,"template_full_name":null,"purl":"pkg:github/alandefreitas/pareto","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/alandefreitas%2Fpareto","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/alandefreitas%2Fpareto/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/alandefreitas%2Fpareto/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/alandefreitas%2Fpareto/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/alandefreitas","download_url":"https://codeload.github.com/alandefreitas/pareto/tar.gz/refs/heads/master","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/alandefreitas%2Fpareto/sbom","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":266540254,"owners_count":23945187,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","status":"online","status_checked_at":"2025-07-22T02:00:09.085Z","response_time":66,"last_error":null,"robots_txt_status":null,"robots_txt_updated_at":null,"robots_txt_url":"https://github.com/robots.txt","online":true,"can_crawl_api":true,"host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["decision-making","dimensional-fronts","dominance","multiobjective-optimization","optimization","pareto-archives","pareto-front","spatial-data"],"created_at":"2024-10-13T17:04:59.629Z","updated_at":"2025-07-22T17:35:12.045Z","avatar_url":"https://github.com/alandefreitas.png","language":"C++","funding_links":["https://patreon.com/modernhpc"],"categories":[],"sub_categories":[],"readme":"# Pareto\n\n\u003e Spatial Containers, Pareto Fronts, and Pareto Archives\n\n[![Two-dimensional front](docs/img/pareto_cover.svg)](https://alandefreitas.github.io/pareto/)\n\n\u003cbr/\u003e\n\nWhile most problems need to simultaneously organize objects according to many criteria, associative containers can only index objects in a single dimension. This library provides a number of containers with optimal asymptotic complexity to represent multi-dimensional associative containers. \n\nThese containers are useful in many applications such as games, maps, nearest neighbor search, range search, compression algorithms, statistics, mechanics, graphics libraries, database queries, finance, multi-criteria decision making, optimization, machine learning, hyper-parameter tuning, approximation algorithms, networks, routing algorithms, robust optimization, design, and systems control.\n\n\u003cbr/\u003e\n\n[![Build Status](https://img.shields.io/github/workflow/status/alandefreitas/pareto/Pareto?event=push\u0026label=Build\u0026logo=Github-Actions)](https://github.com/alandefreitas/pareto/actions?query=workflow%3APareto+event%3Apush)\n[![Latest Release](https://img.shields.io/github/release/alandefreitas/pareto.svg?label=Download)](https://GitHub.com/alandefreitas/pareto/releases/)\n[![Documentation](https://img.shields.io/website-up-down-green-red/http/alandefreitas.github.io/pareto.svg?label=Documentation)](https://alandefreitas.github.io/pareto/)\n[![Documentation](https://img.shields.io/website-up-down-green-red/http/alandefreitas.github.io/pareto.svg?label=CodeDocs)](https://codedocs.xyz/alandefreitas/pareto/)\n[![Discussions](https://img.shields.io/website-up-down-green-red/http/alandefreitas.github.io/pareto.svg?label=Discussions)](https://github.com/alandefreitas/pareto/discussions)\n\n\u003cbr/\u003e\n\n\u003c!-- https://github.com/bradvin/social-share-urls --\u003e\n[![Facebook](https://img.shields.io/twitter/url/http/shields.io.svg?style=social\u0026label=Share+on+Facebook\u0026logo=facebook)](https://www.facebook.com/sharer/sharer.php?t=Pareto%20Fronts%20and%20Archives%20/%20C%2B%2B%20and%20Python\u0026u=https://github.com/alandefreitas/pareto/)\n[![QZone](https://img.shields.io/twitter/url/http/shields.io.svg?style=social\u0026label=Share+on+QZone\u0026logo=qzone)](http://sns.qzone.qq.com/cgi-bin/qzshare/cgi_qzshare_onekey?url=https://github.com/alandefreitas/pareto/\u0026title=Pareto%20Fronts%20and%20Archives%20/%20C%2B%2B%20and%20Python\u0026summary=Pareto%20Fronts%20and%20Archives%20/%20C%2B%2B%20and%20Python)\n[![Weibo](https://img.shields.io/twitter/url/http/shields.io.svg?style=social\u0026label=Share+on+Weibo\u0026logo=sina-weibo)](http://sns.qzone.qq.com/cgi-bin/qzshare/cgi_qzshare_onekey?url=https://github.com/alandefreitas/pareto/\u0026title=Pareto%20Fronts%20and%20Archives%20/%20C%2B%2B%20and%20Python\u0026summary=Pareto%20Fronts%20and%20Archives%20/%20C%2B%2B%20and%20Python)\n[![Reddit](https://img.shields.io/twitter/url/http/shields.io.svg?style=social\u0026label=Share+on+Reddit\u0026logo=reddit)](http://www.reddit.com/submit?url=https://github.com/alandefreitas/pareto/\u0026title=Pareto%20Fronts%20and%20Archives%20/%20C%2B%2B%20and%20Python)\n[![Twitter](https://img.shields.io/twitter/url/http/shields.io.svg?label=Share+on+Twitter\u0026style=social)](https://twitter.com/intent/tweet?text=Pareto%20Fronts%20and%20Archives%20/%20C%2B%2B%20and%20Python\u0026url=https://github.com/alandefreitas/pareto/\u0026hashtags=MOO,MultiObjectiveOptimization,Cpp,ScientificComputing,Optimization,Developers)\n[![LinkedIn](https://img.shields.io/twitter/url/http/shields.io.svg?style=social\u0026label=Share+on+LinkedIn\u0026logo=linkedin)](https://www.linkedin.com/shareArticle?mini=false\u0026url=https://github.com/alandefreitas/pareto/\u0026title=Pareto%20Fronts%20and%20Archives%20/%20C%2B%2B%20and%20Python)\n[![WhatsApp](https://img.shields.io/twitter/url/http/shields.io.svg?style=social\u0026label=Share+on+WhatsApp\u0026logo=whatsapp)](https://api.whatsapp.com/send?text=Pareto%20Fronts%20and%20Archives%20/%20C%2B%2B%20and%20Python:+https://github.com/alandefreitas/pareto/)\n[![Line.me](https://img.shields.io/twitter/url/http/shields.io.svg?style=social\u0026label=Share+on+Line.me\u0026logo=line)](https://lineit.line.me/share/ui?url=https://github.com/alandefreitas/pareto/\u0026text=Pareto%20Fronts%20and%20Archives%20/%20C%2B%2B%20and%20Python)\n[![Telegram.me](https://img.shields.io/twitter/url/http/shields.io.svg?style=social\u0026label=Share+on+Telegram.me\u0026logo=telegram)](https://telegram.me/share/url?url=https://github.com/alandefreitas/pareto/\u0026text=Pareto%20Fronts%20and%20Archives%20/%20C%2B%2B%20and%20Python)\n[![HackerNews](https://img.shields.io/twitter/url/http/shields.io.svg?style=social\u0026label=Share+on+HackerNews\u0026logo=y-combinator)](https://news.ycombinator.com/submitlink?u=https://github.com/alandefreitas/pareto/\u0026t=Pareto%20Fronts%20and%20Archives%20/%20C%2B%2B%20and%20Python)\n\n\u003cbr/\u003e\n\n\u003c!-- START mdsplit-ignore --\u003e\n\n\u003ch2\u003e\n\n[READ THE DOCUMENTATION FOR A QUICK START](https://alandefreitas.github.io/pareto/)\n\n\u003c/h2\u003e\n\n\u003c!-- START doctoc generated TOC please keep comment here to allow auto update --\u003e\n\u003c!-- DON'T EDIT THIS SECTION, INSTEAD RE-RUN doctoc TO UPDATE --\u003e\n\u003cdetails\u003e\n\u003csummary\u003eTable of Contents\u003c/summary\u003e\n\n- [Quick start](#quick-start)\n  - [Spatial Containers](#spatial-containers)\n  - [Front Container](#front-container)\n  - [Archive Container](#archive-container)\n  - [Interfaces](#interfaces)\n  - [Performance](#performance)\n- [Integration](#integration)\n  - [C++](#c)\n  - [Python](#python)\n  - [Installing](#installing)\n  - [Building](#building)\n- [Spatial Containers](#spatial-containers-1)\n  - [Containers](#containers)\n  - [Types](#types)\n  - [Constructors](#constructors)\n  - [Allocators](#allocators)\n  - [Element Access](#element-access)\n  - [Iterators](#iterators)\n  - [Capacity and Reference Points](#capacity-and-reference-points)\n  - [Modifiers](#modifiers)\n  - [Lookup and Queries](#lookup-and-queries)\n  - [Observers](#observers)\n  - [Relational Operators](#relational-operators)\n- [Front Container](#front-container-1)\n  - [Front Concept](#front-concept)\n  - [Types](#types-1)\n  - [Constructors](#constructors-1)\n  - [Allocators](#allocators-1)\n  - [Element Access](#element-access-1)\n  - [Iterators](#iterators-1)\n  - [Capacity and Reference Points](#capacity-and-reference-points-1)\n  - [Dominance Relationships](#dominance-relationships)\n  - [Indicators](#indicators)\n  - [Modifiers](#modifiers-1)\n  - [Lookup and Queries](#lookup-and-queries-1)\n  - [Observers](#observers-1)\n  - [Relational Operators](#relational-operators-1)\n- [Archive Container](#archive-container-1)\n  - [Archive Concept](#archive-concept)\n  - [Types](#types-2)\n  - [Constructors](#constructors-2)\n  - [Allocators](#allocators-2)\n  - [Element Access](#element-access-2)\n  - [Iterators](#iterators-2)\n  - [Capacity and Reference Points](#capacity-and-reference-points-2)\n  - [Dominance Relationships](#dominance-relationships-1)\n  - [Indicators](#indicators-1)\n  - [Modifiers](#modifiers-2)\n  - [Lookup and Queries](#lookup-and-queries-2)\n  - [Observers](#observers-2)\n  - [Relational Operators](#relational-operators-2)\n- [Benchmarks](#benchmarks)\n  - [Construct](#construct)\n  - [Insert](#insert)\n  - [Erase](#erase)\n  - [Dominance](#dominance)\n  - [Query Intersection](#query-intersection)\n  - [Query Nearest](#query-nearest)\n  - [IGD indicator](#igd-indicator)\n  - [Hypervolume indicator](#hypervolume-indicator)\n- [Contributing](#contributing)\n  - [Ideas](#ideas)\n  - [Contributing Guidelines](#contributing-guidelines)\n  - [Contributors](#contributors)\n  - [Thanks](#thanks)\n- [References](#references)\n\n\u003c/details\u003e\n\u003c!-- END doctoc generated TOC please keep comment here to allow auto update --\u003e\n\n\u003c!-- END mdsplit-ignore --\u003e\n\n\n## Quick start\n\n### Spatial Containers\n\nThis library defines and implements **spatial containers**, which are an extension of the *AssociativeContainer* named requirement for multi-dimensional containers:\n\n=== \"C++\"\n\n    ```cpp hl_lines=\"4\"\n    // Unidimensional associative container \n    std::map\u003cdouble, unsigned\u003e m;\n    // Multidimensional associative container\n    pareto::spatial_map\u003cdouble, 3, unsigned\u003e n;\n    ```\n\n=== \"Python\"\n\n    ```python hl_lines=\"4\"\n    # Unidimensional associative container\n    m = sortedcontainers.SortedDict()\n    # Multidimensional associative container\n    n = pareto.spatial_map(3)\n    ```\n\nSpatial containers allow you to later find its elements with query iterators:\n\n=== \"C++\"\n\n    ```cpp\n    spatial_map\u003cdouble, 2, unsigned\u003e m;\n    m(-2.5, -1.5) = 17;\n    m(-2.1, -0.5) = 32;\n    m(-1.6, 0.9) = 36;\n    m(-0.6, 0.9) = 13;\n    m(-0.5, 0.8) = 32;\n    std::cout \u003c\u003c \"Closest elements to [0, 0]:\" \u003c\u003c std::endl;\n    for (auto it = m.find_nearest({0.,0.}, 2); it != m.end(); ++it) {\n        std::cout \u003c\u003c it-\u003efirst \u003c\u003c \": \" \u003c\u003c it-\u003esecond \u003c\u003c std::endl;\n    }\n    std::cout \u003c\u003c \"Elements between [-1, -1] and [+1, +1]:\" \u003c\u003c std::endl;\n    for (auto it = m.find_intersection({-1.,-1.}, {+1, +1}); it != m.end(); ++it) {\n        std::cout \u003c\u003c it-\u003efirst \u003c\u003c \": \" \u003c\u003c it-\u003esecond \u003c\u003c std::endl;\n    }\n    ```\n\n=== \"Python\"\n\n    ```python\n    m = pareto.spatial_map()\n    m[-2.5, -1.5] = 17\n    m[-2.1, -0.5] = 32\n    m[-1.6, 0.9] = 36\n    m[-0.6, 0.9] = 13\n    m[-0.5, 0.8] = 32\n    print(\"Closest elements to [0, 0]:\")\n    for [k, v] in m.find_nearest(pareto.point([0.,0.]), 2):\n        print(k, \":\", v)\n    \n    print(\"Elements between [-1, -1] and [+1, +1]:\")\n    for [k, v] in m.find_intersection(pareto.point([-1.,-1.]), pareto.point([+1, +1])):\n        print(k, \":\", v)\n\n    ```\n\n=== \"Output\"\n\n    ```console\n    Closest elements to [0, 0]:\n    [-0.5, 0.8]: 32\n    [-0.6, 0.9]: 13\n    Elements between [-1, -1] and [+1, +1]:\n    [-0.6, 0.9]: 13\n    [-0.5, 0.8]: 32\n    ```\n\nMulti-dimensional associative containers are useful in applications where you need to simultaneously order objects according to a number for criteria, such as in:\n\n* games\n* maps\n* nearest neighbor search\n* range search\n* compression algorithms\n* statistics\n* mechanics\n* graphics libraries\n* database queries. \n  \nMany applications already need to implement such kinds of containers, although in a less generic way.\n\n!!! info \"Complexity\"\n    Inserting, removing, and finding solutions cost $O(m \\log n)$, where $m$ is the number of dimensions and $n$ is the number of elements. \n\n!!! tip \"Unidimensional Spatial Containers\"\n    When $m=1$, a `pareto::spatial_map` internally decays into a `std::multimap`, which is useful for applications where we don't know $m$ beforehand or need to handle many possible values of $m$ without maintaining two different implementations.\n\n!!! info \"Runtime dimensions\"\n    Some problems are so dynamic that even the number of dimensions changes at runtime. In these applications, you can set the number of compile-time dimensions to `0`, and the containers will accept keys with any number of dimensions. This, of course, comes at a cost of an extra dynamic memory allocation per element.\n\nThe usual `find(k)`, `lower_bound(k)`, and `upper_bound(k)` functions of unidimensional maps are not enough for spatial\ncontainers. We fix this with **query iterators**, that explore the spatial data according to a list of predicates.\nQueries can limit or expand their search region with a conjunction of predicates such as intersections, disjunctions,\nand nearest points.\n\n!!! tip \"Predicate Lists\"\n    To make queries more efficient, the `pareto::predicate_list` object compresses redundant predicates and sorts these predicates by how restrictive they are. All tree nodes store their minimum bounding rectangles, and these underlying data structures are then explored to avoid nodes that might not pass the predicate list. This allows us to find each query element in $O(m \\log n)$ time, regardless of how complex the query is.\n\n### Front Container\n\nThe `pareto::front` object defines a container for **Pareto fronts**, which is both an adapter and an extension of the spatial containers to deal with objects representing conflicting alternatives:\n\n=== \"C++\"\n\n    ```cpp\n    // Three-dimensional Pareto front\n    pareto::front\u003cdouble, 3, unsigned\u003e m;\n    ```\n\n=== \"Python\"\n\n    ```python\n    # Three-dimensional Pareto front\n    # The dimension will be set when you insert the first element\n    m = pareto.front()\n    ```\n\nWhen inserting a new element in the front, all solutions *dominated* by the new solution are erased with spatial queries. \n\n\n=== \"C++\"\n\n    ```cpp\n    front\u003cdouble, 2, unsigned\u003e pf;\n    pf(0., 1.) = 17; // Good at x[0]\n    pf(1., 0.) = 32; // Good at x[1]\n    pf(2., 1.) = 36; // Dominated by [1., 0.]\n    for (const auto \u0026[k, v] : pf) {\n        std::cout \u003c\u003c k \u003c\u003c \" -\u003e \" \u003c\u003c v \u003c\u003c std::endl;\n    }\n    ```\n\n=== \"Python\"\n\n    ```python\n    pf = pareto.front()\n    # Good at x[0]\n    pf[0., 1.] = 17\n    # Good at x[1]\n    pf[1., 0.] = 32\n    # Dominated by [1., 0.]\n    pf[2., 1.] = 36\n    for [k, v] in pf:\n        print(k, \" -\u003e \", v)\n    ```\n\n=== \"Output\"\n\n    ```console\n    [0, 1] -\u003e 17\n    [1, 0] -\u003e 32\n    ```\n\nPareto fronts are useful in any application where we need to store the best objects according to a number of criteria, such as:\n\n* finance\n* multi-criteria decision making\n* optimization\n* machine learning\n* hyper-parameter tuning\n* approximation algorithms\n* P2P networks\n* routing algorithms\n* robust optimization\n* design\n* systems control\n\n!!! tip \n    You can think of fronts as a container for dynamic multidimensional max/min-finding. \n\n!!! example \n     Suppose you want to choose between a number of investment portfolios. By looking at the historical data, you have noticed each portfolio has an average return and some average risk (something like the covariance between the assets). Because there is an exponential number of portfolio candidates, you can instead iteratively update the front with the best portfolios for your criteria and use these portfolios as a reference to test new portfolios. You would then have front like the following:\n\n     ![2-dimensional front](docs/img/front2d_b.svg)\n\nThese objectives often go in different directions (e.g., minimize price vs. maximize quality). In these situations, you can specify a direction for each dimension.\n\n=== \"C++\"\n\n    ```cpp\n    // C++ Three-dimensional Pareto front\n    pareto::front\u003cdouble, 2, unsigned\u003e m({min, max});\n    ```\n\n=== \"Python\"\n\n    ```python\n    # Python Three-dimensional Pareto front\n    m = pareto.front(['min','max'])\n    ```\n\n!!! example\n    ![2-dimensional front](docs/img/front2d_directions.svg)\n\n    In more than two dimensions, we usually represent the fronts with parallel coordinates:\n\n    ![2-dimensional front](docs/img/front3d.svg)\n\n!!! tip \"Plotting Fronts\"\n    The header `pareto/matplot/front.h` includes some snippets to plot these fronts with [Matplot++](https:://www.github.com/alandefreitas/matplotplusplus).\n\nData scientists often use linear lists to represent these fronts, with a cost of $O(mn^2)$ for several operations. This\nmakes it unfeasible to represent the thousands or millions of solutions we usually have in a non-polynomial\nmultidimensional optimization problem due to the curse of dimensionality. With spatial indexes, this cost reduces to\nonly $O(m \\log n)$.\n\n!!! tip \"Indicators\"\n    Because Pareto fronts include solutions that are incomparable by definition, we need metrics to tell us the quality of a front. The `front` objects implement lots of performance indicators that can give us measures of:\n\n    * hypervolume\n    * convergence\n    * cardinality\n    * distribution\n    * correlation\n\n\n### Archive Container\n\nThe `pareto::archive` container is also both an adapter and an extension of spatial containers to cache objects representing conflicting alternatives:\n\n=== \"C++\"\n\n    ```cpp\n    // Three-dimensional Pareto archive\n    pareto::archive\u003cdouble, 3, unsigned\u003e m;\n    ```\n\n=== \"Python\"\n\n    ```python\n    # Python Three-dimensional Pareto archive\n    m = pareto.archive()\n    ```\n\nThey are useful in dynamic applications where the best objects might not be available in the future and we might need a second best. Archives are especially useful in all dynamic applications that use fronts, such as:\n\n* P2P networks\n* multi-criteria decision making\n* generate-and-test optimization algorithms\n* robust optimization\n\n!!! tip\n    You can think of archives as a multidimensional stack.\n\n!!! example\n    This is what a two-dimensional archive would look like:\n\n    ![2-dimensional front](docs/img/archive2d.svg)\n\n!!! tip \"Plotting Archives\"\n    The header `pareto/matplot/archive.h` includes some snippets to plot these archives with [Matplot++](https:://www.github.com/alandefreitas/matplotplusplus).\n\n!!! info \"Archive Capacity\"\n    All archive constructors include an optional parameter to define the maximum number of elements in the archive. If no maximum capacity for the archive is explicitly set, the capacity is set to $\\min(50 \\times 2^m, 100000)$. The exponential factor $2^m$ in this heuristic is meant to take the curse of dimensionality in consideration.\n\nData scientists often use linear lists to represent these fronts, with a cost of $O(mn^3)$ p\u001f\u00181 for several operations. With spatial indexes, this cost reduces to just $O(m \\log^2 n)$.\n\nYou have probably noticed by now that containers for fronts and archives have lots of use cases:\n\n| Use case                                                     | Common keys                                                 |\n| ------------------------------------------------------------ | ----------------------------------------------------------- |\n| Machine Learning                                             | Accuracy vs. Complexity vs. Time                            |\n| Approximation algorithms                                     | Error vs. Time                                              |\n| Product design                                               | Investment vs. Profit vs. Safety vs. Performance  vs. Scope |\n| P2P networks                                                 | Latency vs. Trust vs. Availability                          |\n| Robust optimization                                          | Average quality vs. Robustness                              |\n| Design                                                       | Average quality vs. Standard deviation                      |\n| Systems control                                              | Performance vs. Price vs. Quality                           |\n| Portfolio optimization                                       | Expected return vs. Risk                                    |\n| [More...](https://en.wikipedia.org/wiki/Multi-objective_optimization#Examples_of_applications) | ...                                                         |\n\n### Interfaces\n\nThese containers formally follow and extend on the named requirements of the C++ standard library. If you know how to use `std::map`, you already know how to use 90% any of these containers. You can use `m.erase(it)`, `m.insert(v)`, `m.empty()`, `m.size()`, `m.begin()` , and `m.end()` like you would with any other associative container.\n\n!!! important \"Python Bindings\"\n    Although this library is completely implemented in C++17, because data scientists love Python, we also include Python bindings for all these data structures. We further replicate the syntax of the native Python data structures, so that `m.erase(k)` becomes `del m[k]`, `if m.empty()` becomes `if m:`, and  `m.insert(k,v)` becomes `m[k] = v`. If you're a C++ programmer using Python, the C++ container syntax is still available in Python.\n\n!!! summary \"C++ Concepts / Named Requirements\"\n    Formally, these containers implement the [Container](https://en.cppreference.com/w/cpp/named_req/Container), [ReversibleContainer](https://en.cppreference.com/w/cpp/named_req/ReversibleContainer), [AllocatorAwareContainer](https://en.cppreference.com/w/cpp/named_req/AllocatorAwareContainer), and [AssociativeContainer](https://en.cppreference.com/w/cpp/named_req/AssociativeContainer) Concepts / Named Requirements. Their iterators also implement the [LegacyBidirectionalIterator](https://en.cppreference.com/w/cpp/named_req/BidirectionalIterator) concepts and they can use memory allocators that follow the [Allocator](https://en.cppreference.com/w/cpp/named_req/Allocator) concept. The extensions are formally defined as the concepts [SpatialContainer](tests/unit_tests/concepts.cpp), [FrontContainer](tests/unit_tests/concepts.cpp), and [ArchiveContainer](tests/unit_tests/concepts.cpp), whose pre- and post- conditions are checked with our unit tests.\n\nAll that means they work transparently with other native data structures. We include lots of unit tests, benchmarks, and continuous integration to make sure this compatibility is maintained. This also means they're easy to integrate with other libraries. For instance, the source file [`examples/matplotpp_example.cpp`](examples/matplotpp_example.cpp) and the headers in [`source/pareto/matplot`](source/pareto/matplot) exemplify how to create the plots you are seeing in this documentation with [Matplot++](https://github.com/alandefreitas/matplotplusplus). \n\n### Performance\n\nThe problem of storing multidimensional data is simple to explain but not so easy to solve. It might seem like linear lists, even with their $O(n^2)$ pair-wise comparisons, wouldn't fair much worse than these alternative containers. Even large scale multidimensional problems have at least some subproblems with less than a hundred solutions.\n\nOne common problem in scientific applications is that most of these containers can only outperform linear lists when\nstoring thousands of objects. This happens mainly because data structures based on trees require one memory allocation\nper node.\n\n!!! info \"Setting the Number of Dimensions\"\n    The first strategy we use to mitigate this problem is to allow the number of dimensions to be set at compile-time or runtime. This reduces the number of memory allocations because setting the dimension at runtime require one extra memory allocation per node.\n\n!!! info \"Memory Allocation\"\n    However, to make these associative containers fully competitive with linear lists in all scenarios, we need memory allocators. To avoid one dynamic allocation per node, pool allocators, like linear lists, pre-allocate fixed-size chucks of memory for tree nodes.\n\n    All containers implement the [AllocatorAwareContainer](https://en.cppreference.com/w/cpp/named_req/AllocatorAwareContainer) concept, that includes constructors that can receive custom allocators. All memory allocations happen through these custom allocators. If no allocator is provided, the build script will try to infer a proper allocator for each data structure.\n\n## Integration\n\n### C++\n\n#### Embed as header-only\n\nCopy the files from the `source` directory of this project to your `include` directory.\n\nIf you want to use `std::pmr` allocators by default, set the macro `BUILD_PARETO_WITH_PMR` before including the files.\n\n=== \"C++\"\n\n    ```cpp\n    #def BUILD_PARETO_WITH_PMR\n    #include \u003cpareto/front.h\u003e\n    ```\n\nEach header in `pareto` represents a data structure.\n\n!!! warning Make sure you have C++17+ installed\n\n#### Embed as CMake subdirectory\n\nYou can use pareto directly in CMake projects as a subproject.\n\nClone the whole project inside your own project:\n\n```bash\ngit clone https://github.com/alandefreitas/pareto/\n```\n\nand add the subdirectory to your CMake script:\n\n```cmake\nadd_subdirectory(pareto)\n```\n\nWhen creating your executable, link the library to the targets you want:\n\n```cmake\nadd_executable(my_target main.cpp)\ntarget_link_libraries(my_target PRIVATE pareto)\n```\n\nYour target will be able to see the pareto headers now.\n\n#### Embed with CMake FetchContent\n\nFetchContent is a CMake command to automatically download the repository:\n\n```cmake\ninclude(FetchContent)\n\nFetchContent_Declare(pareto\n        GIT_REPOSITORY https://github.com/alandefreitas/pareto\n        GIT_TAG origin/master # or whatever tag you want\n        )\n\nFetchContent_GetProperties(pareto)\nif (NOT pareto_POPULATED)\n    FetchContent_Populate(pareto)\n    add_subdirectory(${pareto_SOURCE_DIR} ${pareto_BINARY_DIR} EXCLUDE_FROM_ALL)\nendif ()\n\n# ...\ntarget_link_libraries(my_target PRIVATE pareto)\n```\n\nYour target will be able to see the pareto headers now.\n\n#### Embed with CPM.cmake\n\n[CPM.cmake](https://github.com/TheLartians/CPM.cmake) is a nice wrapper around the CMake FetchContent function.\nInstall [CPM.cmake](https://github.com/TheLartians/CPM.cmake) and then use this command to add Pareto to your build\nscript:\n\n```cmake\nCPMAddPackage(\n        NAME Pareto\n        GITHUB_REPOSITORY alandefreitas/pareto\n        GIT_TAG origin/master # or whatever tag you want\n)\n# ...\ntarget_link_libraries(my_target PUBLIC pareto)\n```\n\nYour target will be able to see the pareto headers now.\n\n#### Find as CMake package\n\nIf you are using CMake and have the library installed on your system, you can then find Pareto with the\nusual `find_package` command:\n\n```cmake\nfind_package(Pareto REQUIRED)\n# ...\ntarget_link_libraries(my_target PUBLIC pareto)\n```\n\nYour target will be able to see the pareto headers now.\n\n!!! warning \"find_package on windows\"\nThere is no easy default directory for find_package on windows. You have\nto [set it](https://stackoverflow.com/questions/21314893/what-is-the-default-search-path-for-find-package-in-windows-using-cmake)\nyourself.\n\n### Python\n\n#### Embed as project file\n\nGet the python binary from the [release section](https://github.com/alandefreitas/pareto/releases) and put it in your\nproject directory. You can then use the library with:\n\n```python\nimport pareto\n```\n\n#### Find as package\n\nIf you have installed the library on your system, all you need in your source code is:\n\n```python\nimport pareto\n```\n\n!!! warning There's no `pip install pareto` yet. Because this is a compiled library, creating a pip package is a little\nmore complicated. It's still in our to-do list.\n\n### Installing\n\nGet one of binary packages from the [release section](https://github.com/alandefreitas/pareto/releases). These file\nnames have the following syntax:\n\n* Python Binary \u003cOS\u003e\n    * This is only the binary for Python.\n    * Copy this file to your site-packages directory or to your project directory.\n    * No need to `pip install`\n* pareto-\u003c version \u003e-\u003c OS \u003e.\u003c package extension \u003e\n    * These packages contain the Python bindings and the C++ library.\n* Binary Packages \u003c OS \u003e\n    * These files contain all packages for a given OS.\n\nIf using one the installers, make sure you install the Python bindings to your site-packages directory (this is the\ndefault directory for most packages). You can find your site-packages directory with:\n\n```bash\npython -c \"from distutils.sysconfig import get_python_lib; print(get_python_lib());\"\n```\n\nThese binaries refer to the last release version. If you need a more recent version of pareto, you can download\nthe [binary packages from the CI artifacts](https://github.com/alandefreitas/pareto/actions?query=workflow%3APareto+event%3Apush)\nor build the library [from the source files](#build-from-source).\n\nOnce the package is installed, you can use the Python library with\n\n```\nimport pareto\n```\n\nor link your C++ program to the library and include the directories where you installed pareto.\n\nUnless you changed the default options, the C++ library is likely to be in `/usr/local/` (Linux / Mac OS)\nor `C:/Program Files/` (Windows). The installer will try to find the directory where you usually keep your libraries but\nthat's not always perfect.\n\nCMake should be able to locate the `ParetoConfig.cmake` script automatically if you installed the library\nunder `/usr/local/` (Linux / Mac OS).\n\n!!! warning \"find_package on windows\"\nThere is no easy default directory for `find_package` on windows. You have\nto [set it](https://stackoverflow.com/questions/21314893/what-is-the-default-search-path-for-find-package-in-windows-using-cmake)\nyourself.\n\n### Building\n\n#### Dependencies\n\n**C++**\n\nUpdate your C++ compiler to at least C++17:\n\n=== \"Ubuntu\"\n\n    ```bash\n    # install GCC10\n    sudo apt install build-essential\n    sudo add-apt-repository ppa:ubuntu-toolchain-r/test\n    sudo apt-get update\n    sudo apt install gcc-10\n    sudo apt install g++-10\n    sudo update-alternatives --install /usr/bin/gcc gcc /usr/bin/gcc-10 10\n    sudo update-alternatives --install /usr/bin/g++ g++ /usr/bin/g++-10 10\n    # Choose gcc-10 there as the default compiler\n    update-alternatives --config g++\n    ```\n\n=== \"Mac OS\"\n\n    ```bash\n    # Download clang\n    curl --output clang.tar.xz -L https://github.com/llvm/llvm-project/releases/download/llvmorg-11.0.0/clang+llvm-11.0.0-x86_64-apple-darwin.tar.xz\n    mkdir clang\n    tar -xvJf clang.tar.xz -C clang\n    # Copy the files to use/local\n    cd clang/clang+llvm-11.0.0-x86_64-apple-darwin\n    sudo cp -R * /usr/local/\n    # Make it your default compiler\n    export CXX=/usr/local/bin/clang++\n    ```\n\n=== \"Windows\"\n\n    Update your [Visual Studio Compiler](https://visualstudio.microsoft.com/).\n\n**CMake**\n\nUpdate your CMake to at least CMake 3.16+. You can check your CMake version with:\n\n```bash\ncmake --version\n```\n\nIf you need to update it, then\n\n=== \"Ubuntu + apt\"\n\n    ```bash\n    sudo apt upgrade cmake\n    ```\n\n=== \"Mac OS + Homebrew\"\n\n    ```bash\n    sudo brew upgrade cmake\n    ```\n\n=== \"Website\"\n\n    Download CMake from [https://cmake.org/download/](https://cmake.org/download/) and install it\n\n**Python**\n\nMake sure you have Python 3.6.9+ installed:\n\n```bash\npython3 --version\n```\n\nIf you need to update, then\n\n=== \"Ubuntu\"\n\n    Use `apt-get` or download it from https://www.python.org/downloads/.\n\n=== \"Mac OS\"\n\n    ```bash\n    sudo brew upgrade python3\n    ```\n\n    or download the latest release version from https://www.python.org/downloads/\n\n=== \"Windows\"\n\n    Download Python from [https://www.python.org/downloads/](https://www.python.org/downloads/) and install it\n\nIf using a Python installer, make sure you add the application directory to your PATH environment variable.\n\n#### Building\n\nAfter installing or updating the dependencies, clone the project with\n\n```bash\ngit clone https://github.com/alandefreitas/pareto.git\ncd pareto\n```\n\nand then build it with\n\n=== \"Ubuntu\"\n\n    ```bash\n    mkdir build\n    cd build\n    cmake -version\n    cmake .. -DCMAKE_BUILD_TYPE=Release -DCMAKE_CXX_FLAGS=\"-O2\"\n    cmake --build . -j 2 --config Release\n    # The next command for installing\n    sudo cmake --install .\n    # The next command for building the packages / installers\n    sudo cpack .\n    ```\n\n=== \"Mac OS\"\n\n    ```bash\n    mkdir build\n    cd build\n    cmake -version\n    cmake .. -DCMAKE_BUILD_TYPE=Release -DCMAKE_CXX_FLAGS=\"-O2\"\n    cmake --build . -j 2 --config Release\n    # The next command for installing\n    cmake --install .\n    # The next command for building the packages / installers\n    cpack .\n    ```\n\n=== \"Windows\"\n\n    ```bash\n    mkdir build\n    cd build\n    cmake -version\n    cmake .. -DCMAKE_BUILD_TYPE=Release -DCMAKE_CXX_FLAGS=\"/O2\"\n    cmake --build . -j 2 --config Release\n    # The next command for installing\n    cmake --install .\n    # The next command for building the packages / installers\n    cpack .\n    ```\n\n## Spatial Containers\n\n### Containers\n\nJust like you can create a uni-dimensional map with:\n\n=== \"C++\"\n\n    ```cpp\n    std::multimap\u003cdouble, unsigned\u003e m1;\n    // or\n    std::unordered_map\u003cdouble, unsigned\u003e m2;\n    ```\n\n=== \"Python\"\n\n    ```python\n    m1 = sortedcontainers.SortedDict()\n    # or\n    m2 = dict()\n    ```\n\nSpatial containers allow you to create an $m$-dimensional map with something like:\n\n=== \"C++\"\n\n    ```cpp\n    pareto::spatial_map\u003cdouble, 2, unsigned\u003e m1;\n    pareto::spatial_map\u003cdouble, 3, unsigned\u003e m2;\n    pareto::spatial_map\u003cdouble, 4, unsigned\u003e m3;\n    pareto::spatial_map\u003cdouble, 5, unsigned\u003e m4;\n    ```\n\n=== \"Python\"\n\n    ```python\n    # The dimension will be set when you insert the first point\n    m1 = pareto.spatial_map()\n    ```\n\nA `spatial_map` is currently defined as an alias to an `r_tree`. If you want to be specific about which data structure to use, you can directly define:\n\n=== \"C++\"\n\n    ```cpp\n    pareto::r_tree\u003cdouble, 3, unsigned\u003e m1;\n    pareto::r_star_tree\u003cdouble, 3, unsigned\u003e m2;\n    pareto::kd_tree\u003cdouble, 3, unsigned\u003e m3;\n    pareto::quad_tree\u003cdouble, 3, unsigned\u003e m4;\n    pareto::implicit_tree\u003cdouble, 3, unsigned\u003e m5;\n    ```\n\n=== \"Python\"\n\n    ```python\n    m1 = pareto.r_tree()\n    m2 = pareto.r_star_tree()\n    m3 = pareto.kd_tree()\n    m4 = pareto.quad_tree()\n    m5 = pareto.implicit_tree()\n    ```\n\nHere's a summary of what each container is good at:\n\n| Container       | Best Application                                             | Optimal |\n| --------------- | ------------------------------------------------------------ | ------- |\n| `kd_tree`       | Non-uniformly distributed objects                           | Yes     |\n| `r_tree`        | Non-uniformly distributed objects that might overlap in space | Yes     |\n| `r_star_tree`   | Same as `r_tree` with more expensive insertion and less expensive queries | Yes     |\n| `quad_tree`     | Uniformly distributed objects                               | No      |\n| `implicit_tree` | Benchmarks only                                              | No      |\n\nAlthough `pareto::front` and `pareto::archive` also implement the *SpatialContainer* concept, they serve a different purpose we discuss in Sections [Front Concept](#front-concept) and [Archive Concept](#archive-concept). However, their interface remains unchanged for the most common use cases:\n\n=== \"C++\"\n\n    ```cpp\n    pareto::front\u003cdouble, 3, unsigned\u003e pf;\n    pareto::archive\u003cdouble, 3, unsigned\u003e ar;\n    ```\n\n=== \"Python\"\n\n    ```python\n    pf = pareto.front()\n    ar = pareto.archive()\n    ```\n\n!!! info \"Complexity\"\n    * Containers with optimal asymptotic complexity have a $O(m \\log n)$ cost to search, insert and remove elements.\n\n    * Quadtrees do not have optimal asymptotic complexity because removing elements might require reconstructing subtrees with cost $O(m n \\log n)$. \n\n    * The container `implicit_tree` is emulates a tree with a `std::vector`. You can think of it as a multidimensional [`flat_map`](https://www.boost.org/doc/libs/1_75_0/doc/html/boost/container/flat_map.html). However, unlike a flat map, sorting the elements in a single dimension does not make operations much unless $m \\leq 3$. Its basic operations cost $O(mn)$ and it's mostly used as a reference for our benchmarks.\n\n### Types\n\nThis table summarizes the public types in all SpatialContainers:\n\n| Name                                                         | Type                                                         | Notes                                                        |\n| ------------------------------------------------------------ | ------------------------------------------------------------ | ------------------------------------------------------------ |\n| [**Container**](https://en.cppreference.com/w/cpp/named_req/Container) |                                                              |                                                              |\n| `value_type`                                                 | `std::pair\u003cconst pareto::point\u003cK,M\u003e,T\u003e`                      | The pair key is `const`, like in other associative containers |\n| `reference`                                                  | `value_type\u0026`                                                |                                                              |\n| `const_reference`                                            | `value_type const \u0026`                                         |                                                              |\n| `iterator`                                                   | Iterator pointing to a `value_type`                          | A [LegacyBidirectionalIterator](https://en.cppreference.com/w/cpp/named_req/ForwardIterator) convertible to `const_iterator` |\n| `const_iterator`                                             | Iterator pointing to a `const value_type`                    | Implements [LegacyBidirectionalIterator](https://en.cppreference.com/w/cpp/named_req/ForwardIterator) concept |\n| `difference_type`                                            | A signed integer                                             |                                                              |\n| `size_type`                                                  | An unsigned integer                                          |                                                              |\n| [**ReversibleContainer**](https://en.cppreference.com/w/cpp/named_req/ReversibleContainer) |                                                              |                                                              |\n| `reverse_iterator`                                           | `std::reverse_iterator\u003citerator\u003e`                            |                                                              |\n| `const_reverse_iterator`                                     | `std::reverse_iterator\u003cconst_iterator\u003e`                      |                                                              |\n| [**AssociativeContainer**](https://en.cppreference.com/w/cpp/named_req/AssociativeContainer) |                                                              |                                                              |\n| `key_type`                                                   | `pareto::point\u003cK,M\u003e`                                         | `key_type` is not const, so you can use it to construct and manipulate new points |\n| `mapped_type`                                                | `T`                                                          |                                                              |\n| `key_compare`                                                | `std::function\u003cbool(const value_type \u0026, const value_type \u0026)\u003e` | `key_compare` defines a lexicographic ordering relation over keys using `dimension_compare` |\n| `value_compare`                                              | `std::function\u003cbool(const value_type \u0026, const value_type \u0026)\u003e` | `value_compare` defines an ordering relation over `value_type` using `key_compare` |\n| [**AllocatorAwareContainer**](https://en.cppreference.com/w/cpp/named_req/AllocatorAwareContainer) |                                                              |                                                              |\n| `allocator_type`                                             | `A`, or `pareto::default_allocator\u003cvalue_type\u003e` by default   | `allocator_type::value_type` is the same as `value_type`     |\n| **SpatialContainer**                                         |                                                              |                                                              |\n| `dimension_type`                                                | `K`                                                          |                                                              |\n| `dimension_compare`                                             | `C`, or `std::less\u003cK\u003e` by default                            | `dimension_compare` defines an ordering relation over each `key_value` dimension using `C` |\n| `box_type`                                                   | `pareto::query_box\u003cdimension_type, M\u003e`                          |                                                              |\n| `predicate_list_type`                                        | `pareto::predicate_list\u003cdimension_type, M, T\u003e`                  |                                                              |\n\n**Notes**\n\n`dimension_type` refers to a single dimension in `key_type`. Although this is usually a number, it might be an object of any other type.\n\n!!! info \"Key type\"\n    While the container is defined with the uni-dimensional key `K`, the container expands that into an `M`-dimensional point of type `pareto::point\u003cK,M\u003e`.  This does not break any named requirement for containers, as types can be different from their template parameters.\n\n!!! info \"Iterators to constant keys\"\n    The first type in `value_type` (`const pareto::point\u003cK,M\u003e`) is `const`. This is a requirement of associative containers. Otherwise, the user could externally change keys through references and the container nodes would no longer be properly ordered.\n\n!!! info \"Bidirectional Iterators\"\n    A `spatial_map\u003cK,M,T,A\u003e::iterator` is a [LegacyBidirectionalIterator](https://en.cppreference.com/w/cpp/named_req/ForwardIterator) convertible to a `const_iterator` (but to the other way around). This means iterators can move forward and backward. However, we can also use **queries** to explore specific regions of space, so it's still reasonably easy to look for random points and things like that.\n\n\u003c!-- Include example --\u003e\n\n### Constructors\n\nThe constructors defined by `pareto::spatial_map\u003cK,M,T,C,A\u003e::spatial_map` (or any other [spatial container](#containers)) instantiate new containers from a variety of data sources and optionally using a user supplied allocator `alloc` or comparison function object `comp`.\n\n| Method                                                       |\n| ------------------------------------------------------------ |\n| **Container** + **AllocatorAwareContainer**     |\n| `explicit spatial_map(const allocator_type \u0026alloc = allocator_type())` |\n| `spatial_map(const spatial_map \u0026rhs)`                        |\n| `spatial_map(const spatial_map \u0026rhs, const allocator_type \u0026alloc)` |\n| `spatial_map(spatial_map \u0026\u0026rhs) noexcept`                    |\n| `spatial_map(spatial_map \u0026\u0026rhs, const allocator_type \u0026alloc) noexcept` |\n| **AssociativeContainer** + **AllocatorAwareContainer** |\n| `explicit spatial_map(const C \u0026comp, const allocator_type \u0026alloc = allocator_type())` |\n| `template \u003cclass InputIt\u003e spatial_map(InputIt first, InputIt last, const C \u0026comp = C(), const allocator_type \u0026alloc = allocator_type())` |\n| `spatial_map(std::initializer_list\u003cvalue_type\u003e il, const C \u0026comp = C(), const allocator_type \u0026alloc = allocator_type())` |\n| `template \u003cclass InputIt\u003e spatial_map(InputIt first, InputIt last, const allocator_type \u0026alloc)` |\n| `spatial_map(std::initializer_list\u003cvalue_type\u003e il, const allocator_type \u0026alloc)` |\n| **AssociativeContainer** + **AllocatorAwareContainer** Assignment |\n| `spatial_map \u0026operator=(const spatial_map \u0026rhs)`             |\n| `spatial_map \u0026operator=(spatial_map \u0026\u0026rhs) noexcept`         |\n| **AssociativeContainer** Assignment                          |\n| `spatial_map \u0026operator=(std::initializer_list\u003cvalue_type\u003e il) noexcept` |\n\n**Parameters**\n\n| Parameter       | Description                                                  |\n| --------------- | ------------------------------------------------------------ |\n| `alloc`         | allocator to use for all memory allocations of this container |\n| `comp`          | comparison function object to use for all comparisons of keys |\n| `first`, `last` | the range to copy the elements from                          |\n| `rhs`           | another container to be used as source to initialize the elements of the container with |\n| `il`            | initializer list to initialize the elements of the container with |\n\n**Requirements**\n\n| Type requirements                                            |\n| ------------------------------------------------------------ |\n| -`InputIt` must meet the requirements of [*LegacyInputIterator*](https://en.cppreference.com/w/cpp/named_req/InputIterator). |\n| -`Compare` must meet the requirements of [*Compare*](https://en.cppreference.com/w/cpp/named_req/Compare). |\n| -`Allocator` must meet the requirements of [*Allocator*](https://en.cppreference.com/w/cpp/named_req/Allocator). |\n\n**Complexity**\n\n| Method                              | Complexity                                         |\n| ----------------------------------- | -------------------------------------------------- |\n| Empty constructor                   | $O(1)$                                             |\n| Copy constructor                    | $O(mn)$                                            |\n| Move constructor                    | $O(1)$ if `get_allocator() == rhs.get_allocator()` |\n| Construct from range, or assignment | $O(m n \\log n)$                                    |\n\n**Example**\n\n=== \"C++\"\n\n    ```cpp\n    #include \u003cpareto/spatial_map.h\u003e\n    #include \u003cpareto/kd_tree.h\u003e\n    // ...\n    // Constructing the default spatial map\n    pareto::spatial_map\u003cdouble, 3, unsigned\u003e m;\n    // Constructing a kd-tree spatial map\n    pareto::kd_tree\u003cdouble, 3, unsigned\u003e m;\n    ```\n\n=== \"Python\"\n\n    ```python\n    import pareto\n    # ...\n    # Constructing the default spatial map\n    m = pareto.spatial_map() \n    # // Constructing a kd-tree spatial map\n    m = pareto.kd_tree() \n    ```\n\n### Allocators\n\n| Method                                           |\n| ------------------------------------------------ |\n| **AllocatorAwareContainer**                      |\n| `allocator_type get_allocator() const noexcept;` |\n\n**Return value**\n\nThe associated allocator.\n\n**Complexity**\n\n$$\nO(1)\n$$\n\n**Notes**\n\nOne of the reasons associative containers perform much worse than sequence containers for small containers is that associative containers, being internally represented as trees, require one memory allocation for each new element. An allocator is an object that defines how memory is allocated for a container. Because tree nodes usually have fixed size, pool allocators for associative containers usually allocate a large block of memory for nodes before new nodes are created. Thus, associative containers can have a performance similar to sequential containers even when the container has few elements.  \n\n\n!!! info \"The Allocator Concept\"\n    An allocator must implement the [Allocator](https://en.cppreference.com/w/cpp/named_req/Allocator) concept, while an allocator aware container must implement the [*AllocatorAwareContainer*](https://en.cppreference.com/w/cpp/named_req/AllocatorAwareContainer) concept, which includes constructors accepting allocators as parameters. Internally, a container that is allocator aware should use only the allocator to create new nodes.\n\nBesides the constructors defined in the previous section, spatial containers also define the function `allocator_type get_allocator() const;` to return the current allocator being used by the container. If two allocators compare equal, that means they use the same memory resources. When two containers do not use the same allocator, the move constructor costs $O(mn)$ instead of $O(1)$.\n\n!!! info \"Default Allocator\"\n    By default, all containers in this library use a `std::pmr::polymorphic_allocator` with an internal `std::pmr::unsynchronized_pool_resource` as their default allocator (see our [Benchmarks](#benchmarks)). \n\n!!! warning \"PMR implementations\"\n    Because many compilers haven't completely implemented `std::pmr` yet, the build script will look for `std::pmr` and fallback to `std::allocator` if `std::pmr` is not available yet.\n\n!!! note \"Note on previous versions of Pareto\"\n    Previous versions of this library included a stateful memory allocator based on pools and slots. Because the C++ requirements for allocators are not kind to simple stateful allocators whose elements have fixed size, our allocator ended up looking more and more like a simpler version of the `std::pmr::polymorphic_allocator`. \n    Fortunately, these `std::pmr` is now part of the standard library and our containers are now allocator aware, so you can just use `pmr` or any other efficient allocator for these containers. \n\n**Example**\n\n=== \"C++\"\n\n    ```cpp\n    #include \u003cpareto/spatial_map.h\u003e\n    // ...\n    pareto::spatial_map\u003cdouble, 3, unsigned\u003e m;\n    // Get a copy of the container allocator\n    auto alloc = m.get_allocator();\n    ```\n\n### Element Access\n\n| Method                                                       |\n| ------------------------------------------------------------ |\n| **MapContainer**                                             |\n| Access and throw exception if it doesn't exist               |\n| `mapped_type \u0026at(const key_type \u0026k);`                        |\n| `const mapped_type \u0026at(const key_type \u0026k) const;`            |\n| Access and create new element if it doesn't exist            |\n| `mapped_type \u0026operator[] (const key_type \u0026k);`                |\n| `mapped_type \u0026operator[] (key_type \u0026\u0026k);`                     |\n| `template \u003ctypename... Targs\u003e mapped_type \u0026operator()(const dimension_type \u0026x1, const Targs \u0026...xs);` |\n\n**Parameters**\n\n* `k` - the key of the element to find\n* `x1` - the value of the element to find in the first dimension\n* `xs` - the value of the element to find in other dimensions\n\n**Return value**\n\nA reference to the element associated with that key.\n\n**Exceptions**\n\n[`std::out_of_range`](https://en.cppreference.com/w/cpp/error/out_of_range) if the container does not have an element with the specified `key`\n\n**Complexity**\n\n$$\nO(m \\log n)\n$$\n\n**Notes**\n\nWhile the `at` function throws an error when the element is not found, `operator[]` creates a new element with that key if the element is not found. Like other libraries that handle multidimensional data, we use the `operator()` for element access as a convenience because the `operator[]` does not allow multiple parameters. We can still use `operator[]` with a `front::key_type` though. \n\n!!! note\n    Like `std::map`, and unlike `std::multimap`, spatial containers implement the element access operators even though duplicate keys are permitted. The reason `std::multimap` does not implement these operators is because the operator might be ambiguous when there is more than one element that matches the given key. \n\n    By convention we formally remove this ambiguity by always using the first element that matches that key. It's up to the library user to decide if this behaviour is appropriate for their application. If not, the modifier functions should be used instead.\n\n**Example**\n\n=== \"C++\"\n\n    ```cpp\n    spatial_map\u003cdouble, 3, unsigned\u003e m;\n    // Set some values\n    m(-2.57664, -1.52034, 0.600798) = 17;\n    m(-2.14255, -0.518684, -2.92346) = 32;\n    m(-1.63295, 0.912108, -2.12953) = 36;\n    m(-0.653036, 0.927688, -0.813932) = 13;\n    m(-0.508188, 0.871096, -2.25287) = 32;\n    m(-2.55905, -0.271349, 0.898137) = 6;\n    m(-2.31613, -0.219302, 0) = 8;\n    m(-0.639149, 1.89515, 0.858653) = 10;\n    m(-0.401531, 2.30172, 0.58125) = 39;\n    m(0.0728106, 1.91877, 0.399664) = 25;\n    m(-1.09756, 1.33135, 0.569513) = 20;\n    m(-0.894115, 1.01387, 0.462008) = 11;\n    m(-1.45049, 1.35763, 0.606019) = 17;\n    m(0.152711, 1.99514, -0.112665) = 13;\n    m(-2.3912, 0.395611, 2.78224) = 11;\n    m(-0.00292544, 1.29632, -0.578346) = 20;\n    m(0.157424, 2.30954, -1.23614) = 6;\n    m(0.453686, 1.02632, -2.24833) = 30;\n    m(0.693712, 1.12267, -1.37375) = 12;\n    m(1.49101, 3.24052, 0.724771) = 24;\n    // Access value\n    std::cout \u003c\u003c \"Element access: \" \u003c\u003c m(1.49101, 3.24052, 0.724771) \u003c\u003c std::endl;\n    ```\n\n=== \"Python\"\n\n    ```python\n    m = pareto.spatial_map()\n    # Set some values\n    m[-2.57664, -1.52034, 0.600798] = 17\n    m[-2.14255, -0.518684, -2.92346] = 32\n    m[-1.63295, 0.912108, -2.12953] = 36\n    m[-0.653036, 0.927688, -0.813932] = 13\n    m[-0.508188, 0.871096, -2.25287] = 32\n    m[-2.55905, -0.271349, 0.898137] = 6\n    m[-2.31613, -0.219302, 0] = 8\n    m[-0.639149, 1.89515, 0.858653] = 10\n    m[-0.401531, 2.30172, 0.58125] = 39\n    m[0.0728106, 1.91877, 0.399664] = 25\n    m[-1.09756, 1.33135, 0.569513] = 20\n    m[-0.894115, 1.01387, 0.462008] = 11\n    m[-1.45049, 1.35763, 0.606019] = 17\n    m[0.152711, 1.99514, -0.112665] = 13\n    m[-2.3912, 0.395611, 2.78224] = 11\n    m[-0.00292544, 1.29632, -0.578346] = 20\n    m[0.157424, 2.30954, -1.23614] = 6\n    m[0.453686, 1.02632, -2.24833] = 30\n    m[0.693712, 1.12267, -1.37375] = 12\n    m[1.49101, 3.24052, 0.724771] = 24\n    # Access value\n    print('Element access:', m[1.49101, 3.24052, 0.724771])\n    ```\n\n=== \"Output\"\n\n    ```console\n    Element access: 24\n    ```\n\n### Iterators\n\n| Method                                                       |\n| ------------------------------------------------------------ |\n| **MultimapContainer**                                        |\n| Get constant iterators                                       |\n| `const_iterator begin() const noexcept;`                     |\n| `const_iterator end() const noexcept;`                       |\n| `const_iterator cbegin() const noexcept;`                    |\n| `const_iterator cend() const noexcept;`                      |\n| Get iterators                                                |\n| `iterator begin() noexcept;`                                 |\n| `iterator end() noexcept;`                                   |\n| Get reverse iterators                                        |\n| `std::reverse_iterator\u003cconst_iterator\u003e rbegin() const noexcept;` |\n| `std::reverse_iterator\u003cconst_iterator\u003e rend() const noexcept;` |\n| `std::reverse_iterator\u003citerator\u003e rbegin() noexcept`;         |\n| `std::reverse_iterator\u003citerator\u003e rend() noexcept;`           |\n| Get constant reverse iterators                               |\n| `std::reverse_iterator\u003cconst_iterator\u003e crbegin() const noexcept;` |\n| `std::reverse_iterator\u003cconst_iterator\u003e crend() const noexcept;` |\n\n**Return value**\n\n* `begin()` - Iterator to the first element in the container\n* `end()` - Iterator to the past-the-end element in the container (see notes)\n\n**Complexity**\n\n$$\nO(1)\n$$\n\n**Notes**\n\nAt each iteration, these iterators report the next tree element in a depth-first search algorithm. The reverse iterators perform a reversed depth-first search algorithm, where we get the next element at the rightmost element of the left sibling node or return the parent node when there are no more siblings.\n\n!!! info\n    All spatial maps have two kinds of iterators: the usual iterators and query iterators. Query iterators contain a list of predicates and skip all elements that do not match these predicates. The functions in this section describe only the usual iterators. \n\n    Query iterators and normal iterators compare equal when they point to the same element, but this doesn't mean their next element is the same element.\n\n!!! info \"Python Iterators\"\n    The Python interface uses ranges instead of single iterators. The `begin` and `end` functions are not directly exposed.\n\n!!! note \"Note for C++ Beginners\"\n\n    The iterators `begin()` point to the first element in the container. The iterators `end()` point to one position after the last element in the container.\n\n    ![Iterators from C++ reference](https://upload.cppreference.com/mwiki/images/1/1b/range-begin-end.svg)\n\n    This means that, given an iterator `it` initially equivalent to `begin()`, we can iterate elements `while (it != end()) { ++it; }`. If the `spatial_map` is empty, `begin()` returns an iterator equal to `end()`.\n\nThe functions beginning with `c` return constant iterators. When we dereference a constant iterators with `operator*`, they only return references to constant values (`const value_type\u0026`).\n\nThe functions beginning with `r` return reverse iterators. Reverse iterators go from the last to the first element.\n\n!!! example \"Example of reverse iterators\"\n    ![Reverse Iterators from C++ reference](https://upload.cppreference.com/mwiki/images/3/39/range-rbegin-rend.svg)\n\nThe functions beginning with `cr` return constant reverse iterators.\t\n\n!!! note \"Intermediate C++**\n    Like all other associative containers, non-const iterators return references to `std::pair\u003cconst key_type, mapped_type\u003e` and not  `std::pair\u003ckey_type, mapped_type\u003e` like one might think. This is meant to protect the associative relationship between nodes in the container. \n\n**Example**\n\nContinuing from the previous example:\n\n=== \"C++\"\n\n    ```cpp\n    std::cout \u003c\u003c \"Iterators:\" \u003c\u003c std::endl;\n    for (const auto\u0026 [point, value]: m) {\n        std::cout \u003c\u003c point \u003c\u003c \" -\u003e \" \u003c\u003c value \u003c\u003c std::endl;\n    }\n\n    std::cout \u003c\u003c \"Reversed Iterators:\" \u003c\u003c std::endl;\n    for (auto it = m.rbegin(); it != m.rend(); ++it) {\n        std::cout \u003c\u003c it-\u003efirst \u003c\u003c \" -\u003e \" \u003c\u003c it-\u003esecond \u003c\u003c std::endl;\n    }\n    ```\n\n=== \"Python\"\n\n    ```python\n    print('Iterators')\n    for [point, value] in m:\n        print(point, '-\u003e', value)\n    \n    print('Reversed Iterators')\n    for [point, value] in reversed(m):\n        print(point, '-\u003e', value)\n    ```\n\n=== \"Output\"\n\n    ```console\n    Iterators:\n    [-2.14255, -0.518684, -2.92346] -\u003e 32\n    [-1.63295, 0.912108, -2.12953] -\u003e 36\n    [-0.653036, 0.927688, -0.813932] -\u003e 13\n    [-0.508188, 0.871096, -2.25287] -\u003e 32\n    [0.453686, 1.02632, -2.24833] -\u003e 30\n    [0.693712, 1.12267, -1.37375] -\u003e 12\n    [-2.57664, -1.52034, 0.600798] -\u003e 17\n    [-2.55905, -0.271349, 0.898137] -\u003e 6\n    [-2.31613, -0.219302, 0] -\u003e 8\n    [-0.894115, 1.01387, 0.462008] -\u003e 11\n    [-2.3912, 0.395611, 2.78224] -\u003e 11\n    [-0.639149, 1.89515, 0.858653] -\u003e 10\n    [-0.401531, 2.30172, 0.58125] -\u003e 39\n    [-1.09756, 1.33135, 0.569513] -\u003e 20\n    [-1.45049, 1.35763, 0.606019] -\u003e 17\n    [-0.00292544, 1.29632, -0.578346] -\u003e 20\n    [0.0728106, 1.91877, 0.399664] -\u003e 25\n    [0.152711, 1.99514, -0.112665] -\u003e 13\n    [0.157424, 2.30954, -1.23614] -\u003e 6\n    [1.49101, 3.24052, 0.724771] -\u003e 24\n    Reversed Iterators:\n    [1.49101, 3.24052, 0.724771] -\u003e 24\n    [0.157424, 2.30954, -1.23614] -\u003e 6\n    [0.152711, 1.99514, -0.112665] -\u003e 13\n    [0.0728106, 1.91877, 0.399664] -\u003e 25\n    [-0.00292544, 1.29632, -0.578346] -\u003e 20\n    [-1.45049, 1.35763, 0.606019] -\u003e 17\n    [-1.09756, 1.33135, 0.569513] -\u003e 20\n    [-0.401531, 2.30172, 0.58125] -\u003e 39\n    [-0.639149, 1.89515, 0.858653] -\u003e 10\n    [-2.3912, 0.395611, 2.78224] -\u003e 11\n    [-0.894115, 1.01387, 0.462008] -\u003e 11\n    [-2.31613, -0.219302, 0] -\u003e 8\n    [-2.55905, -0.271349, 0.898137] -\u003e 6\n    [-2.57664, -1.52034, 0.600798] -\u003e 17\n    [0.693712, 1.12267, -1.37375] -\u003e 12\n    [0.453686, 1.02632, -2.24833] -\u003e 30\n    [-0.508188, 0.871096, -2.25287] -\u003e 32\n    [-0.653036, 0.927688, -0.813932] -\u003e 13\n    [-1.63295, 0.912108, -2.12953] -\u003e 36\n    [-2.14255, -0.518684, -2.92346] -\u003e 32\n    ```\n\n### Capacity and Reference Points\n\n| Method                                               |\n| ---------------------------------------------------- |\n| **MultimapContainer**                                |\n| Check size                                           |\n| `[[nodiscard]] bool empty() const noexcept;`         |\n| `[[nodiscard]] size_type size() const noexcept;`     |\n| `[[nodiscard]] size_type max_size() const noexcept;` |\n| **SpatialContainer**                                 |\n| Check dimensions                                     |\n| `[[nodiscard]] size_t dimensions() const noexcept;`  |\n| Get max/min values                                   |\n| `dimension_type max_value(size_t dimension) const;`     |\n| `dimension_type min_value(size_t dimension) const;`     |\n\n**Parameters**\n\n* `dimension` - index of the dimension for which we want the minimum or maximum value\n\n**Return value**\n\n* `empty()`- `true` if and only if container (equivalent but more efficient than `begin() == end()`)\n* `size()` - The number of elements in the container\n* `max_size()` - An upper bound on the maximum number of elements the container can hold\n* `dimensions()` - Number of dimensions in the container (same as `M`, when `M != 0`)\n* `max_value()` - Maximum value in a given dimension\n* `min_value()` - Minimum value in a given dimension\n\n**Complexity**\n\n$$\nO(1)\n$$\n\n**Notes**\n\nBecause all container nodes keep their minimum bounding rectangles, we can get these values in constant time.\n\n**Example**\n\nContinuing from the previous example:\n\n=== \"C++\"\n\n    ```cpp\n    if (!m.empty()) {\n        std::cout \u003c\u003c \"Map is not empty\" \u003c\u003c std::endl;\n    } else {\n        std::cout \u003c\u003c \"Map is empty\" \u003c\u003c std::endl;\n    }\n    std::cout \u003c\u003c m.size() \u003c\u003c \" elements in the spatial map\" \u003c\u003c std::endl;\n    std::cout \u003c\u003c m.dimensions() \u003c\u003c \" dimensions\" \u003c\u003c std::endl;\n    for (size_t i = 0; i \u003c m.dimensions(); ++i) {\n        std::cout \u003c\u003c \"Min value in dimension \" \u003c\u003c i \u003c\u003c \": \" \u003c\u003c m.min_value(i) \u003c\u003c std::endl;\n        std::cout \u003c\u003c \"Max value in dimension \" \u003c\u003c i \u003c\u003c \": \" \u003c\u003c m.max_value(i) \u003c\u003c std::endl;\n    }\n    ```\n\n=== \"Python\"\n\n    ```python\n    if m:\n        print('Map is not empty')\n    else:\n        print('Map is empty')\n\n    print(len(m), 'elements in the spatial map')\n    print(m.dimensions(), 'dimensions')\n    for i in range(m.dimensions()):\n        print('Min value in dimension', i, ': ', m.min_value(i))\n        print('Max value in dimension', i, ': ', m.max_value(i))\n    \n    ```\n\n=== \"Output\"\n\n    ```console\n    Map is not empty\n    20 elements in the spatial map\n    3 dimensions\n    Min value in dimension 0: -2.57664\n    Max value in dimension 0: 1.49101\n    Min value in dimension 1: -1.52034\n    Max value in dimension 1: 3.24052\n    Min value in dimension 2: -2.92346\n    Max value in dimension 2: 2.78224\n    ```\n\n\n### Modifiers\n\n| Method                                                       |\n| ------------------------------------------------------------ |\n| **Container** + **AllocatorAwareContainer**                  |\n| Exchanges the contents of the container with those of `rhs`  |\n| `void swap(kd_tree \u0026rhs) noexcept;`                          |\n| **Multimap**                                                 |\n| Erases all elements from the container                       |\n| `void clear();`                                              |\n| Inserts element(s) into the container                        |\n| `iterator insert(const value_type \u0026v);`                      |\n| `iterator insert(value_type \u0026\u0026v);`                           |\n| `template \u003cclass P\u003e iterator insert(P \u0026\u0026v);`                 |\n| `iterator insert(iterator, const value_type \u0026v);`            |\n| `iterator insert(const_iterator, const value_type \u0026v);`      |\n| `iterator insert(const_iterator, value_type \u0026\u0026v);`           |\n| `template \u003cclass P\u003e iterator insert(const_iterator hint, P \u0026\u0026v);` |\n| `template \u003cclass Inputiterator\u003e void insert(Inputiterator first, Inputiterator last);` |\n| `void insert(std::initializer_list\u003cvalue_type\u003e init);`       |\n| Inserts a new element into the container constructed in-place with the given `args` |\n| `template \u003cclass... Args\u003e iterator emplace(Args \u0026\u0026...args);` |\n| `template \u003cclass... Args\u003e iterator emplace_hint(const_iterator, Args \u0026\u0026...args);` |\n| Removes specified elements from the container                |\n| `iterator erase(const_iterator position);`                   |\n| `iterator erase(iterator position);`                         |\n| `iterator erase(const_iterator first, const_iterator last);` |\n| `size_type erase(const key_type \u0026k);`                        |\n| Attempts to extract (\"splice\") each element in `source` and insert it into `*this` |\n| `void merge(spatial_map \u0026source) noexcept;`                      |\n| `void merge(spatial_map \u0026\u0026source) noexcept;`                      |\n\n**Parameters**\n\n* `rhs` - container to exchange the contents with\n* `v` - element value to insert\n* `first`, `last` - range of elements to insert/erase\n* `init` - initializer list to insert the values from\n* `hint` - iterator, used as a suggestion as to where to start the search\n* `position` - iterator pointer to element to erase\n* `k` - key value of the elements to remove\n* `source` - container to get elements from\n\n**Return value**\n\n* `iterator` - Iterator to the new element (`insert`) or following the last removed element (`erase`)\n* `size_type` - Number of elements erased\n\n**Complexity**\n\n* `insert`, `emplace`,  `erase`: $O(m \\log n)$\n* `swap`: $O(1)$\n* `merge`: $O(mn)$\n\n**Notes**\n\nThe containers cannot take advantage of the hints yet.\n\n**Example**\n\nContinuing from the previous example:\n\n=== \"C++\"\n\n    ```cpp\n    m.insert({{1.49101, 3.24052, 0.724771}, 24});\n    m.erase({1.49101, 3.24052, 0.724771});\n    ```\n\n=== \"Python\"\n\n    ```python\n    m.insert([pareto.point([1.49101, 3.24052, 0.724771]), 24])\n    del m[1.49101, 3.24052, 0.724771]\n    ```\n\n### Lookup and Queries\n\n| Method                                                       |\n| ------------------------------------------------------------ |\n| **Multimap**                                                 |\n| Returns the number of elements matching specific key         |\n| `size_type count(const key_type \u0026p) const;`                  |\n| `template \u003cclass L\u003e size_type count(const L \u0026p) const`       |\n| Finds element with specific key                              |\n| `iterator find(const key_type \u0026p);`                          |\n| `const_iterator find(const key_type \u0026p) const;`              |\n| `template \u003cclass L\u003e iterator find(const L \u0026p)`               |\n| `template \u003cclass L\u003e const_iterator find(const L \u0026p) const;`  |\n| Checks if the container contains element with specific key   |\n| `bool contains(const key_type \u0026p) const;`                    |\n| `template \u003cclass L\u003e bool contains(const L \u0026p) const;`        |\n| **SpatialContainer**                                         |\n| Get iterator to first element that passes the predicates     |\n| `const_iterator find(const predicate_list_type \u0026ps) const noexcept;` |\n| `iterator find(const predicate_list_type \u0026ps) noexcept;`     |\n| Find intersection between point and container                |\n| `iterator find_intersection(const key_type \u0026p);`           |\n| `const_iterator find_intersection(const key_type \u0026p) const;` |\n| Find intersection between container and query box            |\n| `iterator find_intersection(const key_type \u0026lb, const key_type \u0026ub);` |\n| `const_iterator find_intersection(const key_type \u0026lb, const key_type \u0026ub) const;` |\n| Find points inside a query box (excluding borders)           |\n| `iterator find_within(const key_type \u0026lb, const key_type \u0026ub);` |\n| `const_iterator find_within(const key_type \u0026lb, const key_type \u0026ub) const` |\n| Find points outside a query box                              |\n| `iterator find_disjoint(const key_type \u0026lb, const key_type \u0026ub);` |\n| `const_iterator find_disjoint(const key_type \u0026lb, const key_type \u0026ub) const;` |\n| Find the elements closest to a point                         |\n| `iterator find_nearest(const key_type \u0026p);`                |\n| `const_iterator find_nearest(const key_type \u0026p) const;`    |\n| `iterator find_nearest(const key_type \u0026p, size_t k);`      |\n| `const_iterator find_nearest(const key_type \u0026p, size_t k) const;` |\n| `iterator find_nearest(const box_type \u0026b, size_t k);`        |\n| `const_iterator find_nearest(const box_type \u0026b, size_t k) const;` |\n| Find min/max elements                                        |\n| `iterator max_element(size_t dimension)`                     |\n| `const_iterator max_element(size_t dimension) const`         |\n| `iterator min_element(size_t dimension)`                     |\n| `const_iterator min_element(size_t dimension) const`         |\n\n**Parameters**\n\n* `ps` - a list of predicates\n* `p` - a point of type `key_value` or convertible to `key_value`\n* `lb` and `ub` - lower and upper bounds of the query box\n* `k` - number of nearest elements\n\n**Return value**\n\n* `count()`: `size_type`: number of elements with a given key\n* `container()`: `bool`: `true` if and only if the container contains an element with the given key `p`\n* `find_*`: `iterator` and `const_iterator` - Iterator to the first element that passes the query predicates\n  * `find` returns a normal iterator\n  * all other `find_*` functions return a query iterator (see below)\n* `size_type` - Number of elements erased\n\n**Complexity**\n\n$$\nO(m \\log n)\n$$\n\n**Notes**\n\n**Query iterators** might store a list of predicates that limit iterators to query results. A query iterator skips all elements that do not match its predicates.\n\nThere are five types of predicates:\n\n|  Predicate type           |   Description     |\n|---------------------------|-------------------|\n| `intersects`            |   return only elements that intersect a given query box.   |\n| `within`            |   return only elements within a given query box. This is the same as `intersects` but it excludes the borders.   |\n| `disjoint`            |   return only elements that do not intersect a given query box.   |\n| `nearest`            |   return only the $k$ nearest elements to a reference point or query box.   |\n| `satisfies`            |   return only elements that pass a predicate provided by the user.   |\n\n!!! info \"Predicate lists\"\n    Query iterators contain an element of type `pareto::predicate_list`. \n    When a `predicate_list` is being constructed, it will:\n    1) compress to predicates to eliminate any redundancy in the search requirements, and \n    2) sort the predicates by how restrictive they are so that the search for the next element is as efficient as possible.\n\n!!! warning \"Comparing Iterators\"\n    Although a normal iterator and a query iterator that point to the same element compare equal, this does not mean their `operator++` will return the same element. The past-the-end element of all query iterators is also the `end()` iterator.\n\n!!! warning \"Lower and Upper bounds\"\n    Because of how spatial container work, we do not guarantee equivalent elements are necessarily stored in sequence. Thus, unlike `std::multimap` there are no `equal_range`, `lower_bound` and `upper_bound` functions. The same behaviour must be achieved with the `find_intersection` function.\n\n**Examples**\n\nContinuing from the previous example:\n\n=== \"C++\"\n\n    ```cpp\n    for (auto it = m.find_intersection({-10,-10,-10}, {-2.3912, 0.395611, 2.78224}); it != m.end(); ++it) {\n        std::cout \u003c\u003c it-\u003efirst \u003c\u003c \" -\u003e \" \u003c\u003c it-\u003esecond \u003c\u003c std::endl;\n    }\n    for (auto it = m.find_within({-10,-10,-10}, {-2.3912, 0.395611, 2.78224}); it != m.end(); ++it) {\n        std::cout \u003c\u003c it-\u003efirst \u003c\u003c \" -\u003e \" \u003c\u003c it-\u003esecond \u003c\u003c std::endl;\n    }\n    for (auto it = m.find_disjoint({-10,-10,-10}, {+0.71, +1.19, +0.98}); it != m.end(); ++it) {\n        std::cout \u003c\u003c it-\u003efirst \u003c\u003c \" -\u003e \" \u003c\u003c it-\u003esecond \u003c\u003c std::endl;\n    }\n    for (auto it = m.find_nearest({-2.3912, 0.395611, 2.78224}, 2); it != m.end(); ++it) {\n        std::cout \u003c\u003c it-\u003efirst \u003c\u003c \" -\u003e \" \u003c\u003c it-\u003esecond \u003c\u003c std::endl;\n    }\n    auto it = m.find_nearest({2.5, 2.5, 2.5});\n    std::cout \u003c\u003c it-\u003efirst \u003c\u003c \" -\u003e \" \u003c\u003c it-\u003esecond \u003c\u003c std::endl;\n    ```\n\n=== \"Python\"\n\n    ```python\n    for [point, value] in m.find_intersection(pareto.point([-10, -10, -10]), pareto.point([-1.21188, -1.24192, +10])):\n        print(point, '-\u003e', value)\n\n    for [point, value] in m.find_within(pareto.point([-10, -10, -10]), pareto.point([-1.21188, -1.24192, +10])):\n        print(point, '-\u003e', value)\n    \n    for [point, value] in m.find_disjoint(pareto.point([+0.2, +0.19, -1]), pareto.point([+0.71, +1.19, +10])):\n        print(point, '-\u003e', value)\n    \n    for [point, value] in m.find_nearest(pareto.point([-1.21188, -1.24192, 10]), 2):\n        print(point, '-\u003e', value)\n    \n    for [point, value] in m.find_nearest(pareto.point([2.5, 2.5, 10])):\n        print(point, '-\u003e', value)\n    ```\n\n=== \"Output\"\n\n    ```console\n    [-2.57664, -1.52034, 0.600798] -\u003e 17\n    [-2.55905, -0.271349, 0.898137] -\u003e 6\n    [-2.3912, 0.395611, 2.78224] -\u003e 11\n    [-2.57664, -1.52034, 0.600798] -\u003e 17\n    [-2.55905, -0.271349, 0.898137] -\u003e 6\n    [-2.3912, 0.395611, 2.78224] -\u003e 11\n    [-0.639149, 1.89515, 0.858653] -\u003e 10\n    [-0.401531, 2.30172, 0.58125] -\u003e 39\n    [-1.09756, 1.33135, 0.569513] -\u003e 20\n    [-1.45049, 1.35763, 0.606019] -\u003e 17\n    [-0.00292544, 1.29632, -0.578346] -\u003e 20\n    [0.0728106, 1.91877, 0.399664] -\u003e 25\n    [0.152711, 1.99514, -0.112665] -\u003e 13\n    [0.157424, 2.30954, -1.23614] -\u003e 6\n    [-2.3912, 0.395611, 2.78224] -\u003e 11\n    [-2.55905, -0.271349, 0.898137] -\u003e 6\n    [0.0728106, 1.91877, 0.399664] -\u003e 25\n    ```\n\n### Observers\n\n| Method                                                       |\n| ------------------------------------------------------------ |\n| **Multimap**                                                 |\n| Returns the function that compares keys                      |\n| `key_compare key_comp() const noexcept;`                     |\n| Returns the function that compares keys in objects of type value_type |\n| `value_compare value_comp() const noexcept`                  |\n| **SpatialMap**                                               |\n| Returns the function that compares keys in a single dimension |\n| `dimension_compare dimension_comp() const noexcept;`               |\n\n**Return value**\n\nA callable function that compares dimensions, keys, or values.\n\n**Complexity**\n\n$$\nO(1)\n$$\n\n**Notes**\n\nThese functions return copies of the container's constructor argument `comp`, or a wrappers around these copies.\n\n!!! info \"Observers\"\n    These observers are useful in template functions that might receive spatial containers unknown to the function.    \n    \n    Most applications don't really need these observers. If you created the container, you already know the container compares its keys.  \n\n=== \"C++\"\n\n    ```cpp\n    auto fn = m.dimension_comp();\n    if (fn(2.,3.)) {\n        std::cout \u003c\u003c \"2 is less than 3\" \u003c\u003c std::endl;\n    } else {\n        std::cout \u003c\u003c \"2 is not less than 3\" \u003c\u003c std::endl;\n    }\n    ```\n\n=== \"Output\"\n\n    ```console\n    2 is less than 3\n    ```\n\n### Relational Operators\n\nThese are non-member functions.\n\n| Method                                                       |\n| ------------------------------------------------------------ |\n| **Multimap**                                                 |\n| Compares the values in the multimap                          |\n| `template \u003cclass K, size_t M, class T, class C, class A\u003e bool operator==(const spatial_map\u003cK, M, T, C, A\u003e \u0026lhs, const spatial_map\u003cK, M, T, C, A\u003e \u0026rhs);` |\n| `template \u003cclass K, size_t M, class T, class C, class A\u003e bool operator!=(const spatial_map\u003cK, M, T, C, A\u003e \u0026lhs, const spatial_map\u003cK, M, T, C, A\u003e \u0026rhs);` |\n\n**Parameters**\n\n* `lhs`, `rhs` - `spatial_map`s whose contents to compare\n\n**Return value**\n\n`true` if the **internal** contents of the `spatial_map`s are equal, false otherwise. \n\n**Complexity**\n\n$$\nO(n)\n$$\n\n**Notes**\n\n!!! warning\n    This operator tells us if the internal trees are equal and not if they contain the same elements. This is because the standard defines that this operation should take $O(n)$ time. Two trees might contain the same elements in different subtrees if their insertion order was different. \n\n    If you need to compare if *the elements* of `lhs` and `rhs` are the same, regardless of their internal representation, you have to iterate `lhs` and iteratively call `find` on the second container. This operation takes $O(m n \\log n)$ time.\n\nWe do not include `operator\u003c`,  `operator\u003e`,  `operator\u003c=`,  `operator\u003e=` for spatial containers because [std::lexicographical_compare](https://en.cppreference.com/w/cpp/algorithm/lexicographical_compare) would be semantically meaningless in a multidimensional context where we need to return a value in $O(n)$ time and, by definition, there is no priority between key dimensions. \n\n**Example**\n\n=== \"C++\"\n\n    ```cpp\n    spatial_map\u003cdouble, 3, unsigned\u003e m2(m);\n    if (m == m2) {\n        std::cout \u003c\u003c \"The containers have the same elements\" \u003c\u003c std::endl;\n    } else {\n        if (m.size() != m2.size()) {\n            std::cout \u003c\u003c \"The containers do not have the same elements\" \u003c\u003c std::endl;\n        } else {\n            std::cout \u003c\u003c \"The containers might not have the same elements\" \u003c\u003c std::endl;\n            // You need a for loop after here to make sure\n        }\n    }\n\n    spatial_map\u003cdouble, 3, unsigned\u003e m3(m.begin(), m.end());\n    if (m == m3) {\n        std::cout \u003c\u003c \"The containers have the same elements\" \u003c\u003c std::endl;\n    } else {\n        if (m.size() != m3.size()) {\n            std::cout \u003c\u003c \"The containers do not have the same elements\" \u003c\u003c std::endl;\n        } else {\n            std::cout \u003c\u003c \"The containers might not have the same elements\" \u003c\u003c std::endl;\n            // You need a for loop after here to make sure\n        }\n    }\n    ```\n\n=== \"Python\"\n\n    ```python\n    m2 = pareto.spatial_map(m)\n    if m == m2:\n        print('The containers have the same elements')\n    else:\n        if len(m) != len(m2):\n            print('The containers do not have the same elements')\n        else:\n            print('The containers might not have the same elements')\n            # You need a for loop after here to make sure\n    \n    m3 = pareto.spatial_map()\n    for [k, v] in m:\n        m3[k] = v\n    \n    if m == m3:\n        print('The containers have the same elements')\n    else:\n        if len(m) != len(m3):\n            print('The containers do not have the same elements')\n        else:\n            print('The containers might not have the same elements')\n            # You need a for loop after here to make sure\n    ```\n\n=== \"Output\"\n\n    ```console\n    The containers have the same elements\n    The containers might not have the same elements\n    ```\n\n## Front Container\n\n### Front Concept\n\nMost lifelike problems involve several conflicting goals. For this reason, the concepts of Pareto fronts and archives have applications that range from economics to engineering. In Game Theory, we have these kinds of outcomes:\n\n|  Outcome        |    Description      |\n|-----------------|---------------------|\n| **Pareto efficient** or **Pareto optimal** | No other outcome can increase the utility in one goal without decreasing the utility of any other goal |\n| **Pareto inefficient** | There is another that can improve at least one goal without harming other goals |\n| **Pareto improvement** over $p$ | Better than the Pareto inefficient outcome $p$ |\n| **Pareto dominated** by $p$ | Outcome $p$ can improve at least one goal without harming other goals |\n| **Pareto dominated** by $p$ | Outcome $p$ can improve at least one goal without harming other goals |\n\nAlthough many outcomes can be Pareto optimal, no outcome dominates an outcome that is Pareto optimal. The set of all Pareto optimal outcomes is the **Pareto front** (also *Pareto frontier*, or *Pareto set*).\n\n!!! example \"Example: Pareto front\"\n    This is a two-dimensional Pareto front. The region in gray is dominated by the front.\n    \n    ![2-dimensional front](docs/img/front2d_b.svg)\n\n    In this example, we consider lower values of $f(x)$ to be a gain of utility\n\n!!! summary \"Formal Definition: Pareto front\"\n    The set $P$ of all Pareto optimal outcomes, is defined as\n\n    $$\n    P = \\{\\; x \\;|\\; \\tilde \\exists y\\; \\exists i\\; (f_i(y) \u003c f_i(x)) \\;\\} = \\{\\; x \\;|\\; \\tilde \\exists y\\; (y \\prec x)\\}\n    $$\n\n    where $f_i(x)$ is the $i$-th goal in our problem\n\nEvery game has at least one outcome that is Pareto optimal.\n\nThe container `pareto::front` is an extension and an adapter of spatial containers for Pareto fronts. The container uses query predicates to find and erase any dominated solution whenever a new solution is inserted.\n\n### Types\n\nThis table summarizes the public types in a `pareto::front\u003cK,M,T,C\u003e`:\n\n| Concept/Type Name                                            | Type                                                         | Notes                                                        |\n| ------------------------------------------------------------ | ------------------------------------------------------------ | ------------------------------------------------------------ |\n| [**Container**](https://en.cppreference.com/w/cpp/named_req/Container) |                                                              |                                                              |\n| `value_type`                                                 | `container_type::value_type`                                 | The pair key is `const`, like in other associative containers |\n| `reference`                                                  | `value_type\u0026`                                                |                                                              |\n| `const_reference`                                            | `value_type const \u0026`                                         |                                                              |\n| `iterator`                                                   | Iterator pointing to a `value_type`                          | A [LegacyBidirectionalIterator](https://en.cppreference.com/w/cpp/named_req/ForwardIterator) convertible to `const_iterator` |\n| `const_iterator`                                             | Iterator pointing to a `const value_type`                    | Implements [LegacyBidirectionalIterator](https://en.cppreference.com/w/cpp/named_req/ForwardIterator) concept |\n| `difference_type`                                            | A signed integer                                             |                                                              |\n| `size_type`                                                  | An unsigned integer                                          |                                                              |\n| [**ReversibleContainer**](https://en.cppreference.com/w/cpp/named_req/ReversibleContainer) |                                                              |                                                              |\n| `reverse_iterator`                                           | `std::reverse_iterator\u003citerator\u003e`                            |                                                              |\n| `const_reverse_iterator`                                     | `std::reverse_iterator\u003cconst_iterator\u003e`                      |                                                              |\n| [**AssociativeContainer**](https://en.cppreference.com/w/cpp/named_req/AssociativeContainer) |                                                              |                                                              |\n| `key_type`                                                   | `pareto::point\u003cK,M\u003e`                                         | Unlike in `value_type`, `key_type`  is not const, so you can use it to construct and manipulate new points |\n| `mapped_type`                                                | `T`                                                          |                                                              |\n| `key_compare`                                                | `std::function\u003cbool(const value_type \u0026, const value_type \u0026)\u003e` | `key_compare` defines a lexicographic ordering relation over keys using `dimension_compare` |\n| `value_compare`                                              | `std::function\u003cbool(const value_type \u0026, const value_type \u0026)\u003e` | `value_compare` defines an ordering relation over `value_type` using `key_compare` |\n| [**AllocatorAwareContainer**](https://en.cppreference.com/w/cpp/named_req/AllocatorAwareContainer) |                                                              |                                                              |\n| `allocator_type`                                             | `container_type::allocator_type`                             | `allocator_type::value_type` is the same as `value_type`     |\n| **SpatialContainer**                                         |                                                              |                                                              |\n| `dimension_type`                                                | `K`                                                          |                                                              |\n| `dimension_compare`                                             | `container_type::dimension_compare`, or `std::less\u003cK\u003e` by default | `dimension_compare` defines an ordering relation over each `key_value` dimension using `C` |\n| `box_type`                                                   | `pareto::query_box\u003cdimension_type, M\u003e`                          |                                                              |\n| `predicate_list_type`                                        | `pareto::predicate_list\u003cdimension_type, M, T\u003e`                  |                                                              |\n| **SpatialAdapter**                                           |                                                              |                                                              |\n| `container_type`                                             | `C`                                                          | `C` needs to follow the SpatialContainer concept             |\n\n**Notes**\n\nThe underlying container `C` (or `front::container_type`) used to store the values also needs to be a **SpatialContainer**. The allocator type and comparison functions are provided by these containers. If no container is provided, the default `pareto::spatial_map` is used as default. \n\n!!! tip \"Concepts\"\n    All other requirements of a **SpatialContainer** also apply here. Even if you only intend to use fronts in your application, we recommend you to read the sections on spatial containers.\n\n!!! note \"Container Adapters\"\n    The type names and template parameters for the *SpatialAdapter* concept are inspired by other container adapters, such as `std::stack`. However, `pareto::front` is both an adapter and an extension of `SpatialContainer`. That is, unlike `std::stack`, its interface expands on top of the underlying container rather than limiting it.\n\n### Constructors\n\n| Method                                                       |\n| ------------------------------------------------------------ |\n| **Container** + **AllocatorAwareContainer** Constructors     |\n| `explicit front(const allocator_type \u0026alloc = allocator_type())` |\n| `front(const front \u0026rhs)`                                    |\n| `front(const front \u0026rhs, const allocator_type \u0026alloc)`       |\n| `front(front \u0026\u0026rhs) noexcept`                                |\n| `front(front \u0026\u0026rhs, const allocator_type \u0026alloc) noexcept`   |\n| **AssociativeContainer** + **AllocatorAwareContainer** Constructors |\n| `explicit front(const C \u0026comp, const allocator_type \u0026alloc = allocator_type())` |\n| `template \u003cclass InputIt\u003e front(InputIt first, InputIt last, const C \u0026comp = C(), const allocator_type \u0026alloc = allocator_type())` |\n| `front(std::initializer_list\u003cvalue_type\u003e il, const C \u0026comp = C(), const allocator_type \u0026alloc = allocator_type())` |\n| `template \u003cclass InputIt\u003e front(InputIt first, InputIt last, const allocator_type \u0026alloc)` |\n| `front(std::initializer_list\u003cvalue_type\u003e il, const allocator_type \u0026alloc)` |\n| **FrontContainer**                                          |\n| `template \u003cclass InputIt, class DirectionIt\u003e front(InputIt first, InputIt last, DirectionIt first_dir, DirectionIt last_dir,       const dimension_compare \u0026comp = dimension_compare(), const allocator_type \u0026alloc = allocator_type())` |\n| `template \u003cclass DirectionIt\u003e front(std::initializer_list\u003cvalue_type\u003e il, DirectionIt first_dir, DirectionIt last_dir, const dimension_compare \u0026comp = dimension_compare(), const allocator_type \u0026alloc = construct_allocator\u003callocator_type\u003e())` |\n| `template \u003cclass InputIt\u003e front(InputIt first, InputIt last, std::initializer_list\u003cbool\u003e il_dir, const dimension_compare \u0026comp = dimension_compare(), const allocator_type \u0026alloc = construct_allocator\u003callocator_type\u003e())` |\n| `front(std::initializer_list\u003cvalue_type\u003e il, std::initializer_list\u003cbool\u003e il_dir, const dimension_compare \u0026comp = dimension_compare(),       const allocator_type \u0026alloc = construct_allocator\u003callocator_type\u003e())` |\n| `front(std::initializer_list\u003cbool\u003e il_dir, const dimension_compare \u0026comp = dimension_compare(), const allocator_type \u0026alloc = construct_allocator\u003callocator_type\u003e())` |\n| `template \u003cclass InputIt, class DirectionIt\u003e front(InputIt first, InputIt last, DirectionIt first_dir, DirectionIt last_dir, const allocator_type \u0026alloc)` |\n| `template \u003cclass DirectionIt\u003e front(std::initializer_list\u003cvalue_type\u003e il, DirectionIt first_dir, DirectionIt last_dir, const allocator_type \u0026alloc)` |\n| `template \u003cclass InputIt\u003e front(InputIt first, InputIt last, std::initializer_list\u003cbool\u003e il_dir, const allocator_type \u0026alloc)` |\n| `front(std::initializer_list\u003cvalue_type\u003e il, std::initializer_list\u003cbool\u003e il_dir, const allocator_type \u0026alloc)` |\n| `front(std::initializer_list\u003cbool\u003e il_dir, const allocator_type \u0026alloc)` |\n| **AssociativeContainer** + **AllocatorAwareContainer** Assignment |\n| `front \u0026operator=(const front \u0026rhs)`                         |\n| `front \u0026operator=(front \u0026\u0026rhs) noexcept`                     |\n| **AssociativeContainer** Assignment                          |\n| `front \u0026operator=(std::initializer_list\u003cvalue_type\u003e il) noexcept` |\n\n**Parameters**\n\n| Parameter               | Description                                                  |\n| ----------------------- | ------------------------------------------------------------ |\n| `alloc`                 | allocator to use for all memory allocations of this container |\n| `comp`                  | comparison function object to use for all comparisons of keys |\n| `first`, `last`         | the range to copy the elements from                          |\n| `rhs`                   | another container to be used as source to initialize the elements of the container with |\n| `il`                    | initializer list to initialize the elements of the container with |\n| `first_dir`, `last_dir` | the range to copy the target directions from                 |\n| `il_dir`                | initializer list to initialize the target directions of the container with |\n\n**Requirements**\n\n| Type requirements                                            |\n| ------------------------------------------------------------ |\n| -`InputIt` and `DirectionIt` must meet the requirements of [*LegacyInputIterator*](https://en.cppreference.com/w/cpp/named_req/InputIterator). |\n| -`Compare` must meet the requirements of [*Compare*](https://en.cppreference.com/w/cpp/named_req/Compare). |\n| -`Allocator` must meet the requirements of [*Allocator*](https://en.cppreference.com/w/cpp/named_req/Allocator). |\n\n**Complexity**\n\n| Method                              | Complexity                                         |\n| ----------------------------------- | -------------------------------------------------- |\n| Empty constructor                   | $O(1)$                                             |\n| Copy constructor                    | $O(mn)$                                            |\n| Move constructor                    | $O(1)$ if `get_allocator() == rhs.get_allocator()` |\n| Construct from range, or assignment | $O(m n \\log n)$                                    |\n\n**Notes**\n\nAll constructors in **FrontContainer** replicate the constructors for spatial containers with an extra parameter to provide target directions (minimization / maximization). If the dimensions are not supposed to be minimized, we can define one optimization direction for each dimension. \n\n!!! note \"Default directions\"\n    By default, all directions are minimized. Whenever we insert an element in a front, it erases all elements dominated by the new solution:\n\n    ![2-dimensional front](docs/img/front2d_b.svg)\n\n!!! example \"Varying directions\"\n    If we set all directions to `maximization`, this is what a 2-dimensional front looks like:\n    \n    ![2-dimensional front](docs/img/front2d.svg)\n\n    And these are the combinations for two-dimensional fronts:\n\n    ![2-dimensional front](docs/img/front2d_directions.svg)\n    \n    In more than two dimensions, we usually represent fronts with parallel coordinates:\n    \n    ![2-dimensional front](docs/img/front3d.svg)\n\n!!! tip \"Plotting fronts\"\n    The header [`pareto/matplot/front.h`](source/pareto/matplot/front.h) contains an example of a function to plot fronts with [Matplot++](https://github.com/alandefreitas/matplotplusplus). The file [`examples/matplotpp_example.cpp`](examples/matplotpp_example.cpp) includes an example that uses these plot functions. In Python, you can use [Matplotlib](https://matplotlib.org) like you would with any other linear list of points.\n\n**Example**\n\n=== \"C++\"\n\n    ```cpp\n    #include \u003cpareto/front.h\u003e\n    #include \u003cpareto/kd_tree.h\u003e\n    // ...\n    // Constructing the default front\n    front\u003cdouble, 3, unsigned\u003e pf({min, max, min});\n    // Constructing a front based on kd trees\n    front\u003cdouble, 3, unsigned, kd_tree\u003cdouble, 3, unsigned\u003e\u003e pf2({min, max, min});\n    ```\n\n=== \"Python\"\n\n    ```python\n    import pareto\n    # ...\n    # Constructing the default front\n    pf = pareto.front(['min', 'max', 'min']);\n    # Constructing a front based on kd trees\n    pf2 = pareto.kd_front(['min', 'max', 'min']);\n    ```\n\n### Allocators\n\n| Method                                           |\n| ------------------------------------------------ |\n| **AllocatorAwareContainer**                      |\n| `allocator_type get_allocator() const noexcept;` |\n\n**Return value**\n\nThe associated allocator.\n\n**Complexity**\n\n$$\nO(1)\n$$\n\n**Notes**\n\nThis function returns the allocator of the underlying container. \n\n!!! info\n    See the section on spatial map allocators for more information.\n\n**Example**\n\n=== \"C++\"\n\n    ```cpp\n    #include \u003cpareto/front.h\u003e\n    // ...\n    pareto::front\u003cdouble, 3, unsigned\u003e pf;\n    // Get a copy of the container allocator\n    auto alloc = pf.get_allocator();\n    ```\n\n### Element Access\n\n| Method                                                       |\n| ------------------------------------------------------------ |\n| **MapContainer**                                             |\n| Access and throw exception if it doesn't exist               |\n| `mapped_type \u0026at(const key_type \u0026k);`                        |\n| `const mapped_type \u0026at(const key_type \u0026k) const;`            |\n| Access and create new element if it doesn't exist            |\n| `mapped_type \u0026operator[] (const key_type \u0026k);`                |\n| `mapped_type \u0026operator[] (key_type \u0026\u0026k);`                     |\n| `template \u003ctypename... Targs\u003e mapped_type \u0026operator()(const dimension_type \u0026x1, const Targs \u0026...xs);` |\n\n**Parameters**\n\n* `k` - the key of the element to find\n* `x1` - the value of the element to find in the first dimension\n* `xs` - the value of the element to find in other dimensions\n\n**Return value**\n\nA reference to the element associated with that key.\n\n**Exceptions**\n\n[`std::out_of_range`](https://en.cppreference.com/w/cpp/error/out_of_range) if the container does not have an element with the specified `key`\n\n**Complexity**\n\n$$\nO(m \\log n)\n$$\n\n**Notes**\n\nUnlike in a `pareto::spatial_map`, the `insert` operation for fronts is allowed to fail when the new element is already dominated by the front. In this case, the `operator[]` will return a reference to a placeholder that is not ultimately inserted in the front.\n\n!!! info\n    See the section on spatial containers / element access for more information.\n\n**Example**\n\n=== \"C++\"\n\n    ```cpp\n    front\u003cdouble, 3, unsigned\u003e pf({min, max, min});\n    // Set some values\n    pf(-2.57664, -1.52034, 0.600798) = 17;\n    pf(-2.14255, -0.518684, -2.92346) = 32;\n    pf(-1.63295, 0.912108, -2.12953) = 36;\n    pf(-0.653036, 0.927688, -0.813932) = 13;\n    pf(-0.508188, 0.871096, -2.25287) = 32;\n    pf(-2.55905, -0.271349, 0.898137) = 6;\n    pf(-2.31613, -0.219302, 0) = 8;\n    pf(-0.639149, 1.89515, 0.858653) = 10;\n    pf(-0.401531, 2.30172, 0.58125) = 39;\n    pf(0.0728106, 1.91877, 0.399664) = 25;\n    pf(-1.09756, 1.33135, 0.569513) = 20;\n    pf(-0.894115, 1.01387, 0.462008) = 11;\n    pf(-1.45049, 1.35763, 0.606019) = 17;\n    pf(0.152711, 1.99514, -0.112665) = 13;\n    pf(-2.3912, 0.395611, 2.78224) = 11;\n    pf(-0.00292544, 1.29632, -0.578346) = 20;\n    pf(0.157424, 2.30954, -1.23614) = 6;\n    pf(0.453686, 1.02632, -2.24833) = 30;\n    pf(0.693712, 1.12267, -1.37375) = 12;\n    pf(1.49101, 3.24052, 0.724771) = 24;\n\n    // Access value\n    if (pf.contains({1.49101, 3.24052, 0.724771})) {\n        std::cout \u003c\u003c \"Element access: \" \u003c\u003c pf(1.49101, 3.24052, 0.724771) \u003c\u003c std::endl;\n    } else {\n        std::cout \u003c\u003c \"{1.49101, 3.24052, 0.724771} was dominated\" \u003c\u003c std::endl;\n    }\n    ```\n\n=== \"Python\"\n\n    ```python\n    pf = pareto.front()\n    # Set some values\n    pf[-2.57664, -1.52034, 0.600798] = 17\n    pf[-2.14255, -0.518684, -2.92346] = 32\n    pf[-1.63295, 0.912108, -2.12953] = 36\n    pf[-0.653036, 0.927688, -0.813932] = 13\n    pf[-0.508188, 0.871096, -2.25287] = 32\n    pf[-2.55905, -0.271349, 0.898137] = 6\n    pf[-2.31613, -0.219302, 0] = 8\n    pf[-0.639149, 1.89515, 0.858653] = 10\n    pf[-0.401531, 2.30172, 0.58125] = 39\n    pf[0.0728106, 1.91877, 0.399664] = 25\n    pf[-1.09756, 1.33135, 0.569513] = 20\n    pf[-0.894115, 1.01387, 0.462008] = 11\n    pf[-1.45049, 1.35763, 0.606019] = 17\n    pf[0.152711, 1.99514, -0.112665] = 13\n    pf[-2.3912, 0.395611, 2.78224] = 11\n    pf[-0.00292544, 1.29632, -0.578346] = 20\n    pf[0.157424, 2.30954, -1.23614] = 6\n    pf[0.453686, 1.02632, -2.24833] = 30\n    pf[0.693712, 1.12267, -1.37375] = 12\n    pf[1.49101, 3.24052, 0.724771] = 24\n    \n    # Access value\n    if [1.49101, 3.24052, 0.724771] in pf:\n        print('Element access:', pf[1.49101, 3.24052, 0.724771])\n    else:\n        print(\"[1.49101, 3.24052, 0.724771] was dominated\")\n\n    ```\n\n=== \"Output\"\n\n    ```console\n    Element access: 24\n    ```\n\n\n### Iterators\n\n| Method                                                       |\n| ------------------------------------------------------------ |\n| **MultimapContainer**                                        |\n| Get constant iterators                                       |\n| `const_iterator begin() const noexcept;`                     |\n| `const_iterator end() const noexcept;`                       |\n| `const_iterator cbegin() const noexcept;`                    |\n| `const_iterator cend() const noexcept;`                      |\n| Get iterators                                                |\n| `iterator begin() noexcept;`                                 |\n| `iterator end() noexcept;`                                   |\n| Get reverse iterators                                        |\n| `std::reverse_iterator\u003cconst_iterator\u003e rbegin() const noexcept;` |\n| `std::reverse_iterator\u003cconst_iterator\u003e rend() const noexcept;` |\n| `std::reverse_iterator\u003citerator\u003e rbegin() noexcept`;         |\n| `std::reverse_iterator\u003citerator\u003e rend() noexcept;`           |\n| Get constant reverse iterators                               |\n| `std::reverse_iterator\u003cconst_iterator\u003e crbegin() const noexcept;` |\n| `std::reverse_iterator\u003cconst_iterator\u003e crend() const noexcept;` |\n\n**Return value**\n\n* `begin()` - Iterator to the first element in the container\n* `end()` - Iterator to the past-the-end element in the container (see notes)\n\n**Complexity**\n\n$$\nO(1)\n$$\n\n**Notes**\n\nAll requirements of a **SpatialContainer** also apply here.\n\n!!! info\n    See the section on spatial containers / iterators for more information.\n\n**Example**\n\nContinuing from the previous example:\n\n=== \"C++\"\n\n    ```cpp\n    std::cout \u003c\u003c \"Iterators:\" \u003c\u003c std::endl;\n    for (const auto\u0026 [point, value]: pf) {\n        std::cout \u003c\u003c point \u003c\u003c \" -\u003e \" \u003c\u003c value \u003c\u003c std::endl;\n    }\n\n    std::cout \u003c\u003c \"Reversed Iterators:\" \u003c\u003c std::endl;\n    for (auto it = pf.rbegin(); it != pf.rend(); ++it) {\n        std::cout \u003c\u003c it-\u003efirst \u003c\u003c \" -\u003e \" \u003c\u003c it-\u003esecond \u003c\u003c std::endl;\n    }\n    ```\n\n=== \"Python\"\n\n    ```python\n    print('Iterators')\n    for [point, value] in m:\n        print(point, '-\u003e', value)\n    \n    print('Reversed Iterators')\n    for [point, value] in reversed(m):\n        print(point, '-\u003e', value)\n    ```\n\n=== \"Output\"\n\n    ```console\n    Iterators:\n    [-2.14255, -0.518684, -2.92346] -\u003e 32\n    [-1.63295, 0.912108, -2.12953] -\u003e 36\n    [-0.653036, 0.927688, -0.813932] -\u003e 13\n    [-0.508188, 0.871096, -2.25287] -\u003e 32\n    [0.453686, 1.02632, -2.24833] -\u003e 30\n    [0.693712, 1.12267, -1.37375] -\u003e 12\n    [-2.57664, -1.52034, 0.600798] -\u003e 17\n    [-2.55905, -0.271349, 0.898137] -\u003e 6\n    [-2.31613, -0.219302, 0] -\u003e 8\n    [-0.894115, 1.01387, 0.462008] -\u003e 11\n    [-2.3912, 0.395611, 2.78224] -\u003e 11\n    [-0.639149, 1.89515, 0.858653] -\u003e 10\n    [-0.401531, 2.30172, 0.58125] -\u003e 39\n    [-1.09756, 1.33135, 0.569513] -\u003e 20\n    [-1.45049, 1.35763, 0.","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Falandefreitas%2Fpareto","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Falandefreitas%2Fpareto","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Falandefreitas%2Fpareto/lists"}