Before getting started on any practical recipes, we'll use this opening chapter to introduce several core mathematical concepts and structures and their Python representations. In particular, we'll look at basic numerical types, basic mathematical functions (trigonometric functions, the exponential function, and logarithms), and matrices. Matrices are fundamental in most computational applications because of the connection between matrices and solutions of systems of linear equations. We'll explore some of these applications in this chapter, but matrices will play an important role throughout this book.

We'll cover the following main topics in this order:

- Python numerical types
- Basic mathematical functions
- NumPy arrays
- Matrices

# Technical requirements

In this chapter, and throughout this book, we will use Python version 3.8, which is the most recent version of Python at the time of writing. Most of the code in this book will work on recent versions of Python from 3.6. We will use features that were introduced in Python 3.6 at various points, including f-strings. This means that you may need to change `python3.8`, which appears in any terminal commands to match your version of Python. This might be another version of Python, such as `python3.6` or `python3.7`, or a more general command such as `python3` or `python`. For the latter commands, you need to check that the version of Python is at least 3.6 by using the following command:

python --version

Python has built-in numerical types and basic mathematical functions that suffice for small applications that involve only small calculations. The NumPy package provides a high performance array type and associated routines (including...

# Python numerical types

Python provides basic numerical types such as arbitrarily sized integers and floating-point numbers (double precision) as standard, but it also provides several additional types that are useful in specific applications where precision is especially important. Python also provides (built-in) support for complex numbers, which are useful for some more advanced mathematical applications.

## Decimal type

For applications that require decimal digits with accurate arithmetic operations, use the`Decimal` type from the`decimal` module in the Python Standard Library:

from decimal import Decimal

num1 = Decimal('1.1')

num2 = Decimal('1.563')

num1 + num2 # Decimal('2.663')

Performing this calculation with float objects gives the result 2.6630000000000003, which includes a small error arising from the fact that certain numbers cannot be represented exactly using a finite sum of powers of 2. For example, 0.1 has a binary...

# Basic mathematical functions

Basic mathematical functions appear in many applications. For example, logarithms can be used to scale data that grows exponentially to give linear data. The exponential function and trigonometric functions are common fixtures when working with geometric information, the *gamma function* appears in combinatorics, and the *Gaussian error function* is important in statistics*.*

The `math` module in the Python Standard Library provides all of the standard mathematical functions, along with common constants and some utility functions, and it can be imported using the following command:

import math

Once it's imported, we can use any of the mathematical functions that are contained in this module. For instance, to find the square root of a non-negative number, we would use the `sqrt` function from `math`:

import math

math.sqrt(4) # 2.0

Attempting to use the `sqrt` function with a negative argument will raise a ValueError....

# NumPy arrays

NumPy provides high performance array types and routines for manipulating these arrays in Python. These arrays are useful for processing large datasets where performance is crucial. NumPy forms the base for the numerical and scientific computing stack in Python. Under the hood, NumPy makes use of low-level libraries for working with vectors and matrices, such as the **Basic Linear Algebra Subprograms** (**BLAS**) package, and the **Linear Algebra Package** (**LAPACK**)contains more advanced routines for linear algebra.

Traditionally, the NumPy package is imported under the shorter alias `np`, which can be accomplished using the following `import` statement:

import numpy as np

In particular, this convention is used in the NumPy documentation and in the wider scientific Python ecosystem (SciPy, Pandas, and so on).

The basic type provided by the NumPy library is the `ndarray` type (henceforth referred to as a NumPy array). Generally, you won't create your...

# Matrices

NumPy arrays also serve as *matrices*, which are fundamental in mathematics and computational programming. A *matrix* is simply a two-dimensional array. Matrices are central in many applications, such as geometric transformations and simultaneous equations, but also appear as useful tools in other areas such a statistics. Matrices themselves are only distinctive (compared to any other array) once we equip them with *matrix arithmetic*. Matrices have element-wise addition and subtraction operations, just as for NumPy arrays, a third operation called *scalar multiplication*, where we multiply every element of the matrix by a constant number, and a different notion of *matrix multiplication*. Matrix multiplication is fundamentally different from other notions of multiplication, as we will see later.

One of the most important attributes of a matrix is its shape, defined exactly as for NumPy arrays. A matrix with *m* rows and *n* columns is usuallydescribed as an *m × n *matrix...

# Summary

Python offers built-in support for mathematics with some basic numerical types, arithmetic, and basic mathematical functions. However, for more serious computations involving large arrays of numerical values, you should use the NumPy and SciPy packages. NumPy provides high-performance array types and basic routines, while SciPy provides more specific tools for solving equations and working with sparse matrices (among many other things).

NumPy arrays can be multi-dimensional. In particular, two-dimensional arrays have matrix properties that can be accessed using the `linalg` module from either NumPy or SciPy (the former is a subset of the latter). Moreover, there is a special operator in Python for matrix multiplication, `@`, which is implemented for NumPy arrays.

In the next chapter, we'll get started looking at some recipes.

# Further reading

There are many mathematical textbooks describing the basic properties of matrices and linear algebra, which is the study of vectors and matrices. A good introductory text is *Blyth, T. and Robertson, E. (2013). Basic Linear Algebra**. London: Springer London, Limited*.

NumPy and SciPy are part of the Python mathematical and scientific computing ecosystem, and have extensive documentation that can be accessed from the official website, https://scipy.org. We will see several other packages from this ecosystem throughout this book.

More information about the BLAS and LAPACK libraries that NumPy and SciPy use behind the scenes can be found at the following links: BLAS: https://www.netlib.org/blas/ and LAPACK: https://www.netlib.org/lapack/.