{ "cells": [ { "cell_type": "markdown", "id": "b513752e", "metadata": {}, "source": [ "(interval_analysis)=\n", "# interval analysis" ] }, { "cell_type": "code", "execution_count": null, "id": "683e8e35-be2e-4bb1-bdda-134b725bfecf", "metadata": {}, "outputs": [], "source": [ "import pyuncertainnumber as pun\n", "from pyuncertainnumber import pba" ] }, { "cell_type": "markdown", "id": "8e349c05-dedf-4088-aee3-f64272ad54ae", "metadata": {}, "source": [ "*Interval analysis* plays a key role in uncertainty quantification, especially regarding the epistemic uncertainty. `pyuncertainnumber` builds upon a pioneering project [Intervals](https://github.com/marcodeangelis/intervals) which provides a wide spectrum of low-level calculations, and significantly extend to further provide additional functionalities for such as propagation and optimisation in the presence of epistemic uncertainty. One appealing characteristic of *interval analysis* is that it provides a rigorous computational environment." ] }, { "cell_type": "markdown", "id": "309545b3-a60e-44a3-a5ee-29bbffd0c466", "metadata": {}, "source": [ "Intervals are typically used to characterise an uncertain varible when only the range is known. No probability distribution (i.e. relative likelihood within this range) can be justified. There are many ways an interval representation can be constructed. \n", "\n", "Canonically, an interval is constructed by a lower bound and an upper bound. In addition, `pyuncertainnumber` provides many more constructors to allow construcutions in intuitive manners. \n", "\n", "For example, natural language support allows one to specify an interval as in \"[2 +- 10%]\", and linguistic hedges such as \"about 7\". See {ref}`hedges` about additional details of linguistic hedges. Moreover, significant digits frequent in engineering analysis also indicate measurement uncertainties and can thus be modelled as intervals as well." ] }, { "cell_type": "code", "execution_count": 2, "id": "f60bd72d-46f6-492a-8baa-ac0aea6d97ef", "metadata": {}, "outputs": [ { "data": { "text/plain": [ "UncertainNumber(essence='interval', intervals=[2.0,3.0], _construct=[2.0,3.0], nominal_value=2.5)" ] }, "execution_count": 2, "metadata": {}, "output_type": "execute_result" } ], "source": [ "# canonical construction\n", "pun.I(2, 3)" ] }, { "cell_type": "code", "execution_count": 3, "id": "357f1988-56af-438f-b2c0-9bc0a67c90e1", "metadata": {}, "outputs": [ { "data": { "text/plain": [ "UncertainNumber(essence='interval', intervals=[1.8,2.2], _construct=[1.8,2.2], nominal_value=2.0)" ] }, "execution_count": 3, "metadata": {}, "output_type": "execute_result" } ], "source": [ "pun.I(\"[2 +- 10%]\")" ] }, { "cell_type": "code", "execution_count": 4, "id": "aab42675-af68-4339-98b7-c27544e28a96", "metadata": {}, "outputs": [ { "data": { "text/plain": [ "UncertainNumber(essence='interval', intervals=[6.8,7.2], _construct=[6.8,7.2], nominal_value=7.0)" ] }, "execution_count": 4, "metadata": {}, "output_type": "execute_result" } ], "source": [ "pun.I(\"about 7.\")" ] }, { "cell_type": "markdown", "id": "97f868bb-7c49-4b6c-b6f0-5a35dbd9f645", "metadata": {}, "source": [ "### Interval arrays\n", "\n", "Additional capabilities are provided when working with the `pba` API. Similar to `numpy`, high dimentional interval objects (i.e. interval arrays) can be created with ease, and one can get the hint about the interval array `i` with attributes such as `i.scalar`, `i.ndim`, `i.shape`." ] }, { "cell_type": "code", "execution_count": 5, "id": "073236f2-cd9c-4e14-a4ff-be9ef29e2420", "metadata": {}, "outputs": [ { "data": { "text/plain": [ "True" ] }, "execution_count": 5, "metadata": {}, "output_type": "execute_result" } ], "source": [ "s = pba.I(2,3)\n", "s.scalar" ] }, { "cell_type": "code", "execution_count": 6, "id": "2b90a541-efba-42db-86d2-f6db4c244d32", "metadata": {}, "outputs": [], "source": [ "v = pba.I(lo=[2., 3., 4.], hi=[7., 8., 9.])" ] }, { "cell_type": "code", "execution_count": 7, "id": "ce4b02cf-6385-4d4f-b001-382f6367f465", "metadata": {}, "outputs": [ { "data": { "text/plain": [ "1" ] }, "execution_count": 7, "metadata": {}, "output_type": "execute_result" } ], "source": [ "v.ndim" ] }, { "cell_type": "code", "execution_count": 8, "id": "09ae3e6c-b6fd-4e1d-8ffb-e2fc06bc92ce", "metadata": {}, "outputs": [ { "data": { "text/plain": [ "(3,)" ] }, "execution_count": 8, "metadata": {}, "output_type": "execute_result" } ], "source": [ "v.shape" ] }, { "cell_type": "markdown", "id": "167c60b5-8254-45de-bed1-98a12f56b961", "metadata": {}, "source": [ "Any array-like structure whose shape is (n,...,2) can be cast to an interval structure." ] }, { "cell_type": "code", "execution_count": 9, "id": "45dad043-15f2-40bd-9d73-8dc495daf569", "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "[1. 2.] [2. 3.] [4. 5.]\n", "[-1. 2.] [-2. 1.] [3. 5.]\n", "[0. 2.] [3. 4.] [6. 8.]\n" ] } ], "source": [ "a = [[[1,2], [2,3], [4,5]],\n", " [[-1,2],[-2,1],[3,5]],\n", " [[0,2], [3,4], [6,8]]]\n", "\n", "m = pba.intervalise(a)\n", "print(m)" ] }, { "cell_type": "markdown", "id": "d46d06af-9fbc-45e3-adef-34f6d2c647cc", "metadata": {}, "source": [ "### margin-of-error notation" ] }, { "cell_type": "markdown", "id": "07c71bc1-18dd-4d6e-97e8-202e429a4843", "metadata": {}, "source": [ "Intervals can also be created with the common conception of error bars. Common in scientific computations, a margin of error, in the form of `[x +- half_width]` is employed as ballpark estimates." ] }, { "cell_type": "code", "execution_count": 10, "id": "f461d0e4-36c3-4095-94ec-d74387fe3a41", "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "[1.7,2.3]\n" ] } ], "source": [ "s = pba.I.from_meanform(\n", " x=2, half_width=0.3\n", ")\n", "print(s)" ] }, { "cell_type": "code", "execution_count": 11, "id": "bc5bf86f-14c4-4df6-ae03-8cb7e65f633b", "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "[1.8,2.2]\n", "[2.7,3.3]\n", "[3.6,4.4]\n" ] } ], "source": [ "v = pba.I.from_meanform(\n", " [2, 3, 4], [0.2, 0.3, 0.4]\n", ")\n", "print(v)" ] }, { "cell_type": "markdown", "id": "a9d154fd-6589-460d-8d76-db0b3750a911", "metadata": {}, "source": [ "```note\n", "**convertion to p-box**\n", "Interval can also be deemed as a p-box whose bounds are unit step functions. \n", "```" ] }, { "cell_type": "markdown", "id": "9c1fa6ce-43c2-47b3-ba66-a7d8ffdfaa4c", "metadata": {}, "source": [ "Such conversion can be easily done in `pyuncertainnumber`" ] }, { "cell_type": "code", "execution_count": 12, "id": "29ea0c54-02d1-4547-b3cf-4d731f0c1a9d", "metadata": {}, "outputs": [ { "data": { "text/plain": [ "Pbox ~ (range=[2.000, 3.000], mean=[2.000, 3.000], var=[0.000, 0.250])" ] }, "execution_count": 12, "metadata": {}, "output_type": "execute_result" } ], "source": [ "pba.I(2, 3).to_pbox()" ] }, { "cell_type": "markdown", "id": "d89fa855-4426-404d-9566-a2e7f46594db", "metadata": {}, "source": [ "### interval propagation\n", "\n", "Abundant strategies exist for propagating intervals through functions, and it is desired to be acomplished in a rigorous way. See this [guide](https://pyuncertainnumber.readthedocs.io/en/latest/guides/up.html) for an overview of such strategies. Besides a high-level API [Propagation](https://pyuncertainnumber.readthedocs.io/en/latest/autoapi/pyuncertainnumber/propagation/p/index.html#pyuncertainnumber.propagation.p.Propagation) which allows users to conduct uncertainty propagation whatever the uncertainty representations are, `pyuncertainnumber` also provides a low-level bespoke function [b2b](https://pyuncertainnumber.readthedocs.io/en/latest/autoapi/pyuncertainnumber/propagation/epistemic_uncertainty/b2b/index.html#pyuncertainnumber.propagation.epistemic_uncertainty.b2b.b2b) to support such operations with detailed controls." ] }, { "cell_type": "markdown", "id": "8890ea0b-af14-4800-ac28-7098501ef83e", "metadata": {}, "source": [ "In some simple cases, one can directly do interval arithmeic calculations intrusively when the function/equation is accessible. Through duck-typing, `pyuncertainnumber` allows drop-in replacements of uncertain number objects in Python function. But note that *interval dependency* presents as a critical issue, see {ref}`interval_dependency` for additional details and the take-away message is `pyuncertainnumber` provide strategies to solve this issue." ] }, { "cell_type": "markdown", "id": "01e2f729-01ed-48bb-8789-123545ea0968", "metadata": {}, "source": [ "```tip\n", "See xxx for a realistic engineering example demonstrating uncertainty propagation\n", "```" ] }, { "cell_type": "code", "execution_count": 13, "id": "ba0830d4-61ea-4de1-90f3-b767b3782137", "metadata": {}, "outputs": [], "source": [ "def foo(x,y):\n", " return x*3 + y**3" ] }, { "cell_type": "code", "execution_count": 14, "id": "b976fb40-12c3-465c-8b31-57c8aeae32aa", "metadata": {}, "outputs": [ { "data": { "text/plain": [ "[70.0,134.0]" ] }, "execution_count": 14, "metadata": {}, "output_type": "execute_result" } ], "source": [ "x, y = pba.I(2., 3.), pba.I(4, 5)\n", "foo(x,y)" ] }, { "cell_type": "markdown", "id": "d87549b7-e94f-405a-ba1c-77567fd3d803", "metadata": {}, "source": [ "### backcalculation" ] } ], "metadata": { "kernelspec": { "display_name": "Python 3 (ipykernel)", "language": "python", "name": "python3" }, "language_info": { "codemirror_mode": { "name": "ipython", "version": 3 }, "file_extension": ".py", "mimetype": "text/x-python", "name": "python", "nbconvert_exporter": "python", "pygments_lexer": "ipython3", "version": "3.11.10" } }, "nbformat": 4, "nbformat_minor": 5 }