diff --git a/.gitignore b/.gitignore index 5b7b68c77..27b93db12 100644 --- a/.gitignore +++ b/.gitignore @@ -1,3 +1,6 @@ +# Added +/docs/html/ +docs/source/autoapi/ # Compiled files *.py[cod] *.a @@ -46,4 +49,3 @@ htmlcov # Mac OSX .DS_Store -/docs/html/ diff --git a/asv/__init__.py b/asv/__init__.py index f0ca73483..9950fe1ac 100644 --- a/asv/__init__.py +++ b/asv/__init__.py @@ -1,6 +1,9 @@ # Licensed under a 3-clause BSD style license - see LICENSE.rst -from asv._version import version as __version__ +from importlib_metadata import version as get_version + from asv import plugin_manager # noqa F401 Needed to load the plugins +__version__ = get_version("asv") + __all__ = '__version__', diff --git a/asv/statistics.py b/asv/_stats.py similarity index 92% rename from asv/statistics.py rename to asv/_stats.py index b6549e9b8..ad2709b94 100644 --- a/asv/statistics.py +++ b/asv/_stats.py @@ -76,8 +76,9 @@ def mann_whitney_u(x, y, method='auto'): """ Mann-Whitney U test - Ties are handled conservatively, returning the least significant - tie breaking. + Ties are handled conservatively, returning the least significant tie + breaking. + :cite:empty:`mwu-mannTestWhetherOne1947,mwu-gibbonsNonparametricStatisticalInference2010`. Parameters ---------- @@ -96,8 +97,10 @@ def mann_whitney_u(x, y, method='auto'): References ---------- - .. [1] Mann & Whitney, Ann. Math. Statist. 18, 50 (1947). - .. [2] Gibbons & Chakraborti, "Nonparametric statistical inference". (2003) + .. bibliography:: + :filter: docname in docnames + :labelprefix: MWU_ + :keyprefix: mwu- """ memo = _mann_whitney_u_memo @@ -177,11 +180,19 @@ def mann_whitney_u_r(m, n, u, memo=None): Number of orderings in Mann-Whitney U test. The PMF of U for samples of sizes (m, n) is given by - p(u) = r(m, n, u) / binom(m + n, m). + :cite:empty:`mwur-mannTestWhetherOne1947` + + .. code-block:: + + p(u) = r(m, n, u) / binom(m + n, m). References ---------- - .. [1] Mann & Whitney, Ann. Math. Statist. 18, 50 (1947). + .. bibliography:: + :filter: docname in docnames + :labelprefix: MWUR_ + :keyprefix: mwur- + """ if u < 0: value = 0 diff --git a/asv/commands/__init__.py b/asv/commands/__init__.py index 0790fc8e7..b61af95e9 100644 --- a/asv/commands/__init__.py +++ b/asv/commands/__init__.py @@ -14,7 +14,6 @@ 'Machine', 'Setup', 'Run', - 'Dev', 'Continuous', 'Find', 'Rm', diff --git a/asv/commands/common_args.py b/asv/commands/common_args.py index 94dc8e899..13f614cd0 100644 --- a/asv/commands/common_args.py +++ b/asv/commands/common_args.py @@ -5,7 +5,9 @@ import multiprocessing import argparse -from .. import __version__, util +from importlib_metadata import version as get_version + +from asv import util def add_global_arguments(parser, suppress_defaults=True): @@ -29,7 +31,8 @@ def add_global_arguments(parser, suppress_defaults=True): default=(argparse.SUPPRESS if suppress_defaults else None)) parser.add_argument( - "--version", action="version", version="%(prog)s " + __version__, + "--version", action="version", + version="%(prog)s " + get_version("asv"), help="Print program version", **suppressor) diff --git a/asv/commands/compare.py b/asv/commands/compare.py index 4e53d61d3..14b3cd072 100644 --- a/asv/commands/compare.py +++ b/asv/commands/compare.py @@ -15,7 +15,7 @@ from ..util import human_value, load_json from ..console import log from ..environment import get_environments -from .. import util, statistics +from .. import util, _stats def mean(values): @@ -76,7 +76,7 @@ def _is_result_better(a, b, a_ss, b_ss, factor, use_stats=True): # Special-case the situation with only one sample, in which # case we do the comparison only based on `factor` as there's # not enough data to do statistics. - if not statistics.is_different(a_ss[1], b_ss[1], + if not _stats.is_different(a_ss[1], b_ss[1], a_ss[0], b_ss[0]): return False diff --git a/asv/commands/dev.py b/asv/commands/dev.py deleted file mode 100644 index 1a9375120..000000000 --- a/asv/commands/dev.py +++ /dev/null @@ -1,32 +0,0 @@ -# Licensed under a 3-clause BSD style license - see LICENSE.rst - -from .run import Run - - -class Dev(Run): - @classmethod - def setup_arguments(cls, subparsers): - parser = subparsers.add_parser( - "dev", help="Do a test run of a benchmark suite during development", - description=""" - This runs a benchmark suite in a mode that is useful - during development. It is equivalent to - ``asv run --python=same``""") - - cls._setup_arguments(parser, env_default_same=True) - - parser.set_defaults(func=cls.run_from_args) - - return parser - - @classmethod - def run(cls, conf, **kwargs): - raise RuntimeError( - "`asv dev` has been removed. It was a shortcut of `asv run`, which " - "you can use instead. It was removed because it caused confusion, " - "in particular after changing what it was running in asv 0.5.x\n\n" - "You can be interested in the next `asv run` arguments:\n" - " - `--python=same`: to use the current environment and not create one\n" - " - `--quick`: to run benchmarks just once\n" - " - `--dry-run`: to not save the results\n" - ) diff --git a/asv/commands/publish.py b/asv/commands/publish.py index 56ba25c97..976bfc744 100644 --- a/asv/commands/publish.py +++ b/asv/commands/publish.py @@ -5,15 +5,17 @@ import datetime from collections import defaultdict -from . import Command -from ..benchmarks import Benchmarks -from ..console import log -from ..graph import GraphSet -from ..machine import iter_machine_files -from ..repo import get_repo -from ..results import iter_results -from ..publishing import OutputPublisher -from .. import statistics, util, __version__ +from importlib_metadata import version as get_version + +from asv.commands import Command +from asv.benchmarks import Benchmarks +from asv.console import log +from asv.graph import GraphSet +from asv.machine import iter_machine_files +from asv.repo import get_repo +from asv.results import iter_results +from asv.publishing import OutputPublisher +from asv import _stats, util def check_benchmark_params(name, benchmark): @@ -189,7 +191,7 @@ def copy_ignore(src, names): b_params = b['params'] result = results.get_result_value(key, b_params) - weight = [statistics.get_weight(s) + weight = [_stats.get_weight(s) for s in results.get_result_stats(key, b_params)] if not b_params: result = result[0] @@ -281,7 +283,7 @@ def copy_ignore(src, names): }, compact=True) util.write_json(os.path.join(conf.html_dir, "info.json"), { - 'asv-version': __version__, + 'asv-version': get_version("asv"), 'timestamp': util.datetime_to_js_timestamp( datetime.datetime.now(datetime.timezone.utc) ) diff --git a/asv/commands/rm.py b/asv/commands/rm.py index 3bf6a1cda..6eb6cff0a 100644 --- a/asv/commands/rm.py +++ b/asv/commands/rm.py @@ -4,7 +4,9 @@ from asv_runner.console import get_answer_default -from . import Command, util +from asv import util + +from . import Command from ..console import log from ..results import iter_results diff --git a/asv/graph.py b/asv/graph.py index a204cf2eb..190ca2607 100644 --- a/asv/graph.py +++ b/asv/graph.py @@ -16,7 +16,7 @@ class GraphSet: - """Manage multiple `Graph`""" + """Manage multiple :py:class:`Graph` objects""" def __init__(self): self._graphs = {} @@ -326,15 +326,19 @@ def make_summary_graph(graphs): def _compute_summary_data_series(*ys): """ - Given multiple input series:: + Given a multiple input series: - y0, y1, ... + .. code-block:: - calculate summary data series:: + y0, y1, ... - val = [geom_mean([y0[0], y1[0], ...]), - geom_mean([y0[1], y1[1], ...]), - ...] + calculate summary data series: + + .. code-block:: + + val = [geom_mean([y0[0], y1[0], ...]), + geom_mean([y0[1], y1[1], ...]), + ...] Missing data in each y-series is filled for each series separately, before averaging. Data points that are missing from diff --git a/asv/plugin_manager.py b/asv/plugin_manager.py index cf0e592e9..16fd68e26 100644 --- a/asv/plugin_manager.py +++ b/asv/plugin_manager.py @@ -12,8 +12,8 @@ class PluginManager: """ A class to load and manage plugins. - By default in asv, plugins are searched for in the `asv.plugins` - namespace package and in the `asv.commands` package. + By default in asv, plugins are searched for in the :py:mod:`asv.plugins` + namespace package and in the :py:mod:`asv.commands` package. Then, any modules specified in the ``plugins`` entry in the ``asv.conf.json`` file are loaded. diff --git a/asv/plugins/_mamba_helpers.py b/asv/plugins/_mamba_helpers.py index bf8518901..3b15d6bf9 100644 --- a/asv/plugins/_mamba_helpers.py +++ b/asv/plugins/_mamba_helpers.py @@ -218,18 +218,24 @@ def replace_channels(self): def solve(self, specs, pkg_cache_path=None): """Solve given a set of specs. + Parameters ---------- + specs : list of str - A list of package specs. You can use `conda.models.match_spec.MatchSpec` - to get them to the right form by calling - `MatchSpec(mypec).conda_build_form()` + A list of package specs. You can use + ``conda.models.match_spec.MatchSpec`` to get them to the right form + by calling ``MatchSpec(mypec).conda_build_form()`` + Returns ------- + transaction : libmambapy.Transaction The mamba transaction. + Raises ------ + RuntimeError : If the solver did not find a solution. """ diff --git a/asv/plugins/mamba.py b/asv/plugins/mamba.py index 62ad292e7..8e0be1b7b 100644 --- a/asv/plugins/mamba.py +++ b/asv/plugins/mamba.py @@ -12,7 +12,9 @@ except ImportError: from yaml import Loader -from ._mamba_helpers import libmambapy, MambaSolver +import libmambapy + +from ._mamba_helpers import MambaSolver from .. import environment, util from ..console import log diff --git a/asv/schema.py b/asv/schema.py new file mode 100644 index 000000000..a1627ae7b --- /dev/null +++ b/asv/schema.py @@ -0,0 +1,162 @@ +from asv import util +import rtoml +import json + +from pathlib import Path + +from pydantic import ( + BaseModel, + Field, + HttpUrl, + AnyUrl, + ConfigDict, + field_serializer, +) +from typing import Optional, Any, Union +from typing_extensions import Literal + + +class ASVConfig(BaseModel): + model_config = ConfigDict(use_attribute_docstrings=False) + + @field_serializer("project_url", "repo") + def serialize_urls(self, _url: Optional[HttpUrl]): + return str(_url) + + project: str = Field(..., description="The name of the project being benchmarked.") + project_url: Optional[HttpUrl] = Field(None) + """ + The URL to the homepage of the project. + + This can point to anywhere, really, as it's only used for the link at the + top of the benchmark results page back to your project. + """ + + repo: Union[AnyUrl, Path] = Field(...) + """ + The URL to the repository for the project. + + The value can also be a path, relative to the location of the + configuration file. For example, if the benchmarks are stored in the + same repository as the project itself, and the configuration file is + located at ``benchmarks/asv.conf.json`` inside the repository, you can + set ``"repo": ".."`` to use the local repository. + + Currently, only ``git`` and ``hg`` repositories are supported, so this must be + a URL that ``git`` or ``hg`` know how to clone from, for example:: + + - git@github.com:airspeed-velocity/asv.git + - https://github.com/airspeed-velocity/asv.git + - ssh://hg@bitbucket.org/yt_analysis/yt + - hg+https://bitbucket.org/yt_analysis/yt + + The repository may be readonly. + """ + repo_subdir: Optional[str] = Field(None) + """ + The relative path to your Python project inside the repository. This is + where its ``setup.py`` file is located. + + If empty or omitted, the project is assumed to be located at the root of + the repository. + """ + + build_command: Optional[list[str]] = Field( + default=[ + "python setup.py build", + "python -mpip wheel --no-deps --no-index -w {build_cache_dir} {build_dir}", + ], + description="Commands to rebuild the project.", + ) + install_command: Optional[list[str]] = Field( + default=["in-dir={env_dir} python -mpip install {wheel_file}"], + description="Command to install the project.", + ) + uninstall_command: Optional[list[str]] = Field( + default=["return-code=any python -mpip uninstall -y {project}"], + description="Command to uninstall the project.", + ) + + branches: Optional[list[str]] = Field( + None, description="List of branches to benchmark." + ) + dvcs: Optional[str] = Field(None, description="The DVCS being used (e.g., 'git').") + environment_type: Optional[str] = Field( + None, description="The tool to use to create environments (e.g., 'virtualenv')." + ) + install_timeout: Optional[int] = Field( + 600, description="Timeout in seconds for installing dependencies." + ) + show_commit_url: Optional[str] = Field( + None, description="Base URL to show a commit for the project." + ) + pythons: Optional[list[str]] = Field( + None, description="List of Python versions to test against." + ) + conda_channels: Optional[list[str]] = Field( + None, description="List of conda channels for dependency packages." + ) + conda_environment_file: Optional[str] = Field( + None, description="A conda environment file for environment creation." + ) + + matrix: Optional[dict[str, dict[str, Union[list[Optional[str]], None]]]] = Field( + None, + description="Matrix of dependencies and environment variables to test.", + ) + exclude: Optional[list[dict[str, Union[str, dict[str, Optional[str]]]]]] = Field( + None, + description="Combinations of libraries/python versions to exclude from testing.", + ) + include: Optional[list[dict[str, Union[str, dict[str, Optional[str]]]]]] = Field( + None, + description="Combinations of libraries/python versions to include for testing.", + ) + + benchmark_dir: Optional[str] = Field( + None, description="Directory where benchmarks are stored." + ) + env_dir: Optional[str] = Field( + None, description="Directory to cache Python environments." + ) + results_dir: Optional[str] = Field( + None, description="Directory where raw benchmark results are stored." + ) + html_dir: Optional[str] = Field( + None, description="Directory where the HTML tree is written." + ) + hash_length: Optional[int] = Field( + 8, description="Number of characters to retain in commit hashes." + ) + build_cache_size: Optional[int] = Field( + 2, description="Number of builds to cache per environment." + ) + regressions_first_commits: Optional[dict[str, Optional[str]]] = Field( + None, description="Commits after which regression search starts." + ) + regressions_thresholds: Optional[dict[str, float]] = Field( + None, + description="Thresholds for relative change in results to report regressions.", + ) + + +# Example usage +config = ASVConfig( + project="MyProject", + project_url="https://example.com", + repo="https://github.com/example/repo", + matrix={ + "req": {"numpy": ["1.6", "1.7"], "six": ["", None], "pip+emcee": [""]}, + "env": {"ENV_VAR_1": ["val1", "val2"]}, + "env_nobuild": {"ENV_VAR_2": ["val3", None]}, + }, +) + +# Using model_dump with mode='json' to ensure proper serialization +# print(rtoml.dumps(config.model_dump(mode="toml"))) +# print(json.dumps(config.model_dump(mode="toml"), indent=4)) +mkconf = ASVConfig.model_validate_json( + Path("../asv_samples/asv.conf.json").open("rb").read() +) +# exclude_defaults=True to prevents "fat" outputs +print(json.dumps(mkconf.model_dump(mode="toml", exclude_defaults=True), indent=4)) diff --git a/asv/step_detect.py b/asv/step_detect.py index ea6009dc5..37648af3f 100644 --- a/asv/step_detect.py +++ b/asv/step_detect.py @@ -1,362 +1,4 @@ # Licensed under a 3-clause BSD style license - see LICENSE.rst -r"""Regression detection in ASV is based on detecting stepwise changes -in the graphs. The assumptions on the data are as follows: the curves -are piecewise constant plus random noise. We don't know the scaling of -the data or the amplitude of the noise, but assume the relative weight -of the noise amplitude is known for each data point. - -ASV measures the noise amplitude of each data point, based on a number -of samples. We use this information for weighting the different data -points: - -.. math:: - - \sigma_j = \sigma \mathrm{CI}_{99} = \sigma / w_j - -i.e., we assume the uncertainty in each measurement point is -proportional to the estimated confidence interval for each data point. -Their inverses are taken as the relative weights ``w_j``. If ``w_j=0`` -or undefined, we replace it with the median weight, or with ``1`` if -all are undefined. The step detection algorithm determines the -absolute noise amplitude itself based on all available data, which is -more robust than relying on the individual measurements. - -Step detection is a well-studied problem. In this implementation, we -mainly follow a variant of the approach outlined in [Friedrich2008]_ -and elsewhere. This provides a fast algorithm for solving the -piecewise weighted fitting problem - -.. math:: - :label: gamma-opt - - \mathop{\mathrm{argmin}}_{k,\{j\},\{\mu\}} \gamma k + - \sum_{r=1}^k\sum_{i=j_{r-1}}^{j_r} w_i |y_i - \mu_r| - -The differences are: as we do not need exact solutions, we add -additional heuristics to work around the :math:`{\mathcal O}(n^2)` -scaling, which is too harsh for pure-Python code. For details, see -``asv.step_detect.solve_potts_approx``. Moreover, we follow a -slightly different approach on obtaining a suitable number of -intervals, by selecting an optimal value for :math:`\gamma`, based on -a variant of the information criterion problem discussed in -[Yao1988]_. - - -.. [Friedrich2008] F. Friedrich et al., - ''Complexity Penalized M-Estimation: Fast Computation'', - Journal of Computational and Graphical Statistics 17.1, 201-224 (2008). - http://dx.doi.org/10.1198/106186008X285591 - -.. [Yao1988] Y.-C. Yao, - ''Estimating the number of change-points via Schwarz criterion'', - Statistics & Probability Letters 6, 181-189 (1988). - http://dx.doi.org/10.1016/0167-7152(88)90118-6 - - -Bayesian information --------------------- - -To proceed, we need an argument by which to select a suitable -:math:`\gamma` in :eq:`gamma-opt`. Some of the literature on step -detection, e.g. [Yao1988]_, suggests results based on Schwarz information -criteria, - -.. math:: - :label: ic-form - - \text{SC} = \frac{m}{2} \ln \sigma^2 + k \ln m = \text{min!} - -where :math:`\sigma^2` is maximum likelihood variance estimator (if -noise is gaussian). For the implementation, see -``asv.step_detect.solve_potts_autogamma``. - -What follows is a handwaving plausibility argument why such an -objective function makes sense, and how to end up with :math:`l_1` -rather than gaussians. Better approaches are probably to be found in -step detection literature. If you have a better formulation, -contributions/corrections are welcome! - -We assume a Bayesian model: - -.. math:: - :label: prob-model - - P(\{y_i\}_{i=1}^m|\sigma,k,\{\mu_i\}_{i=1}^k,\{j_i\}_{i=1}^{k-1}) - = - N - \sigma^{-m} - \exp( - -\sigma^{-1}\sum_{r=1}^k\sum_{i=j_{r-1}+1}^{j_r} w_i |y_i - \mu_r| - ) - -Here, :math:`y_i` are the :math:`m` data points at hand, :math:`k` is -the number of intervals, :math:`\mu_i` are the values of the function -at the intervals, :math:`j_i` are the interval breakpoints; -:math:`j_0=0`, :math:`j_k=m`, :math:`j_{r-1}0`. The effect in the -:math:`\sigma` integral is cutting off the log-divergence, so that -with sufficient accuracy we can in :eq:`bic-form` replace - -.. math:: - :label: bic-form-2 - - \ln \sigma \mapsto \ln(\sigma_0 + \sigma) - -Here, we fix a measurement accuracy floor with the following guess: -``sigma_0 = 0.1 * w0 * min(abs(diff(mu)))`` and ``sigma_0 = 0.001 * w0 -* abs(mu)`` when there is only a single interval. Here, ``w0`` is the -median weight. - -Autocorrelated noise --------------------- - -Practical experience shows that the noise in the benchmark results can be -correlated. Often benchmarks are run for multiple commits at once, for -example the new commits at a given time, and the benchmark machine -does something else between the runs. Alternatively, the background -load from other processes on the machine varies with time. - -To give a basic model for the noise correlations, we include -AR(1) Laplace noise in :eq:`prob-model`, - -.. math:: - :label: autocorr-model - - P(\{y_i\}_{i=1}^m|\sigma,\rho,k,\{\mu_i\}_{i=1}^k,\{j_i\}_{i=1}^{k-1}) - = - N - \sigma^{-m} - \exp(-\sigma^{-1}\sum_{r=1}^k\sum_{i=j_{r-1}+1}^{j_r} |\epsilon_{i,r} - \rho \epsilon_{i-1,r}|) - -where :math:`\epsilon_{i,r}=y_i-\mu_{r}` with -:math:`\epsilon_{j_{r-1},r}=y_{j_{r-1}}-\mu_{r-1}` and -:math:`\epsilon_{j_0,1}=0` are the deviations from the stepwise -model. The correlation measure :math:`\rho` is unknown, but assumed to -be constant in :math:`(-1,1)`. - -Since the parameter :math:`\rho` is global, it does not change the parameter -counting part of the Schwarz criterion. The maximum likelihood term however -does depend on :math:`\rho`, so that the problem becomes: - -.. math:: - :label: bic-form-autocorr - - \mathop{\mathrm{argmin}}_{k,\rho,\{j\},\{\mu\}} r(m) k + - \ln\sum_{r=1}^k\sum_{i=j_{r-1}}^{j_r} |\epsilon_{i,r} - \rho\epsilon_{i-1,r}| - -To save computation time, we do not solve this optimization problem -exactly. Instead, we again minimize along the :math:`\mu_r^*(\gamma)`, -:math:`j_r^*(\gamma)` curve provided by the solution to -:eq:`gamma-opt`, and use :eq:`bic-form-autocorr` only in selecting the -optimal value of the :math:`\gamma` parameter. - -The minimization vs. :math:`\rho` can be done numerically for given -:math:`\mu_r^*(\gamma)`, :math:`j_r^*(\gamma)`. This minimization step -is computationally cheap compared to the piecewise fit, so including -it will not significantly change the runtime of the total algorithm. - -Postprocessing --------------- - -For the purposes of regression detection, we do not report all steps -the above approach provides. For details, see -``asv.step_detect.detect_regressions``. - -Making use of measured variance -------------------------------- - -``asv`` measures also variance in the timings. This information is -currently used to provide relative data weighting (see above). - -""" - import math import collections @@ -392,7 +34,7 @@ def detect_steps(y, w=None): constant function. Each element contains the left (inclusive) and right (exclusive) bounds of a segment, the average value on the segment, the minimum value in the segment, and the l1 error - estimate, <|Y - avg|>. Missing data points are not necessarily + estimate, :math:`|Y - avg|`. Missing data points are not necessarily contained in any segment; right_pos-1 is the last non-missing data point. @@ -541,11 +183,12 @@ def solve_potts(y, w, gamma, min_size=1, max_size=None, where J(x) is the number of jumps (x_{j+1} != x_j) in x. - The algorithm used is described in Ref. [1]_, it uses dynamic - programming to find an exact solution to the problem (within the - constraints specified). + The algorithm used is described in + :cite:t:`ptts-friedrichComplexityPenalizedMEstimation2008`, it uses dynamic + programming to find an exact solution to the problem (within the constraints + specified). - Computation work is ~ O(n**2 log n). + The computational cost is ~ O(n**2 log n). Parameters ---------- @@ -557,7 +200,7 @@ def solve_potts(y, w, gamma, min_size=1, max_size=None, Minimum interval size to consider max_size : int, optional Maximum interval size to consider - mu_dist : *Dist, optional + mu_dist : Dist, optional Precomputed interval means/medians and cost function values min_pos : int, optional Start point (inclusive) for the interval grid @@ -572,13 +215,15 @@ def solve_potts(y, w, gamma, min_size=1, max_size=None, List of values of the intervals dist : list List of ``sum(|y - x|**p)`` for each interval. - mu_dist : *Dist + mu_dist : Dist Precomputed interval means/medians and cost function values References ---------- - [1] F. Friedrich et al., "Complexity Penalized M-Estimation: Fast Computation", - Journal of Computational and Graphical Statistics 17.1, 201-224 (2008). + .. bibliography:: + :filter: docname in docnames + :labelprefix: PTTS_ + :keyprefix: ptts- """ @@ -852,16 +497,20 @@ def merge_pieces(gamma, right, values, dists, mu_dist, max_size): class L1Dist: """ - Fast computations for:: + Fast computations for the L1 distance measures. + + This computes: + + .. code-block:: mu(l, r) = median(y[l:r+1], weights=w[l:r+1]) dist(l, r) = sum(w*abs(x - mu(l, r)) for x, w in zip(y[l:r+1], weights[l:r+1])) - We do not use here an approach that has asymptotically optimal - performance; at least O(n**2 * log(n)) would be achievable, whereas - we have here O(n**3). The asymptotic performance does not matter - for solve_potts_approx, which only looks at small windows of the - data. It is more important to try to optimize the constant + We do not use here an approach that has asymptotically optimal performance; + at least :math:`O(n^2 * \log(n))` would be achievable, whereas we have here + :math:`O(n^3)`. The asymptotic performance does not matter for + :py:func:`asv.step_detect.solve_potts_approx`, which only looks at small + windows of the data. It is more important to try to optimize the constant prefactors, which for Python means minimal code. """ diff --git a/asv/util.py b/asv/util.py index cf808b6dc..53ca9a29c 100644 --- a/asv/util.py +++ b/asv/util.py @@ -886,16 +886,18 @@ def format_text_table(rows, num_headers=0, top_header_span_start=0, top_header_text=None): """ - Format rows in as a reStructuredText table, in the vein of:: - - ========== ========== ========== - -- top header text, span start 1 - ---------- --------------------- - row0col0 r0c1 r0c2 - ========== ========== ========== - row1col0 r1c1 r1c2 - row2col0 r2c1 r2c2 - ========== ========== ========== + Format rows in as a reStructuredText table, in the vein of: + + .. code-block:: + + ========== ========== ========== + -- top header text, span start 1 + ---------- --------------------- + row0col0 r0c1 r0c2 + ========== ========== ========== + row1col0 r1c1 r1c2 + row2col0 r2c1 r2c2 + ========== ========== ========== """ diff --git a/docs/Makefile b/docs/Makefile deleted file mode 100644 index 24f404332..000000000 --- a/docs/Makefile +++ /dev/null @@ -1,177 +0,0 @@ -# Makefile for Sphinx documentation -# - -# You can set these variables from the command line. -SPHINXOPTS = -SPHINXBUILD = sphinx-build -PAPER = -BUILDDIR = build - -# User-friendly check for sphinx-build -ifeq ($(shell which $(SPHINXBUILD) >/dev/null 2>&1; echo $$?), 1) -$(error The '$(SPHINXBUILD)' command was not found. Make sure you have Sphinx installed, then set the SPHINXBUILD environment variable to point to the full path of the '$(SPHINXBUILD)' executable. Alternatively you can add the directory with the executable to your PATH. If you don't have Sphinx installed, grab it from http://sphinx-doc.org/) -endif - -# Internal variables. -PAPEROPT_a4 = -D latex_paper_size=a4 -PAPEROPT_letter = -D latex_paper_size=letter -ALLSPHINXOPTS = -d $(BUILDDIR)/doctrees $(PAPEROPT_$(PAPER)) $(SPHINXOPTS) source -# the i18n builder cannot share the environment and doctrees with the others -I18NSPHINXOPTS = $(PAPEROPT_$(PAPER)) $(SPHINXOPTS) source - -.PHONY: help clean html dirhtml singlehtml pickle json htmlhelp qthelp devhelp epub latex latexpdf text man changes linkcheck doctest gettext - -help: - @echo "Please use \`make ' where is one of" - @echo " html to make standalone HTML files" - @echo " dirhtml to make HTML files named index.html in directories" - @echo " singlehtml to make a single large HTML file" - @echo " pickle to make pickle files" - @echo " json to make JSON files" - @echo " htmlhelp to make HTML files and a HTML help project" - @echo " qthelp to make HTML files and a qthelp project" - @echo " devhelp to make HTML files and a Devhelp project" - @echo " epub to make an epub" - @echo " latex to make LaTeX files, you can set PAPER=a4 or PAPER=letter" - @echo " latexpdf to make LaTeX files and run them through pdflatex" - @echo " latexpdfja to make LaTeX files and run them through platex/dvipdfmx" - @echo " text to make text files" - @echo " man to make manual pages" - @echo " texinfo to make Texinfo files" - @echo " info to make Texinfo files and run them through makeinfo" - @echo " gettext to make PO message catalogs" - @echo " changes to make an overview of all changed/added/deprecated items" - @echo " xml to make Docutils-native XML files" - @echo " pseudoxml to make pseudoxml-XML files for display purposes" - @echo " linkcheck to check all external links for integrity" - @echo " doctest to run all doctests embedded in the documentation (if enabled)" - -clean: - rm -rf $(BUILDDIR)/* - -html: - $(SPHINXBUILD) -b html $(ALLSPHINXOPTS) $(BUILDDIR)/html - @echo - @echo "Build finished. The HTML pages are in $(BUILDDIR)/html." - -dirhtml: - $(SPHINXBUILD) -b dirhtml $(ALLSPHINXOPTS) $(BUILDDIR)/dirhtml - @echo - @echo "Build finished. The HTML pages are in $(BUILDDIR)/dirhtml." - -singlehtml: - $(SPHINXBUILD) -b singlehtml $(ALLSPHINXOPTS) $(BUILDDIR)/singlehtml - @echo - @echo "Build finished. The HTML page is in $(BUILDDIR)/singlehtml." - -pickle: - $(SPHINXBUILD) -b pickle $(ALLSPHINXOPTS) $(BUILDDIR)/pickle - @echo - @echo "Build finished; now you can process the pickle files." - -json: - $(SPHINXBUILD) -b json $(ALLSPHINXOPTS) $(BUILDDIR)/json - @echo - @echo "Build finished; now you can process the JSON files." - -htmlhelp: - $(SPHINXBUILD) -b htmlhelp $(ALLSPHINXOPTS) $(BUILDDIR)/htmlhelp - @echo - @echo "Build finished; now you can run HTML Help Workshop with the" \ - ".hhp project file in $(BUILDDIR)/htmlhelp." - -qthelp: - $(SPHINXBUILD) -b qthelp $(ALLSPHINXOPTS) $(BUILDDIR)/qthelp - @echo - @echo "Build finished; now you can run "qcollectiongenerator" with the" \ - ".qhcp project file in $(BUILDDIR)/qthelp, like this:" - @echo "# qcollectiongenerator $(BUILDDIR)/qthelp/airspeedvelocity.qhcp" - @echo "To view the help file:" - @echo "# assistant -collectionFile $(BUILDDIR)/qthelp/airspeedvelocity.qhc" - -devhelp: - $(SPHINXBUILD) -b devhelp $(ALLSPHINXOPTS) $(BUILDDIR)/devhelp - @echo - @echo "Build finished." - @echo "To view the help file:" - @echo "# mkdir -p $$HOME/.local/share/devhelp/airspeedvelocity" - @echo "# ln -s $(BUILDDIR)/devhelp $$HOME/.local/share/devhelp/airspeedvelocity" - @echo "# devhelp" - -epub: - $(SPHINXBUILD) -b epub $(ALLSPHINXOPTS) $(BUILDDIR)/epub - @echo - @echo "Build finished. The epub file is in $(BUILDDIR)/epub." - -latex: - $(SPHINXBUILD) -b latex $(ALLSPHINXOPTS) $(BUILDDIR)/latex - @echo - @echo "Build finished; the LaTeX files are in $(BUILDDIR)/latex." - @echo "Run \`make' in that directory to run these through (pdf)latex" \ - "(use \`make latexpdf' here to do that automatically)." - -latexpdf: - $(SPHINXBUILD) -b latex $(ALLSPHINXOPTS) $(BUILDDIR)/latex - @echo "Running LaTeX files through pdflatex..." - $(MAKE) -C $(BUILDDIR)/latex all-pdf - @echo "pdflatex finished; the PDF files are in $(BUILDDIR)/latex." - -latexpdfja: - $(SPHINXBUILD) -b latex $(ALLSPHINXOPTS) $(BUILDDIR)/latex - @echo "Running LaTeX files through platex and dvipdfmx..." - $(MAKE) -C $(BUILDDIR)/latex all-pdf-ja - @echo "pdflatex finished; the PDF files are in $(BUILDDIR)/latex." - -text: - $(SPHINXBUILD) -b text $(ALLSPHINXOPTS) $(BUILDDIR)/text - @echo - @echo "Build finished. The text files are in $(BUILDDIR)/text." - -man: - $(SPHINXBUILD) -b man $(ALLSPHINXOPTS) $(BUILDDIR)/man - @echo - @echo "Build finished. The manual pages are in $(BUILDDIR)/man." - -texinfo: - $(SPHINXBUILD) -b texinfo $(ALLSPHINXOPTS) $(BUILDDIR)/texinfo - @echo - @echo "Build finished. The Texinfo files are in $(BUILDDIR)/texinfo." - @echo "Run \`make' in that directory to run these through makeinfo" \ - "(use \`make info' here to do that automatically)." - -info: - $(SPHINXBUILD) -b texinfo $(ALLSPHINXOPTS) $(BUILDDIR)/texinfo - @echo "Running Texinfo files through makeinfo..." - make -C $(BUILDDIR)/texinfo info - @echo "makeinfo finished; the Info files are in $(BUILDDIR)/texinfo." - -gettext: - $(SPHINXBUILD) -b gettext $(I18NSPHINXOPTS) $(BUILDDIR)/locale - @echo - @echo "Build finished. The message catalogs are in $(BUILDDIR)/locale." - -changes: - $(SPHINXBUILD) -b changes $(ALLSPHINXOPTS) $(BUILDDIR)/changes - @echo - @echo "The overview file is in $(BUILDDIR)/changes." - -linkcheck: - $(SPHINXBUILD) -b linkcheck $(ALLSPHINXOPTS) $(BUILDDIR)/linkcheck - @echo - @echo "Link check complete; look for any errors in the above output " \ - "or in $(BUILDDIR)/linkcheck/output.txt." - -doctest: - $(SPHINXBUILD) -b doctest $(ALLSPHINXOPTS) $(BUILDDIR)/doctest - @echo "Testing of doctests in the sources finished, look at the " \ - "results in $(BUILDDIR)/doctest/output.txt." - -xml: - $(SPHINXBUILD) -b xml $(ALLSPHINXOPTS) $(BUILDDIR)/xml - @echo - @echo "Build finished. The XML files are in $(BUILDDIR)/xml." - -pseudoxml: - $(SPHINXBUILD) -b pseudoxml $(ALLSPHINXOPTS) $(BUILDDIR)/pseudoxml - @echo - @echo "Build finished. The pseudo-XML files are in $(BUILDDIR)/pseudoxml." diff --git a/docs/make.bat b/docs/make.bat deleted file mode 100644 index aaf3d65f6..000000000 --- a/docs/make.bat +++ /dev/null @@ -1,242 +0,0 @@ -@ECHO OFF - -REM Command file for Sphinx documentation - -if "%SPHINXBUILD%" == "" ( - set SPHINXBUILD=sphinx-build -) -set BUILDDIR=build -set ALLSPHINXOPTS=-d %BUILDDIR%/doctrees %SPHINXOPTS% source -set I18NSPHINXOPTS=%SPHINXOPTS% source -if NOT "%PAPER%" == "" ( - set ALLSPHINXOPTS=-D latex_paper_size=%PAPER% %ALLSPHINXOPTS% - set I18NSPHINXOPTS=-D latex_paper_size=%PAPER% %I18NSPHINXOPTS% -) - -if "%1" == "" goto help - -if "%1" == "help" ( - :help - echo.Please use `make ^` where ^ is one of - echo. html to make standalone HTML files - echo. dirhtml to make HTML files named index.html in directories - echo. singlehtml to make a single large HTML file - echo. pickle to make pickle files - echo. json to make JSON files - echo. htmlhelp to make HTML files and a HTML help project - echo. qthelp to make HTML files and a qthelp project - echo. devhelp to make HTML files and a Devhelp project - echo. epub to make an epub - echo. latex to make LaTeX files, you can set PAPER=a4 or PAPER=letter - echo. text to make text files - echo. man to make manual pages - echo. texinfo to make Texinfo files - echo. gettext to make PO message catalogs - echo. changes to make an overview over all changed/added/deprecated items - echo. xml to make Docutils-native XML files - echo. pseudoxml to make pseudoxml-XML files for display purposes - echo. linkcheck to check all external links for integrity - echo. doctest to run all doctests embedded in the documentation if enabled - goto end -) - -if "%1" == "clean" ( - for /d %%i in (%BUILDDIR%\*) do rmdir /q /s %%i - del /q /s %BUILDDIR%\* - goto end -) - - -%SPHINXBUILD% 2> nul -if errorlevel 9009 ( - echo. - echo.The 'sphinx-build' command was not found. Make sure you have Sphinx - echo.installed, then set the SPHINXBUILD environment variable to point - echo.to the full path of the 'sphinx-build' executable. Alternatively you - echo.may add the Sphinx directory to PATH. - echo. - echo.If you don't have Sphinx installed, grab it from - echo.http://sphinx-doc.org/ - exit /b 1 -) - -if "%1" == "html" ( - %SPHINXBUILD% -b html %ALLSPHINXOPTS% %BUILDDIR%/html - if errorlevel 1 exit /b 1 - echo. - echo.Build finished. The HTML pages are in %BUILDDIR%/html. - goto end -) - -if "%1" == "dirhtml" ( - %SPHINXBUILD% -b dirhtml %ALLSPHINXOPTS% %BUILDDIR%/dirhtml - if errorlevel 1 exit /b 1 - echo. - echo.Build finished. The HTML pages are in %BUILDDIR%/dirhtml. - goto end -) - -if "%1" == "singlehtml" ( - %SPHINXBUILD% -b singlehtml %ALLSPHINXOPTS% %BUILDDIR%/singlehtml - if errorlevel 1 exit /b 1 - echo. - echo.Build finished. The HTML pages are in %BUILDDIR%/singlehtml. - goto end -) - -if "%1" == "pickle" ( - %SPHINXBUILD% -b pickle %ALLSPHINXOPTS% %BUILDDIR%/pickle - if errorlevel 1 exit /b 1 - echo. - echo.Build finished; now you can process the pickle files. - goto end -) - -if "%1" == "json" ( - %SPHINXBUILD% -b json %ALLSPHINXOPTS% %BUILDDIR%/json - if errorlevel 1 exit /b 1 - echo. - echo.Build finished; now you can process the JSON files. - goto end -) - -if "%1" == "htmlhelp" ( - %SPHINXBUILD% -b htmlhelp %ALLSPHINXOPTS% %BUILDDIR%/htmlhelp - if errorlevel 1 exit /b 1 - echo. - echo.Build finished; now you can run HTML Help Workshop with the ^ -.hhp project file in %BUILDDIR%/htmlhelp. - goto end -) - -if "%1" == "qthelp" ( - %SPHINXBUILD% -b qthelp %ALLSPHINXOPTS% %BUILDDIR%/qthelp - if errorlevel 1 exit /b 1 - echo. - echo.Build finished; now you can run "qcollectiongenerator" with the ^ -.qhcp project file in %BUILDDIR%/qthelp, like this: - echo.^> qcollectiongenerator %BUILDDIR%\qthelp\airspeedvelocity.qhcp - echo.To view the help file: - echo.^> assistant -collectionFile %BUILDDIR%\qthelp\airspeedvelocity.ghc - goto end -) - -if "%1" == "devhelp" ( - %SPHINXBUILD% -b devhelp %ALLSPHINXOPTS% %BUILDDIR%/devhelp - if errorlevel 1 exit /b 1 - echo. - echo.Build finished. - goto end -) - -if "%1" == "epub" ( - %SPHINXBUILD% -b epub %ALLSPHINXOPTS% %BUILDDIR%/epub - if errorlevel 1 exit /b 1 - echo. - echo.Build finished. The epub file is in %BUILDDIR%/epub. - goto end -) - -if "%1" == "latex" ( - %SPHINXBUILD% -b latex %ALLSPHINXOPTS% %BUILDDIR%/latex - if errorlevel 1 exit /b 1 - echo. - echo.Build finished; the LaTeX files are in %BUILDDIR%/latex. - goto end -) - -if "%1" == "latexpdf" ( - %SPHINXBUILD% -b latex %ALLSPHINXOPTS% %BUILDDIR%/latex - cd %BUILDDIR%/latex - make all-pdf - cd %BUILDDIR%/.. - echo. - echo.Build finished; the PDF files are in %BUILDDIR%/latex. - goto end -) - -if "%1" == "latexpdfja" ( - %SPHINXBUILD% -b latex %ALLSPHINXOPTS% %BUILDDIR%/latex - cd %BUILDDIR%/latex - make all-pdf-ja - cd %BUILDDIR%/.. - echo. - echo.Build finished; the PDF files are in %BUILDDIR%/latex. - goto end -) - -if "%1" == "text" ( - %SPHINXBUILD% -b text %ALLSPHINXOPTS% %BUILDDIR%/text - if errorlevel 1 exit /b 1 - echo. - echo.Build finished. The text files are in %BUILDDIR%/text. - goto end -) - -if "%1" == "man" ( - %SPHINXBUILD% -b man %ALLSPHINXOPTS% %BUILDDIR%/man - if errorlevel 1 exit /b 1 - echo. - echo.Build finished. The manual pages are in %BUILDDIR%/man. - goto end -) - -if "%1" == "texinfo" ( - %SPHINXBUILD% -b texinfo %ALLSPHINXOPTS% %BUILDDIR%/texinfo - if errorlevel 1 exit /b 1 - echo. - echo.Build finished. The Texinfo files are in %BUILDDIR%/texinfo. - goto end -) - -if "%1" == "gettext" ( - %SPHINXBUILD% -b gettext %I18NSPHINXOPTS% %BUILDDIR%/locale - if errorlevel 1 exit /b 1 - echo. - echo.Build finished. The message catalogs are in %BUILDDIR%/locale. - goto end -) - -if "%1" == "changes" ( - %SPHINXBUILD% -b changes %ALLSPHINXOPTS% %BUILDDIR%/changes - if errorlevel 1 exit /b 1 - echo. - echo.The overview file is in %BUILDDIR%/changes. - goto end -) - -if "%1" == "linkcheck" ( - %SPHINXBUILD% -b linkcheck %ALLSPHINXOPTS% %BUILDDIR%/linkcheck - if errorlevel 1 exit /b 1 - echo. - echo.Link check complete; look for any errors in the above output ^ -or in %BUILDDIR%/linkcheck/output.txt. - goto end -) - -if "%1" == "doctest" ( - %SPHINXBUILD% -b doctest %ALLSPHINXOPTS% %BUILDDIR%/doctest - if errorlevel 1 exit /b 1 - echo. - echo.Testing of doctests in the sources finished, look at the ^ -results in %BUILDDIR%/doctest/output.txt. - goto end -) - -if "%1" == "xml" ( - %SPHINXBUILD% -b xml %ALLSPHINXOPTS% %BUILDDIR%/xml - if errorlevel 1 exit /b 1 - echo. - echo.Build finished. The XML files are in %BUILDDIR%/xml. - goto end -) - -if "%1" == "pseudoxml" ( - %SPHINXBUILD% -b pseudoxml %ALLSPHINXOPTS% %BUILDDIR%/pseudoxml - if errorlevel 1 exit /b 1 - echo. - echo.Build finished. The pseudo-XML files are in %BUILDDIR%/pseudoxml. - goto end -) - -:end diff --git a/docs/source/_static/dark_logo.png b/docs/source/_static/dark_logo.png new file mode 100644 index 000000000..ec18110bd Binary files /dev/null and b/docs/source/_static/dark_logo.png differ diff --git a/docs/source/_static/gh_fork.css b/docs/source/_static/gh_fork.css deleted file mode 100644 index 1a4004ad2..000000000 --- a/docs/source/_static/gh_fork.css +++ /dev/null @@ -1,56 +0,0 @@ -/* from: https://codepo8.github.io/css-fork-on-github-ribbon/ */ -#forkongithub a{ - background:#000; - color:#fff; - text-decoration:none; - font-family:arial,sans-serif; - text-align:center; - font-weight:bold; - padding:5px 40px; - font-size:1rem; - line-height:2rem; - position:relative; - transition:0.5s; -} -#forkongithub a:hover{ - background:#c11; - color:#fff; -} -#forkongithub a::before,#forkongithub a::after{ - content:""; - width:100%; - display:block; - position:absolute; - top:1px; - left:0; - height:1px; - background:#fff; -} -#forkongithub a::after{ - bottom:1px; - top:auto; -} -@media screen and (min-width:800px){ - #forkongithub{ - position:fixed; - display:block; - top:0; - right:0; - width:200px; - overflow:hidden; - height:200px; - z-index:9999; - } - #forkongithub a{ - width:200px; - position:absolute; - top:60px; - right:-60px; - transform:rotate(45deg); - -webkit-transform:rotate(45deg); - -ms-transform:rotate(45deg); - -moz-transform:rotate(45deg); - -o-transform:rotate(45deg); - box-shadow:4px 4px 10px rgba(0,0,0,0.8); - } -} diff --git a/docs/source/_static/light_logo.png b/docs/source/_static/light_logo.png new file mode 100644 index 000000000..1a216c648 Binary files /dev/null and b/docs/source/_static/light_logo.png differ diff --git a/docs/source/_templates/layout.html b/docs/source/_templates/layout.html index dc73f7624..40074d50f 100644 --- a/docs/source/_templates/layout.html +++ b/docs/source/_templates/layout.html @@ -2,7 +2,6 @@ {% block header %} {{ super() }} -Fork me on GitHub {% endblock %} {# Custom CSS overrides #} diff --git a/docs/source/asv.bib b/docs/source/asv.bib new file mode 100644 index 000000000..32bcf535a --- /dev/null +++ b/docs/source/asv.bib @@ -0,0 +1,54 @@ +@article{friedrichComplexityPenalizedMEstimation2008, + title = {Complexity {{Penalized M-Estimation}}: {{Fast Computation}}}, + author = {Friedrich, F. and Kempe, A. and Liebscher, V. and Winkler, G.}, + year = {2008}, + journal = {Journal of Computational and Graphical Statistics}, + volume = {17}, + number = {1}, + eprint = {27594299}, + eprinttype = {jstor}, + pages = {201--224}, + doi = {10.1198/106186008X285591}, + langid = {english} +} + +@book{gibbonsNonparametricStatisticalInference2010, + title = {Nonparametric {{Statistical Inference}}}, + author = {Gibbons, Jean Dickinson and Chakraborti, Subhabrata}, + year = {2010}, + month = jul, + edition = {5}, + publisher = {{Chapman and Hall/CRC}}, + address = {New York}, + doi = {10.1201/9781439896129}, + isbn = {978-0-429-11188-4} +} + +@article{mannTestWhetherOne1947, + title = {On a {{Test}} of {{Whether}} One of {{Two Random Variables}} Is {{Stochastically Larger}} than the {{Other}}}, + author = {Mann, H. B. and Whitney, D. R.}, + year = {1947}, + journal = {The Annals of Mathematical Statistics}, + volume = {18}, + number = {1}, + eprint = {2236101}, + eprinttype = {jstor}, + pages = {50--60}, + doi = {10.1214/aoms/1177730491}, + langid = {english} +} + +@article{yaoEstimatingNumberChangepoints1988, + title = {Estimating the Number of Change-Points via {{Schwarz}}' Criterion}, + author = {Yao, Yi-Ching}, + year = {1988}, + month = feb, + journal = {Statistics \& Probability Letters}, + volume = {6}, + number = {3}, + pages = {181--189}, + issn = {01677152}, + doi = {10.1016/0167-7152(88)90118-6}, + urldate = {2022-12-07}, + langid = {english} +} diff --git a/docs/source/asv.conf.json.rst b/docs/source/asv.conf.json.rst index f996720b6..3c8263502 100644 --- a/docs/source/asv.conf.json.rst +++ b/docs/source/asv.conf.json.rst @@ -1,5 +1,9 @@ .. _conf-reference: + +.. autopydantic_model:: asv.schema.ASVConfig + + ``asv.conf.json`` reference =========================== @@ -22,8 +26,6 @@ this file and their expected values. .. only:: not man - .. contents:: - ``project`` ----------- The name of the project being benchmarked. @@ -289,12 +291,12 @@ the project being benchmarked may specify in its ``setup.py`` file. preface the package name with ``pip+``. For example, ``emcee`` is only available from ``pip``, so the package name to be used is ``pip+emcee``. - .. versionadded::0.6.0 + .. versionadded:: 0.6.0 ``pip`` dependencies can now accept local (fully qualified) directories, and also take flags (e.g. ``-e``) - .. versionadded::0.6.1 + .. versionadded:: 0.6.1 ``asv`` can now optionally load dependencies from ``environment.yml`` if ``conda`` or ``mamba`` is set as the ``environment_type``. As ``asv`` @@ -302,7 +304,7 @@ the project being benchmarked may specify in its ``setup.py`` file. These specifications in ``environment.yml`` or another (user-defined) file will be overridden by the environment matrix. - .. versionadded::0.6.2 + .. versionadded:: 0.6.2 The ``mamba`` plugin will now take channels and channel priority from the ``MAMBARC`` environment variable if it is provided. e.g. diff --git a/docs/source/benchmarks.rst b/docs/source/benchmarks.rst index f2d7bed05..9997eeb9e 100644 --- a/docs/source/benchmarks.rst +++ b/docs/source/benchmarks.rst @@ -3,8 +3,6 @@ Benchmark types and attributes .. only:: not man - .. contents:: - .. warning:: .. versionchanged:: 0.6.0 diff --git a/docs/source/commands.rst b/docs/source/commands.rst index 48557f5e4..f9b307ecc 100644 --- a/docs/source/commands.rst +++ b/docs/source/commands.rst @@ -1,6 +1,5 @@ Commands ======== -.. contents:: - .. automodule:: asv.commands + :no-index: diff --git a/docs/source/conf.py b/docs/source/conf.py index 6d55f4459..38459d55b 100644 --- a/docs/source/conf.py +++ b/docs/source/conf.py @@ -1,29 +1,4 @@ -# -# airspeed velocity documentation build configuration file, created by -# sphinx-quickstart on Mon Nov 18 09:12:08 2013. -# -# This file is execfile()d with the current directory set to its -# containing dir. -# -# Note that not all possible configuration values are present in this -# autogenerated file. -# -# All configuration values have a default; values that are commented out -# serve to show the default. - -import asv - -try: - import sphinx_bootstrap_theme -except ImportError: - raise ImportError( - "sphinx_bootstrap_theme must be installed to build the docs." - " Try `pip install sphinx_bootstrap_theme`.") - -# If extensions (or modules to document with autodoc) are in another directory, -# add these directories to sys.path here. If the directory is relative to the -# documentation root, use os.path.abspath to make it absolute, like shown here. -# sys.path.insert(0, os.path.abspath('.')) +from importlib_metadata import version as get_version # -- General configuration ------------------------------------------------ @@ -31,251 +6,79 @@ # needs_sphinx = '1.0' intersphinx_mapping = { - 'python': (' https://docs.python.org/3/', None), - 'asv_runner': ('https://airspeed-velocity.github.io/asv_runner/', None) + "python": (" https://docs.python.org/3/", None), + "asv_runner": ("https://airspeed-velocity.github.io/asv_runner/", None), } -# Add any Sphinx extension module names here, as strings. They can be -# extensions coming with Sphinx (named 'sphinx.ext.*') or your custom -# ones. extensions = [ - 'sphinx.ext.autodoc', - 'sphinx.ext.intersphinx', - 'sphinx.ext.todo', - 'sphinx.ext.mathjax' + "sphinx.ext.viewcode", + "sphinx.ext.intersphinx", + "sphinx.ext.todo", + "sphinxcontrib.katex", + "sphinxcontrib.bibtex", + "sphinx_collapse", + "autoapi.extension", + "sphinxcontrib.autodoc_pydantic", +] + +autoapi_dirs = ["../../asv"] +autoapi_add_toc_entry = True +autoapi_keep_files = True +autoapi_ignore = ["*_version*", "*migrations*", "*schema*"] +autoapi_options = [ + "members", + "undoc-members", + "private-members", + # "show-inheritance", + "show-module-summary", + "special-members", + "imported-members", ] +bibtex_bibfiles = ["asv.bib"] +bibtex_default_style = "alpha" + # Add any paths that contain templates here, relative to this directory. -templates_path = ['_templates'] +templates_path = ["_templates"] # The suffix of source filenames. -source_suffix = '.rst' +source_suffix = ".rst" # The encoding of source files. -# source_encoding = 'utf-8-sig' +source_encoding = "utf-8-sig" # The root toctree document. -root_doc = 'index' +root_doc = "index" # General information about the project. -project = u'airspeed velocity' -copyright = u'2013--present, Michael Droettboom, Pauli Virtanen, asv Developers' +project = "airspeed velocity" +copyright = "2013--present, Michael Droettboom, Pauli Virtanen, asv Developers" # The version info for the project you're documenting, acts as replacement for # |version| and |release|, also used in various other places throughout the # built documents. # -# The short X.Y version. -version = asv.__version__ # The full version, including alpha/beta/rc tags. -release = asv.__version__ - -# The language for content autogenerated by Sphinx. Refer to documentation -# for a list of supported languages. -# language = None - -# There are two options for replacing |today|: either, you set today to some -# non-false value, then it is used: -# today = '' -# Else, today_fmt is used as the format for a strftime call. -# today_fmt = '%B %d, %Y' - -# List of patterns, relative to source directory, that match files and -# directories to ignore when looking for source files. -exclude_patterns = [] - -# The reST default role (used for this markup: `text`) to use for all -# documents. -default_role = 'obj' +release: str = get_version("asv") +# The short X.Y.Z version. +version: str = ".".join(release.split(".")[:3]) # Warn about all references where the target cannot be found. nitpicky = True -# If true, '()' will be appended to :func: etc. cross-reference text. -# add_function_parentheses = True - -# If true, the current module name will be prepended to all description -# unit titles (such as .. function::). -# add_module_names = True - -# If true, sectionauthor and moduleauthor directives will be shown in the -# output. They are ignored by default. -# show_authors = False - # The name of the Pygments (syntax highlighting) style to use. -pygments_style = 'sphinx' - -# A list of ignored prefixes for module index sorting. -# modindex_common_prefix = [] - -# If true, keep warnings as "system message" paragraphs in the built documents. -# keep_warnings = False - +pygments_style = "lightbulb" +pygments_dark_style = "one-dark" # -- Options for HTML output ---------------------------------------------- -# The theme to use for HTML and HTML Help pages. See the documentation for -# a list of builtin themes. -html_theme = 'bootstrap' - -# Theme options are theme-specific and customize the look and feel of a theme -# further. For a list of options available for each theme, see the -# documentation. +html_theme = "furo" +html_favicon = "_static/swallow.ico" +html_static_path = ["_static"] html_theme_options = { - # This is a workaround for a bug in `sphinx_bootstrap_theme` for - # Python 3.x - 'bootswatch_theme': None + "source_repository": "https://github.com/airspeed-velocity/asv/", + "source_branch": "main", + "source_directory": "docs/source/", + "light_logo": "dark_logo.png", + "dark_logo": "light_logo.png", } - -# Add any paths that contain custom themes here, relative to this directory. -html_theme_path = sphinx_bootstrap_theme.get_html_theme_path() - -# The name for this set of Sphinx documents. If None, it defaults to -# " v documentation". -# html_title = None - -# A shorter title for the navigation bar. Default is the same as html_title. -# html_short_title = None - -# The name of an image file (relative to this directory) to place at the top -# of the sidebar. -# html_logo = None - -# The name of an image file (within the static path) to use as favicon of the -# docs. This file should be a Windows icon file (.ico) being 16x16 or 32x32 -# pixels large. -html_favicon = '_static/swallow.ico' - -# Add any paths that contain custom static files (such as style sheets) here, -# relative to this directory. They are copied after the builtin static files, -# so a file named "default.css" will overwrite the builtin "default.css". -html_static_path = ['_static'] - -# Add any extra paths that contain custom files (such as robots.txt or -# .htaccess) here, relative to this directory. These files are copied -# directly to the root of the documentation. -# html_extra_path = [] - -# If not '', a 'Last updated on:' timestamp is inserted at every page bottom, -# using the given strftime format. -# html_last_updated_fmt = '%b %d, %Y' - -# If true, SmartyPants will be used to convert quotes and dashes to -# typographically correct entities. -# html_use_smartypants = True - -# Custom sidebar templates, maps document names to template names. -html_sidebars = { - '**': [] -} - -# Additional templates that should be rendered to pages, maps page names to -# template names. -# html_additional_pages = {} - -# If false, no module index is generated. -# html_domain_indices = True - -# If false, no index is generated. -# html_use_index = True - -# If true, the index is split into individual pages for each letter. -# html_split_index = False - -# If true, links to the reST sources are added to the pages. -html_show_sourcelink = False - -# If true, "Created using Sphinx" is shown in the HTML footer. Default is True. -# html_show_sphinx = True - -# If true, "(C) Copyright ..." is shown in the HTML footer. Default is True. -# html_show_copyright = True - -# If true, an OpenSearch description file will be output, and all pages will -# contain a tag referring to it. The value of this option must be the -# base URL from which the finished HTML is served. -# html_use_opensearch = '' - -# This is the file name suffix for HTML files (e.g. ".xhtml"). -# html_file_suffix = None - -# Output file base name for HTML help builder. -htmlhelp_basename = 'airspeedvelocitydoc' - - -# -- Options for LaTeX output --------------------------------------------- - -latex_elements = { - # The paper size ('letterpaper' or 'a4paper'). - # 'papersize': 'letterpaper', - - # The font size ('10pt', '11pt' or '12pt'). - # 'pointsize': '10pt', - - # Additional stuff for the LaTeX preamble. - # 'preamble': '', -} - -# Grouping the document tree into LaTeX files. List of tuples -# (source start file, target name, title, -# author, documentclass [howto, manual, or own class]). -latex_documents = [ - ('index', 'airspeedvelocity.tex', 'airspeed velocity Documentation', - 'Michael Droettboom', 'manual'), -] - -# The name of an image file (relative to this directory) to place at the top of -# the title page. -# latex_logo = None - -# For "manual" documents, if this is true, then toplevel headings are parts, -# not chapters. -# latex_use_parts = False - -# If true, show page references after internal links. -# latex_show_pagerefs = False - -# If true, show URL addresses after external links. -# latex_show_urls = False - -# Documents to append as an appendix to all manuals. -# latex_appendices = [] - -# If false, no module index is generated. -# latex_domain_indices = True - - -# -- Options for manual page output --------------------------------------- - -# One entry per manual page. List of tuples -# (source start file, name, description, authors, manual section). -man_pages = [ - ('manindex', 'asv', u'Airspeed Velocity', [u'Michael Droettboom', u'Pauli Virtanen'], '1'), -] - -# If true, show URL addresses after external links. -# man_show_urls = False - - -# -- Options for Texinfo output ------------------------------------------- - -# Grouping the document tree into Texinfo files. List of tuples -# (source start file, target name, title, author, -# dir menu entry, description, category) -texinfo_documents = [ - ('index', 'airspeedvelocity', 'airspeed velocity Documentation', - 'Michael Droettboom', 'airspeedvelocity', 'Benchmarking suite for python code.', - 'Miscellaneous'), -] - -# Documents to append as an appendix to all manuals. -# texinfo_appendices = [] - -# If false, no module index is generated. -# texinfo_domain_indices = True - -# How to display URL addresses: 'footnote', 'no', or 'inline'. -# texinfo_show_urls = 'footnote' - -# If true, do not generate a @detailmenu in the "Top" node's menu. -# texinfo_no_detailmenu = False diff --git a/docs/source/credits.rst b/docs/source/credits.rst deleted file mode 100644 index 00e94d5b9..000000000 --- a/docs/source/credits.rst +++ /dev/null @@ -1,88 +0,0 @@ -Credits -------- - -.. rst-class:: credits-list - -- Michael Droettboom (founder) -- Pauli Virtanen - -The rest of the contributors are listed in alphabetical order. - -- Aaron Meurer -- @afragner -- Akihiro Nitta -- Andrew Nelson -- Andrew Thomas -- Antoine Pitrou -- Antony Lee -- Ariel Silvio Norberto RAMOS -- Arne Neumann -- Boris Feld -- Chiara Marmo -- Chris Beaumont -- Christoph Deil -- Christopher Whelan -- Colin Carroll -- Daniel Andres Pinto -- David Stansby -- Dieter Werthmüller -- Dorothy Kabarozi -- @DWesl -- Edison Gustavo Muenz -- Elliott Sales de Andrade -- Eric Dill -- Erik M. Bray -- Erik Tollerud -- Erwan Pannier -- Fangchen Li -- Hans Moritz Günther -- Isuru Fernando -- Jarrod Millman -- @jbrockmendel -- jeremie du boisberranger -- John Kirkham -- Josh Soref -- Juan Nunez-Iglesias -- Julian Rüth -- Kacper Kowalik -- Kacper Kowalik (Xarthisius) -- Kevin Anderson -- @Leenkiz -- Lucas Colley -- Lucy Jiménez -- Marc Garcia -- @mariamadronah -- Mark Harfouche -- Markus Mohrhard -- Matthew Treinish -- Matthew Turk -- Matti Picus -- Mike Sarahan -- Min RK -- Nathan Goldbaum -- Nick Crews -- Nicole Franco León -- @pawel -- Paweł Redzyński -- Philippe Pepiot -- Pierre Glaser -- P. L. Lim -- Raphaël Gomès -- Richard Hattersley -- Rohit Goswami -- Rok Mihevc -- Sayed Adel -- serge-sans-paille -- Sofía Miñano -- Sourcery AI -- Thomas Pfaff -- Thomas Robitaille -- Tim Felgentreff -- Tom Augspurger -- Tushabe Catherine -- Tyler Reddy -- Valentin Haenel -- @Warbo -- Wojtek Ruszczewski -- Yaroslav Halchenko -- Zach Burnett diff --git a/docs/source/dev.rst b/docs/source/dev.rst index b325d25c6..e258901d1 100644 --- a/docs/source/dev.rst +++ b/docs/source/dev.rst @@ -12,8 +12,6 @@ developers and other people interested in internals of ``asv``. environments, loading plugins, and collecting the results of the benchmarks run with ``asv_runner``. -.. contents:: - Development setup ----------------- @@ -310,12 +308,6 @@ To use them, at least one of the following needs to be installed: For other options regarding the webdriver to use, see ``py.test --help``. -Step detection --------------- - -.. automodule:: asv.step_detect - - Release management ------------------ diff --git a/docs/source/env_vars.rst b/docs/source/env_vars.rst index 5b9956834..1c9adda97 100644 --- a/docs/source/env_vars.rst +++ b/docs/source/env_vars.rst @@ -27,7 +27,7 @@ behavior are also set: .. note:: - .. versionadded::0.6.0 + .. versionadded:: 0.6.0 ``ASV_RUNNER_PATH`` may be set to provide a local installation of ``asv_runner``, mostly used for the CI to ensure changes to ``asv_runner`` diff --git a/docs/source/index.rst b/docs/source/index.rst index 23123c930..9116bbcaf 100644 --- a/docs/source/index.rst +++ b/docs/source/index.rst @@ -1,22 +1,23 @@ -.. airspeed velocity documentation root file, created by - sphinx-quickstart on Mon Nov 18 09:12:08 2013. - You can adapt this file completely to your liking, but it should at least - contain the root `toctree` directive. - airspeed velocity ================= +Overview +-------- + **airspeed velocity** (``asv``) is a tool for benchmarking Python packages over their lifetime. Runtime, memory consumption and even custom-computed values may be tracked. The results are displayed in an interactive web frontend that requires only a basic static webserver to host. -See examples of Airspeed Velocity websites: +Deployed examples of Airspeed Velocity websites: `astropy `__, `numpy `__, `scipy `__. +User examples may be found at the `asv_sample +`__ repository. + License: `BSD three-clause license `__. @@ -31,7 +32,99 @@ Development: https://github.com/airspeed-velocity/asv using.rst writing_benchmarks.rst tuning.rst - reference.rst + user_reference.rst dev.rst + step_detection.rst changelog.rst - credits.rst + autoapi/index.rst + +Credits +------- + +.. collapse:: Original creators + + - Michael Droettboom (founder) + - Pauli Virtanen + +Other contributors are listed in alphabetical order. + +.. collapse:: Additional contributors + + - Aaron Meurer + - @afragner + - Akihiro Nitta + - Andrew Nelson + - Andrew Thomas + - Antoine Pitrou + - Antony Lee + - Ariel Silvio Norberto RAMOS + - Arne Neumann + - Boris Feld + - Chiara Marmo + - Chris Beaumont + - Christoph Deil + - Christopher Whelan + - Colin Carroll + - Daniel Andres Pinto + - David Stansby + - Dieter Werthmüller + - Dorothy Kabarozi + - @DWesl + - Edison Gustavo Muenz + - Elliott Sales de Andrade + - Eric Dill + - Erik M. Bray + - Erik Tollerud + - Erwan Pannier + - Fangchen Li + - Hans Moritz Günther + - Isuru Fernando + - Jarrod Millman + - @jbrockmendel + - jeremie du boisberranger + - John Kirkham + - Josh Soref + - Juan Nunez-Iglesias + - Julian Rüth + - Kacper Kowalik + - Kacper Kowalik (Xarthisius) + - Kevin Anderson + - @Leenkiz + - Lucas Colley + - Lucy Jiménez + - Marc Garcia + - @mariamadronah + - Mark Harfouche + - Markus Mohrhard + - Matthew Treinish + - Matthew Turk + - Matti Picus + - Mike Sarahan + - Min RK + - Nathan Goldbaum + - Nick Crews + - Nicole Franco León + - @pawel + - Paweł Redzyński + - Philippe Pepiot + - Pierre Glaser + - P. L. Lim + - Raphaël Gomès + - Richard Hattersley + - Rohit Goswami + - Rok Mihevc + - Sayed Adel + - serge-sans-paille + - Sofía Miñano + - Sourcery AI + - Thomas Pfaff + - Thomas Robitaille + - Tim Felgentreff + - Tom Augspurger + - Tushabe Catherine + - Tyler Reddy + - Valentin Haenel + - @Warbo + - Wojtek Ruszczewski + - Yaroslav Halchenko + - Zach Burnett diff --git a/docs/source/installing.rst b/docs/source/installing.rst index 5a3edb4be..1bfbf3530 100644 --- a/docs/source/installing.rst +++ b/docs/source/installing.rst @@ -1,23 +1,30 @@ Installing airspeed velocity ============================ -**airspeed velocity** is known to work on Linux, Mac OS-X, and Windows. -It is known to work with Python 3.7 and higher. -It works also with PyPy. +**airspeed velocity** is known to work on Linux, MacOS, and Windows, for Python +3.7 and higher. PyPy 3.8 is also supported. -**airspeed velocity** is a standard Python package, and the latest -released version may be `installed in the standard -way from PyPI `__:: +**airspeed velocity** is a standard Python package, and the latest released +version may be `installed from PyPI +`__: + +.. code-block:: sh pip install asv -The development version can be installed by cloning the source -repository and running ``pip install .`` inside it, or by ``pip -install git+https://github.com/airspeed-velocity/asv``. +The development version can be installed from GitHub: + +.. code-block:: sh + + git clone git@github.com:airspeed-velocity/asv + cd asv + pip install . + # Or in one shot + pip install git+https://github.com/airspeed-velocity/asv -The requirements should be automatically installed. If they aren't -installed automatically, for example due to networking restrictions, -the ``python`` requirements are as noted in the ``pyproject.toml``. +The basic requirements should be automatically installed. If they aren't +installed automatically, for example due to networking restrictions, the +``python`` requirements are as noted in the ``pyproject.toml``. For managing the environments, one of the following packages is required: @@ -43,25 +50,23 @@ For managing the environments, one of the following packages is required: without precompiled wheels usually have to be compiled every time the environments are set up. -Optional optimization ---------------------- +Optional optimizations +---------------------- + +If your project being benchmarked contains C, C++, Objective-C or Cython, +consider installing ``ccache``. `ccache `__ is a +compiler cache that speeds up compilation time when the same objects are +repeatedly compiled. -If your project being benchmarked contains C, C++, Objective-C or -Cython, consider installing ``ccache``. `ccache -`__ is a compiler cache that speeds up -compilation time when the same objects are repeatedly compiled. In -**airspeed velocity**, the project being benchmarked is recompiled at -many different points in its history, often with only minor changes to -the source code, so ``ccache`` can help speed up the total benchmarking -time considerably. +In **airspeed velocity**, the project being benchmarked is recompiled at many +different points in its history, often with only minor changes to the source +code, so ``ccache`` can help speed up the total benchmarking time considerably. Running the self-tests ---------------------- -The self tests are based on `pytest `__. If you -don't have it installed, and you have a connection to the Internet, it -will be installed automatically. +The testsuite is based on `pytest `__. -To run **airspeed velocity**'s self tests:: +To run **airspeed velocity**'s testsuite:: pytest diff --git a/docs/source/step_detection.rst b/docs/source/step_detection.rst new file mode 100644 index 000000000..4503356a8 --- /dev/null +++ b/docs/source/step_detection.rst @@ -0,0 +1,355 @@ +Step Detection +============== + +Regression detection in ASV is based on detecting stepwise changes +in the graphs. The assumptions on the data are as follows: the curves +are piecewise constant plus random noise. We don't know the scaling of +the data or the amplitude of the noise, but assume the relative weight +of the noise amplitude is known for each data point. + +ASV measures the noise amplitude of each data point, based on a number +of samples. We use this information for weighting the different data +points: + +.. math:: + + \sigma_j = \sigma \mathrm{CI}_{99} = \sigma / w_j + +i.e., we assume the uncertainty in each measurement point is +proportional to the estimated confidence interval for each data point. +Their inverses are taken as the relative weights ``w_j``. If ``w_j=0`` +or undefined, we replace it with the median weight, or with ``1`` if +all are undefined. The step detection algorithm determines the +absolute noise amplitude itself based on all available data, which is +more robust than relying on the individual measurements. + +Step detection is a well-studied problem. In this implementation, we mainly +follow a variant of the approach outlined in +:cite:p:`sdm-friedrichComplexityPenalizedMEstimation2008` and elsewhere. This +provides a fast algorithm for solving the piecewise weighted fitting problem + +.. math:: + :label: gamma-opt + + \mathop{\mathrm{argmin}}_{k,\{j\},\{\mu\}} \gamma k + + \sum_{r=1}^k\sum_{i=j_{r-1}}^{j_r} w_i |y_i - \mu_r| + +The differences are: as we do not need exact solutions, we add additional +heuristics to work around the :math:`{\mathcal O}(n^2)` scaling, which is too +harsh for pure-Python code. For details, see +:py:func:`asv.step_detect.solve_potts_approx`. Moreover, we follow a slightly +different approach on obtaining a suitable number of intervals, by selecting an +optimal value for :math:`\gamma`, based on a variant of the information +criterion problem discussed in +:cite:p:`sdm-yaoEstimatingNumberChangepoints1988`. + + +Bayesian information +-------------------- + +To proceed, we need an argument by which to select a suitable :math:`\gamma` in +:eq:`gamma-opt`. Some of the literature on step detection, e.g. +:cite:p:`sdm-yaoEstimatingNumberChangepoints1988`, suggests results based on +Schwarz information criteria, + +.. math:: + :label: ic-form + + \text{SC} = \frac{m}{2} \ln \sigma^2 + k \ln m = \text{min!} + +where :math:`\sigma^2` is maximum likelihood variance estimator (if +noise is gaussian). For the implementation, see +:py:func:`asv.step_detect.solve_potts_autogamma`. + +What follows is a handwaving plausibility argument why such an +objective function makes sense, and how to end up with :math:`l_1` +rather than gaussians. Better approaches are probably to be found in +step detection literature. If you have a better formulation, +contributions/corrections are welcome! + +We assume a Bayesian model: + +.. math:: + :label: prob-model + + P(\{y_i\}_{i=1}^m|\sigma,k,\{\mu_i\}_{i=1}^k,\{j_i\}_{i=1}^{k-1}) + = + N + \sigma^{-m} + \exp( + -\sigma^{-1}\sum_{r=1}^k\sum_{i=j_{r-1}+1}^{j_r} w_i |y_i - \mu_r| + ) + +Here, :math:`y_i` are the :math:`m` data points at hand, :math:`k` is +the number of intervals, :math:`\mu_i` are the values of the function +at the intervals, :math:`j_i` are the interval breakpoints; +:math:`j_0=0`, :math:`j_k=m`, :math:`j_{r-1}0`. The effect in the +:math:`\sigma` integral is cutting off the log-divergence, so that +with sufficient accuracy we can in :eq:`bic-form` replace + +.. math:: + :label: bic-form-2 + + \ln \sigma \mapsto \ln(\sigma_0 + \sigma) + +Here, we fix a measurement accuracy floor with the following guess: +``sigma_0 = 0.1 * w0 * min(abs(diff(mu)))`` and ``sigma_0 = 0.001 * w0 +* abs(mu)`` when there is only a single interval. Here, ``w0`` is the +median weight. + +Autocorrelated noise +-------------------- + +Practical experience shows that the noise in the benchmark results can be +correlated. Often benchmarks are run for multiple commits at once, for +example the new commits at a given time, and the benchmark machine +does something else between the runs. Alternatively, the background +load from other processes on the machine varies with time. + +To give a basic model for the noise correlations, we include +AR(1) Laplace noise in :eq:`prob-model`, + +.. math:: + :label: autocorr-model + + P(\{y_i\}_{i=1}^m|\sigma,\rho,k,\{\mu_i\}_{i=1}^k,\{j_i\}_{i=1}^{k-1}) + = + N + \sigma^{-m} + \exp(-\sigma^{-1}\sum_{r=1}^k\sum_{i=j_{r-1}+1}^{j_r} |\epsilon_{i,r} - \rho \epsilon_{i-1,r}|) + +where :math:`\epsilon_{i,r}=y_i-\mu_{r}` with +:math:`\epsilon_{j_{r-1},r}=y_{j_{r-1}}-\mu_{r-1}` and +:math:`\epsilon_{j_0,1}=0` are the deviations from the stepwise +model. The correlation measure :math:`\rho` is unknown, but assumed to +be constant in :math:`(-1,1)`. + +Since the parameter :math:`\rho` is global, it does not change the parameter +counting part of the Schwarz criterion. The maximum likelihood term however +does depend on :math:`\rho`, so that the problem becomes: + +.. math:: + :label: bic-form-autocorr + + \mathop{\mathrm{argmin}}_{k,\rho,\{j\},\{\mu\}} r(m) k + + \ln\sum_{r=1}^k\sum_{i=j_{r-1}}^{j_r} |\epsilon_{i,r} - \rho\epsilon_{i-1,r}| + +To save computation time, we do not solve this optimization problem +exactly. Instead, we again minimize along the :math:`\mu_r^*(\gamma)`, +:math:`j_r^*(\gamma)` curve provided by the solution to +:eq:`gamma-opt`, and use :eq:`bic-form-autocorr` only in selecting the +optimal value of the :math:`\gamma` parameter. + +The minimization vs. :math:`\rho` can be done numerically for given +:math:`\mu_r^*(\gamma)`, :math:`j_r^*(\gamma)`. This minimization step +is computationally cheap compared to the piecewise fit, so including +it will not significantly change the runtime of the total algorithm. + +Postprocessing +-------------- + +For the purposes of regression detection, we do not report all steps +the above approach provides. For details, see +``asv.step_detect.detect_regressions``. + +Making use of measured variance +------------------------------- + +``asv`` measures also variance in the timings. This information is +currently used to provide relative data weighting (see above). + +References +---------- + +.. bibliography:: + :filter: docname in docnames + :labelprefix: SDM_ + :keyprefix: sdm- diff --git a/docs/source/reference.rst b/docs/source/user_reference.rst similarity index 74% rename from docs/source/reference.rst rename to docs/source/user_reference.rst index ce0f91d61..1135e5f8e 100644 --- a/docs/source/reference.rst +++ b/docs/source/user_reference.rst @@ -1,5 +1,5 @@ -Reference -========= +User Reference +============== .. toctree:: diff --git a/docs/source/using.rst b/docs/source/using.rst index 211ee1954..2ee746632 100644 --- a/docs/source/using.rst +++ b/docs/source/using.rst @@ -127,7 +127,9 @@ information about the machine, such as its platform, cpu and memory. **airspeed velocity** will try to make reasonable guesses, so it's usually ok to just press ``Enter`` to accept each default value. This information is stored in the ``~/.asv-machine.json`` file in your home -directory:: +directory: + +.. code-block:: sh I will now ask you some questions about this machine to identify it in the benchmarks. diff --git a/pyproject.toml b/pyproject.toml index bdf4559f6..407c49de7 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -32,6 +32,9 @@ dependencies = [ "build", "tabulate", "virtualenv", + "packaging", + "pydantic", + "importlib-metadata", "tomli; python_version < '3.11'", "colorama; platform_system == 'Windows'", "pyyaml; platform_python_implementation != \"PyPy\"", @@ -52,7 +55,6 @@ test = [ "pytest-timeout", "pytest-rerunfailures>=10.0", "filelock", - "virtualenv", "numpy", "scipy; platform_python_implementation != \"PyPy\"", "feedparser", @@ -64,29 +66,32 @@ test = [ ] doc = [ "sphinx", - "sphinx_bootstrap_theme", + "sphinx-autoapi", + "sphinx-collapse", + "sphinxcontrib.bibtex", + "setuptools", # dependency from bibtex + "sphinxcontrib.katex", + "autodoc-pydantic", + "furo", ] dev = [ "ruff", "isort >= 5.11.5", ] -virtualenv = [ - "virtualenv", - "packaging", -] hg = [ "python-hglib", ] plugs = [ "asv-bench-memray", ] +all = ["asv[doc,dev,hg,plugs]"] [build-system] requires = [ "wheel", # pin setuptools: # https://github.com/airspeed-velocity/asv/pull/1426#issuecomment-2290658198 "setuptools>=64,<72.2.0", - "setuptools_scm>=6", + "setuptools_scm>=6", # Can't update to 8, it needs 3.8 ] build-backend = "setuptools.build_meta" diff --git a/test/test_statistics.py b/test/test_statistics.py index dbe4b5896..e8f810239 100644 --- a/test/test_statistics.py +++ b/test/test_statistics.py @@ -9,7 +9,7 @@ from asv_runner.statistics import (compute_stats, LaplacePosterior, quantile, quantile_ci, binom_pmf, get_err) -from asv import statistics +from asv import _stats def test_compute_stats(): @@ -51,8 +51,8 @@ def test_is_different(): samples_b = true_mean + 0.1 * np.random.rand(n) _, stats_a = compute_stats(samples_a, 1) _, stats_b = compute_stats(samples_b, 1) - assert statistics.is_different(None, None, stats_a, stats_b) == significant - assert statistics.is_different(samples_a, samples_b, stats_a, stats_b) == significant + assert _stats.is_different(None, None, stats_a, stats_b) == significant + assert _stats.is_different(samples_a, samples_b, stats_a, stats_b) == significant def _check_ci(estimator, sampler, nsamples=300): @@ -315,7 +315,7 @@ def check_table(m, tbl): if p is None: continue - p2 = statistics.mann_whitney_u_cdf(m, n, u, memo=memo) + p2 = _stats.mann_whitney_u_cdf(m, n, u, memo=memo) assert p2 == pytest.approx(p, abs=1e-3, rel=0), (m, n, u, p2, p) # Tables from Mann & Whitney, Ann. Math. Statist. 18, 50 (1947). @@ -363,15 +363,15 @@ def test_mann_whitney_u_scipy(): def check(x, y): u0, p0 = stats.mannwhitneyu(x, y, alternative='two-sided', use_continuity=False) - u, p = statistics.mann_whitney_u(x.tolist(), y.tolist(), method='normal') + u, p = _stats.mann_whitney_u(x.tolist(), y.tolist(), method='normal') assert u == u0 assert p == pytest.approx(p0, rel=1e-9, abs=0) - u, p = statistics.mann_whitney_u(x.tolist(), y.tolist(), method='exact') + u, p = _stats.mann_whitney_u(x.tolist(), y.tolist(), method='exact') assert u == u0 assert p == pytest.approx(p0, rel=5e-2, abs=5e-3) - u, p = statistics.mann_whitney_u(x.tolist(), y.tolist()) + u, p = _stats.mann_whitney_u(x.tolist(), y.tolist()) assert u == u0 assert p == pytest.approx(p0, rel=5e-2, abs=5e-3) @@ -388,19 +388,19 @@ def test_mann_whitney_u_basic(): # wilcox.test(a, b, exact=TRUE) a = [1, 2, 3, 4] b = [0.9, 1.1, 0.7] - u, p = statistics.mann_whitney_u(a, b, method='exact') + u, p = _stats.mann_whitney_u(a, b, method='exact') assert u == 11 assert p == pytest.approx(0.11428571428571428, abs=0, rel=1e-10) a = [1, 2] b = [1.5] - u, p = statistics.mann_whitney_u(a, b, method='exact') + u, p = _stats.mann_whitney_u(a, b, method='exact') assert u == 1 assert p == 1.0 a = [1, 2] b = [2.5] - u, p = statistics.mann_whitney_u(a, b, method='exact') + u, p = _stats.mann_whitney_u(a, b, method='exact') assert u == 0 assert p == pytest.approx(2 / 3, abs=0, rel=1e-10) @@ -419,7 +419,7 @@ def test_mann_whitney_u_R(): for m in range(1, len(a) + 1): for n in range(1, len(b) + 1): - u, p = statistics.mann_whitney_u(a[:m], b[:n]) + u, p = _stats.mann_whitney_u(a[:m], b[:n]) r = wilcox_test(robjects.FloatVector(a[:m]), robjects.FloatVector(b[:n])) @@ -442,7 +442,7 @@ def test_mann_whitney_u_R(): def test_binom(): for n in range(10): for k in range(10): - p = statistics.binom(n, k) + p = _stats.binom(n, k) if 0 <= k <= n: p2 = math.factorial(n) / math.factorial(k) / math.factorial(n - k) else: