Skip to content

Element-wise Min Max

np.minimum

1. Basic Usage

np.minimum compares two arrays element-wise and returns the smaller value at each position.

import numpy as np

def main():
    a = np.array([1, 5, 3, 7])
    b = np.array([2, 3, 4, 6])

    c = np.minimum(a, b)

    print(f"a = {a}")
    print(f"b = {b}")
    print(f"np.minimum(a, b) = {c}")

if __name__ == "__main__":
    main()

Output:

a = [1 5 3 7]
b = [2 3 4 6]
np.minimum(a, b) = [1 3 3 6]

2. With Scalar

Broadcasting allows comparing with a scalar.

import numpy as np

def main():
    a = np.array([1, 5, 3, 7, 2])
    threshold = 4

    c = np.minimum(a, threshold)

    print(f"a = {a}")
    print(f"threshold = {threshold}")
    print(f"np.minimum(a, threshold) = {c}")

if __name__ == "__main__":
    main()

Output:

a = [1 5 3 7 2]
threshold = 4
np.minimum(a, threshold) = [1 4 3 4 2]

3. Clamp Upper Bound

import numpy as np
import matplotlib.pyplot as plt

def main():
    a = np.linspace(-2, 2, 11)
    b = np.zeros_like(a)
    c = np.minimum(a, b)

    fig, ax = plt.subplots(figsize=(6.5, 4))

    ax.plot(a, c, 'b-', linewidth=2)

    ax.spines['left'].set_position("zero")
    ax.spines['bottom'].set_position("zero")
    ax.spines['right'].set_visible(False)
    ax.spines['top'].set_visible(False)

    ax.set_xticks((-2, -1, 0, 1, 2))
    ax.set_yticks((0, -1, -2))
    ax.set_xlim(-2, 2)
    ax.set_ylim(-2, 0.1)
    ax.set_title('np.minimum(x, 0)')

    plt.show()

if __name__ == "__main__":
    main()

np.maximum

1. Basic Usage

np.maximum compares two arrays element-wise and returns the larger value at each position.

import numpy as np

def main():
    a = np.array([1, 5, 3, 7])
    b = np.array([2, 3, 4, 6])

    c = np.maximum(a, b)

    print(f"a = {a}")
    print(f"b = {b}")
    print(f"np.maximum(a, b) = {c}")

if __name__ == "__main__":
    main()

Output:

a = [1 5 3 7]
b = [2 3 4 6]
np.maximum(a, b) = [2 5 4 7]

2. With Scalar

import numpy as np

def main():
    a = np.array([1, 5, 3, 7, 2])
    threshold = 4

    c = np.maximum(a, threshold)

    print(f"a = {a}")
    print(f"threshold = {threshold}")
    print(f"np.maximum(a, threshold) = {c}")

if __name__ == "__main__":
    main()

Output:

a = [1 5 3 7 2]
threshold = 4
np.maximum(a, threshold) = [4 5 4 7 4]

3. ReLU Activation

The ReLU (Rectified Linear Unit) function is max(0, x).

import numpy as np
import matplotlib.pyplot as plt

def main():
    a = np.linspace(-2, 2, 11)
    b = np.zeros_like(a)
    c = np.maximum(a, b)

    fig, ax = plt.subplots(figsize=(12, 3))

    ax.plot(a, c, label='ReLU')
    ax.legend(fontsize=15)

    ax.spines['left'].set_position("zero")
    ax.spines['bottom'].set_position("zero")
    ax.spines['right'].set_visible(False)
    ax.spines['top'].set_visible(False)

    ax.set_xticks((-2, -1, 0, 1, 2))
    ax.set_yticks((0, 1, 2))
    ax.set_xlim(-2, 2)
    ax.set_ylim(-0.1, 2)

    plt.show()

if __name__ == "__main__":
    main()

Broadcasting

1. Scalar Broadcast

Both np.minimum and np.maximum support broadcasting with scalars.

import numpy as np
import matplotlib.pyplot as plt

def main():
    # ReLU with broadcasting (no zeros_like needed)
    a = np.linspace(-2, 2, 11)
    c = np.maximum(a, 0)  # scalar broadcasts

    fig, ax = plt.subplots(figsize=(12, 3))

    ax.plot(a, c, label='ReLU')
    ax.legend(fontsize=15)

    ax.spines['left'].set_position("zero")
    ax.spines['bottom'].set_position("zero")
    ax.spines['right'].set_visible(False)
    ax.spines['top'].set_visible(False)

    ax.set_xticks((-2, -1, 0, 1, 2))
    ax.set_yticks((0, 1, 2))
    ax.set_xlim(-2, 2)
    ax.set_ylim(-0.1, 2)

    plt.show()

