{"record":{"id":"1c50f7203c55ce1e","repo":"TheAlgorithms/Python","slug":"epsilon-must-be-non-negative-got-epsilon-r","errorCode":null,"errorMessage":"epsilon must be non-negative, got {epsilon!r}","messagePattern":"epsilon must be non-negative, got (.+?)","errorType":"validation","errorClass":"ValueError","httpStatus":null,"severity":"error","filePath":"geometry/ramer_douglas_peucker.py","lineNumber":133,"sourceCode":"    []\n    >>> ramer_douglas_peucker([(0.0, 0.0)], epsilon=1.0)\n    [(0.0, 0.0)]\n    >>> ramer_douglas_peucker([(0.0, 0.0), (1.0, 0.0)], epsilon=1.0)\n    [(0.0, 0.0), (1.0, 0.0)]\n    >>> # middle point is within epsilon - it is discarded\n    >>> ramer_douglas_peucker([(0.0, 0.0), (1.0, 0.1), (2.0, 0.0)], epsilon=0.5)\n    [(0.0, 0.0), (2.0, 0.0)]\n    >>> # middle point exceeds epsilon - it is kept\n    >>> ramer_douglas_peucker([(0.0, 0.0), (1.0, 1.0), (2.0, 0.0)], epsilon=0.5)\n    [(0.0, 0.0), (1.0, 1.0), (2.0, 0.0)]\n    >>> ramer_douglas_peucker([(0.0, 0.0), (1.0, 0.5), (2.0, 0.0)], epsilon=-1.0)\n    Traceback (most recent call last):\n        ...\n    ValueError: epsilon must be non-negative, got -1.0\n    \"\"\"\n    if epsilon < 0:\n        msg = f\"epsilon must be non-negative, got {epsilon!r}\"\n        raise ValueError(msg)\n\n    if len(pts) < 3:\n        return list(pts)\n\n    # ---------------------------------------------------------------------------\n    # Iterative, stack-based implementation.\n    #\n    # The naive recursive approach copies sublists at every level via slicing\n    # (pts[:max_index+1] / pts[max_index:]), which is O(n) per call and makes\n    # the overall algorithm O(n²) in memory even for well-balanced splits.  An\n    # explicit stack operating on index ranges avoids all copying and also\n    # eliminates the risk of hitting Python's recursion limit for long polylines.\n    # ---------------------------------------------------------------------------\n    n = len(pts)\n\n    # keep[i] is True when pts[i] must appear in the output.\n    keep: list[bool] = [False] * n\n    keep[0] = True","sourceCodeStart":115,"sourceCodeEnd":151,"githubUrl":"https://github.com/TheAlgorithms/Python/blob/f5988cc09713315817df6a7e327e258013a94440/geometry/ramer_douglas_peucker.py#L115-L151","documentation":"Raised by ramer_douglas_peucker (geometry/ramer_douglas_peucker.py:133) when the epsilon parameter is negative. Epsilon is the maximum perpendicular distance a point may deviate from the simplification line; negative tolerances are geometrically meaningless, so the function validates epsilon >= 0 up front.","triggerScenarios":"ramer_douglas_peucker(points, epsilon=-1.0), or epsilon arriving as a computed value (e.g. -tolerance due to a sign flip, or 0.0 - margin from floating-point subtraction).","commonSituations":"Config/UI code computing epsilon as a difference that can go negative; parsing epsilon from config where a minus sign was mistyped; unit tests sweeping epsilon values across a range that includes negatives.","solutions":["Pass 0.0 to keep every point (no simplification) or a positive tolerance such as 0.5","Fix the producer of epsilon: clamp with max(0.0, epsilon) only if zero is genuinely acceptable for your use case","Validate config values at load time so a bad epsilon fails early with your own error message"],"exampleFix":"# before\nsimplified = ramer_douglas_peucker(pts, epsilon=base - margin)  # can be negative\n\n# after\nepsilon = abs(base - margin)\nsimplified = ramer_douglas_peucker(pts, epsilon=epsilon)","handlingStrategy":"validation","validationCode":"if not isinstance(epsilon, (int, float)) or epsilon < 0:\n    raise ValueError(f\"epsilon must be a non-negative number, got {epsilon!r}\")\nsimplified = ramer_douglas_peucker(points, epsilon=epsilon)","typeGuard":null,"tryCatchPattern":"try:\n    simplified = ramer_douglas_peucker(pts, epsilon=eps)\nexcept ValueError:\n    simplified = list(pts)  # fall back: keep all points","preventionTips":["Treat epsilon as an absolute distance; never derive it from a subtraction that can go negative","Validate tolerance values when loading configuration"],"tags":["geometry","input-validation","preprocessing"],"backgroundTag":null,"analyzedSha":"f5988cc09713315817df6a7e327e258013a94440","analyzedAt":"2026-08-14T17:30:07.041Z","schemaVersion":2},"datasetVersion":"2026-08-15T17:31:12.345Z"}