TheAlgorithms/Python · error · ValueError

number of (artificial) variables must be a natural number

Error message

number of (artificial) variables must be a natural number

What it means

Raised by the simplex solver when n_vars < 2 or n_artificial_vars < 0. The implementation requires at least two decision variables and a non-negative count of artificial variables (0 for standard-form problems, > 0 for problems needing phase 1).

Source

Thrown at linear_programming/simplex.py:54

    ...
    ValueError: number of (artificial) variables must be a natural number
    """

    # Max iteration number to prevent cycling
    maxiter = 100

    def __init__(
        self, tableau: np.ndarray, n_vars: int, n_artificial_vars: int
    ) -> None:
        if tableau.dtype != "float64":
            raise TypeError("Tableau must have type float64")

        # Check if RHS is negative
        if not (tableau[:, -1] >= 0).all():
            raise ValueError("RHS must be > 0")

        if n_vars < 2 or n_artificial_vars < 0:
            raise ValueError(
                "number of (artificial) variables must be a natural number"
            )

        self.tableau = tableau
        self.n_rows, n_cols = tableau.shape

        # Number of decision variables x1, x2, x3...
        self.n_vars, self.n_artificial_vars = n_vars, n_artificial_vars

        # 2 if there are >= or == constraints (nonstandard), 1 otherwise (std)
        self.n_stages = (self.n_artificial_vars > 0) + 1

        # Number of slack variables added to make inequalities into equalities
        self.n_slack = n_cols - self.n_vars - self.n_artificial_vars - 1

        # Objectives for each stage
        self.objectives = ["max"]

View on GitHub (pinned to f5988cc097)

Solutions

  1. Pass n_vars >= 2; for one-variable problems solve directly or add the class's expected minimum by modeling an unused slack variable.
  2. Compute the artificial-variable count as the number of '>='/'==' constraints (>= 0), never negative.
  3. Log both values right before construction to catch off-by-one counting from the constraint matrix.

Example fix

# before
solver = Simplex(tableau, n_vars=1, n_artificial_vars=-1)

# after
n_artificial = sum(1 for c in constraints if c.op in (">=", "=="))
solver = Simplex(tableau, n_vars=2, n_artificial_vars=n_artificial)
Defensive patterns

Strategy: validation

Validate before calling

n_artificial = sum(1 for c in constraints if c.op in (">=", "=="))
assert n_vars >= 2 and n_artificial >= 0
solver = Simplex(tableau, n_vars, n_artificial)

Type guard

def valid_var_counts(n_vars: int, n_artificial_vars: int) -> bool:
    return isinstance(n_vars, int) and n_vars >= 2 and isinstance(n_artificial_vars, int) and n_artificial_vars >= 0

Try / catch

try:
    Simplex(tableau, n_vars, n_artificial_vars)
except ValueError as e:
    if "natural number" in str(e):
        raise ValueError(f"bad counts: n_vars={n_vars}, n_artificial={n_artificial_vars}") from e
    raise

Prevention

When it happens

Trigger: Constructing the solver with n_vars=1 (single-variable LP), passing n_vars=0, or passing a negative artificial-variable count such as -1.

Common situations: Trying to solve a trivial one-variable LP through this class, or computing n_artificial_vars by a buggy count (e.g. subtracting instead of adding) that can go negative.

Related errors


AI-assisted analysis of TheAlgorithms/Python@f5988cc097 (2026-08-14). Data as JSON: /api/errors/5af5a48dd15d8694. Report an issue: GitHub.