if __name__ == "__main__":
    main()

2. Array Broadcast

import numpy as np

def main():
    # 2D array vs 1D array
    a = np.array([[1, 5, 3],
                  [4, 2, 6]])

    b = np.array([2, 3, 4])  # broadcasts to each row

    print("a =")
    print(a)
    print()
    print(f"b = {b}")
    print()
    print("np.maximum(a, b) =")
    print(np.maximum(a, b))

if __name__ == "__main__":
    main()

Output:

a =
[[1 5 3]
 [4 2 6]]

b = [2 3 4]

np.maximum(a, b) =
[[2 5 4]
 [4 3 6]]

3. Different Shapes

import numpy as np

def main():
    # Column vector vs row vector
    a = np.array([[1], [2], [3]])  # (3, 1)
    b = np.array([10, 20])         # (2,)

    print(f"a.shape = {a.shape}")
    print(f"b.shape = {b.shape}")
    print()

    result = np.maximum(a, b)
    print(f"np.maximum(a, b).shape = {result.shape}")
    print(result)

if __name__ == "__main__":
    main()

min vs minimum

1. Key Difference

  • np.min / a.min(): Reduction (finds minimum in array)
  • np.minimum: Element-wise comparison of two arrays
import numpy as np

def main():
    a = np.array([1, 5, 3])
    b = np.array([2, 3, 4])

    print("Reduction (single array):")
    print(f"  np.min(a) = {np.min(a)}")
    print(f"  a.min() = {a.min()}")
    print()

    print("Element-wise (two arrays):")
    print(f"  np.minimum(a, b) = {np.minimum(a, b)}")

if __name__ == "__main__":
    main()

2. Similar Pattern

import numpy as np

def main():
    a = np.array([1, 5, 3])
    b = np.array([2, 3, 4])

    print("Reduction functions:")
    print(f"  np.min(a) = {np.min(a)}")
    print(f"  np.max(a) = {np.max(a)}")
    print()

    print("Element-wise functions:")
    print(f"  np.minimum(a, b) = {np.minimum(a, b)}")
    print(f"  np.maximum(a, b) = {np.maximum(a, b)}")

if __name__ == "__main__":
    main()

3. Use Case Summary

import numpy as np

def main():
    """
    Use np.min/np.max when:
    - Finding the smallest/largest value in one array
    - Reducing along an axis

    Use np.minimum/np.maximum when:
    - Comparing two arrays element by element
    - Clamping values (with scalar broadcast)
    - Implementing functions like ReLU
    """

    data = np.array([[-1, 2], [3, -4]])

    # Find global minimum
    print(f"Global min: {np.min(data)}")

    # Clamp negative values to 0
    print(f"ReLU result:\n{np.maximum(data, 0)}")

if __name__ == "__main__":
    main()

Practical Examples

1. Clip Values

import numpy as np

def main():
    data = np.array([0.1, 0.5, 1.2, -0.3, 0.8])

    # Clip to [0, 1] range
    clipped = np.minimum(np.maximum(data, 0), 1)

    print(f"Original: {data}")
    print(f"Clipped:  {clipped}")

    # Equivalent using np.clip
    clipped2 = np.clip(data, 0, 1)
    print(f"np.clip:  {clipped2}")

if __name__ == "__main__":
    main()

2. Leaky ReLU

import numpy as np
import matplotlib.pyplot as plt

def leaky_relu(x, alpha=0.1):
    return np.maximum(x, alpha * x)

def main():
    x = np.linspace(-2, 2, 100)
    y = leaky_relu(x, alpha=0.1)

    fig, ax = plt.subplots(figsize=(8, 4))

    ax.plot(x, y, label='Leaky ReLU (α=0.1)')
    ax.plot(x, np.maximum(x, 0), '--', label='ReLU')
    ax.legend()

    ax.axhline(0, color='gray', linewidth=0.5)
    ax.axvline(0, color='gray', linewidth=0.5)
    ax.set_xlabel('x')
    ax.set_ylabel('y')
    ax.set_title('Leaky ReLU vs ReLU')

    plt.show()

if __name__ == "__main__":
    main()

3. Soft Maximum

import numpy as np

def main():
    # Element-wise max of multiple arrays
    a = np.array([1, 4, 2])
    b = np.array([3, 2, 5])
    c = np.array([2, 3, 1])

    # Chain maximum calls
    result = np.maximum(np.maximum(a, b), c)

    print(f"a = {a}")
    print(f"b = {b}")
    print(f"c = {c}")
    print(f"Element-wise max = {result}")

if __name__ == "__main__":
    main()