# Dot Products

> NumKong for Python

Dot products are their own family because storage type, conjugation rules, and output widening matter.

```python
import numpy as np
import numkong as nk

a = (np.random.randn(256) + 1j * np.random.randn(256)).astype(np.complex64)
b = (np.random.randn(256) + 1j * np.random.randn(256)).astype(np.complex64)

dot = nk.dot(a, b)   # numpy.dot(a, b)
vdot = nk.vdot(a, b) # numpy.vdot(a, b)

print(dot, vdot)
```

Real low-precision inputs can also be routed through explicit dtype tags when the storage buffer itself is raw bytes.

`import numkong`

## pointer_to_*

Return the address of the [`inner`](#inner) kernel for [`dtype`](https://www.unum.cloud/docs/numkong/python/mesh-alignment.md#dtype), as an integer.

```python
def pointer_to_inner(
    dtype: _FloatTypeName | _ComplexTypeName | _MiniFloatType,
    /,
) -> int
```

- `pointer_to_inner`
- `pointer_to_dot`
- `pointer_to_vdot`

## *

Compute the inner product of two real or complex vectors.

```python
def inner(
    a: _BufferType,
    b: _BufferType,
    /,
    dtype: _FloatTypeName | _ComplexTypeName | _MiniFloatType | None = None,
    *,
    out: _BufferType | None = None,
    out_dtype: _FloatTypeName | _ComplexTypeName | _MiniFloatType | None = None,
    capabilities: Capability | int | None = ...,
    stream: int | None = ...,
) -> float | complex | Tensor | None
```

- `inner`
- `dot`

Similar to [`numpy.inner`](#inner). Two vectors give a scalar. Matrices pair row i of `a` with row i of
`b`, a single row pairing with every row of the other, into a new Tensor of one result per pair,
or into `out`, returning None.

Similar to [`numpy.dot`](#dot). Two vectors give a scalar. Matrices pair row i of `a` with row i of `b`,
a single row pairing with every row of the other, into a new Tensor of one result per pair, or
into `out`, returning None.

- `a`: First real or complex vector or matrix.
- `b`: Second real or complex vector or matrix, of the dtype of `a`.
- `dtype`: Input dtype to read both buffers as, overriding the one they report.
- `out`: Output vector for the results.
- `out_dtype`: Result dtype, by default that of `out`, else float64, complex128 for complex input.
- `capabilities`: Capabilities to run within: every CPU one by default, or for packed operands the mask that packed them.
- `stream`: A GPU stream pointer, left None on the CPU.

## vdot

Compute the dot product of two complex vectors, conjugating the first.

```python
def vdot(
    a: _BufferType,
    b: _BufferType,
    /,
    dtype: _ComplexTypeName | _MiniFloatType | None = None,
    *,
    out: _BufferType | None = None,
    out_dtype: _ComplexTypeName | _MiniFloatType | None = None,
    capabilities: Capability | int | None = ...,
    stream: int | None = ...,
) -> complex | Tensor | None
```

Similar to [`numpy.vdot`](#vdot). Two vectors give a scalar. Matrices pair row i of `a` with row i of
`b`, a single row pairing with every row of the other, into a new Tensor of one result per pair,
or into `out`, returning None.

- `a`: First complex vector or matrix.
- `b`: Second complex vector or matrix, of the dtype of `a`.
- `dtype`: Input dtype to read both buffers as, overriding the one they report.
- `out`: Output vector for the results.
- `out_dtype`: Result dtype, by default that of `out`, else complex128.
- `capabilities`: Capabilities to run within: every CPU one by default, or for packed operands the mask that packed them.
- `stream`: A GPU stream pointer, left None on the CPU.

