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

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 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.

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 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 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.

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 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:

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 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 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 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) 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.
  • 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, 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.

Have a question about this repo?

These articles cover the highlights, but your codebase questions are specific. Give your agent direct access to the source. Share this with your agent to get started:

Share the following with your agent to get started:
curl -s "https://instagit.com/install.md"

Works with
Claude Codex Cursor VS Code OpenClaw Any MCP Client

Maintain an open-source project? Get it listed too →