# How to Use Multi-Value Parameter Types (`multi_int`, `multi_float`) in Hypster

> Learn to use multi_int and multi_float parameter types in Hypster. Get validated lists of numbers with optional bounds and strict type checks using the HP class.

- Repository: [Gilad Rubin/hypster](https://github.com/gilad-rubin/hypster)
- Tags: how-to-guide
- Published: 2026-03-02

---

**The `HP` class in Hypster provides `multi_int` and `multi_float` helper methods that return validated lists of integers or floats while enforcing optional bounds checking and strict type constraints.**

The gilad-rubin/hypster library offers robust configuration management through type-safe parameter validation. When you need to capture lists of numeric values rather than single scalars, multi-value parameter types apply rigorous `IntValidator` or `FloatValidator` checks to every element. This guide demonstrates how to define integer and float list parameters with constraints, default values, and strict type enforcement.

## Defining Integer Lists with `multi_int`

The `multi_int` method creates a parameter that accepts a list of integers. According to the implementation in [[`src/hypster/hp.py`](https://github.com/gilad-rubin/hypster/blob/main/src/hypster/hp.py) lines 525-543](https://github.com/gilad-rubin/hypster/blob/master/src/hypster/hp.py#L525-L543), this helper validates each element using `IntValidator` and applies optional `min` and `max` constraints to every item in the list.

### Basic Syntax and Bounds Checking

Call `hp.multi_int(default_list, *, name, min=None, max=None)` to define an integer list parameter. The method requires a default list and a parameter name, with optional bounds that apply to each element individually.

```python
from hypster import HP, instantiate
from typing import List

def cfg(hp: HP) -> List[int]:
    # Default list [1, 2, 3]; each element must be in [0, 10]

    return hp.multi_int([1, 2, 3], name="values", min=0, max=10)

# Normal usage – returns the default list

assert instantiate(cfg) == [1, 2, 3]

# Override via values dict

assert instantiate(cfg, values={"values": [5, 6, 7]}) == [5, 6, 7]

```

This example demonstrates the bounds enforcement verified in [[`tests/test_multi_parameters.py`](https://github.com/gilad-rubin/hypster/blob/main/tests/test_multi_parameters.py) lines 10-22](https://github.com/gilad-rubin/hypster/blob/master/tests/test_multi_parameters.py#L10-L22). If you pass values outside the specified range, the validation raises an appropriate error before instantiation completes.

## Working with Float Lists via `multi_float`

The `multi_float` method, defined in [[`src/hypster/hp.py`](https://github.com/gilad-rubin/hypster/blob/main/src/hypster/hp.py) lines 545-563](https://github.com/gilad-rubin/hypster/blob/master/src/hypster/hp.py#L545-L563), operates similarly but uses `FloatValidator` for element validation. This helper includes a `strict` parameter that controls whether integers are automatically converted to floats or rejected as type errors.

### Strict Mode vs. Flexible Type Coercion

By default, `multi_float` operates with `strict=False`, allowing integer inputs to be silently converted to floating-point values. When `strict=True`, the validator raises a `ValueError` if any element is not a native float.

```python
def cfg_strict(hp: HP) -> List[float]:
    # strict=True forbids integer elements

    return hp.multi_float([1.0, 2.0], name="vals", strict=True)

# Valid call with native floats

assert instantiate(cfg_strict, values={"vals": [1.5, 2.5]}) == [1.5, 2.5]

# Invalid – integers raise ValueError

import pytest
with pytest.raises(ValueError, match="expected float but got int"):
    instantiate(cfg_strict, values={"vals": [1, 2]})

```

As shown in [[`tests/test_multi_parameters.py`](https://github.com/gilad-rubin/hypster/blob/main/tests/test_multi_parameters.py) lines 39-46](https://github.com/gilad-rubin/hypster/blob/master/tests/test_multi_parameters.py#L39-L46), strict mode ensures type safety when your configuration requires genuine floating-point inputs.

### Automatic Integer Conversion

When strict mode is disabled (the default), the system converts valid integers to floats automatically:

```python
def cfg_flexible(hp: HP) -> List[float]:
    # strict=False (default) – ints are auto-converted

    return hp.multi_float([1.0, 2.0], name="vals")

assert instantiate(cfg_flexible, values={"vals": [1, 2]}) == [1.0, 2.0]

```

This behavior is validated in [[`tests/test_multi_parameters.py`](https://github.com/gilad-rubin/hypster/blob/main/tests/test_multi_parameters.py) lines 48-52](https://github.com/gilad-rubin/hypster/blob/master/tests/test_multi_parameters.py#L48-L52).

## How Multi-Value Validation Works Internally

Understanding the internal implementation helps debug complex configurations. Both `multi_int` and `multi_float` delegate to `_execute_multi`, which forwards to `_handle_multi_value` in [[`src/hypster/hp.py`](https://github.com/gilad-rubin/hypster/blob/main/src/hypster/hp.py) lines 153-188](https://github.com/gilad-rubin/hypster/blob/master/src/hypster/hp.py#L153-L188).

The validation pipeline follows three steps:

1. **Spec Creation**: Each call builds a `MultiValueSpec` dataclass (defined in [[`hp.py`](https://github.com/gilad-rubin/hypster/blob/main/hp.py) lines 71-78](https://github.com/gilad-rubin/hypster/blob/master/src/hypster/hp.py#L71-L78)) that stores the name, default list, element validator, and constraint flags.

2. **Multi-Validation**: The `MultiValidator` class (from [`hp_calls.py`](https://github.com/gilad-rubin/hypster/blob/main/hp_calls.py)) validates each list element individually. For `multi_float`, it applies the `strict` flag during `FloatValidator` checks; for `multi_int`, it ensures every item is an integer.

3. **Bounds Enforcement**: After type validation, the system checks `min` and `max` constraints against each element using `validate_bounds` before storing the final list under the parameter path.

This architecture ensures consistent validation across all multi-value parameter types while maintaining clear error messages that identify which specific element failed validation.

## Summary

- **`multi_int`** creates validated integer lists with optional `min`/`max` bounds applied to every element, implemented via `IntValidator` in [`src/hypster/hp.py`](https://github.com/gilad-rubin/hypster/blob/main/src/hypster/hp.py).
- **`multi_float`** creates float lists with an optional `strict` mode; when enabled, rejects integers rather than converting them, using `FloatValidator` logic.
- Both methods store configurations as `MultiValueSpec` objects processed through `HP._handle_multi_value` to ensure type safety and bounds compliance.
- Override multi-value defaults by passing dictionaries to `instantiate()` with the parameter name as the key and a list as the value.

## Frequently Asked Questions

### What happens if I pass a single value instead of a list to `multi_int` or `multi_float`?

The `MultiValidator` expects an iterable collection. Passing a single scalar value will cause the validation to treat the scalar as the input, typically resulting in an iteration error or validation failure depending on the specific value type. Always wrap single overrides in a list, for example: `values={"param": [5]}` rather than `values={"param": 5}`.

### Can I use `multi_int` and `multi_float` with negative bounds?

Yes. The `min` and `max` parameters accept any valid integer or float, including negative values. The bounds validation in `_handle_multi_value` performs standard numeric comparisons, so you can constrain ranges like `min=-10, max=-1` or mix positive and negative boundaries as needed for your domain.

### How does strict mode affect performance?

Strict mode adds minimal overhead because it only changes the type-checking logic within `FloatValidator`. According to the implementation in [`src/hypster/hp_calls.py`](https://github.com/gilad-rubin/hypster/blob/main/src/hypster/hp_calls.py), the check is a simple `isinstance` validation prior to conversion. The performance difference is negligible for typical configuration lists, though strict mode prevents silent data type changes that might cause precision issues in downstream mathematics.

### Can I combine `multi_int` with other parameter types in the same configuration function?

Absolutely. You can mix `multi_int`, `multi_float`, single-value parameters like `int` or `float`, and selection parameters within the same `HP` configuration. Each parameter maintains its own namespace, and the `instantiate` function resolves all values simultaneously. Ensure each parameter has a unique `name` to avoid collisions during the configuration phase.