File size: 3,955 Bytes
79bc79a
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
"""Gradio interfaces for Operations Research solvers."""
import gradio as gr
import numpy as np

def parse_vector(input_str: str, dtype=float) -> list:
    """Parses a comma-separated string into a list of numbers."""
    if not input_str:
        return []
    try:
        return [dtype(x.strip()) for x in input_str.split(',')]
    except ValueError:
        gr.Warning(f"Could not parse vector: '{input_str}'. Please use comma-separated numbers (e.g., '1,2,3.5').")
        return []

def parse_matrix(input_str: str) -> np.ndarray:
    """Parses a string (rows separated by semicolons, elements by commas) into a NumPy array."""
    if not input_str:
        return np.array([])
    try:
        rows = input_str.split(';')
        matrix = []
        num_cols = -1
        for i, row_str in enumerate(rows):
            if not row_str.strip(): continue # Allow empty rows if they result from trailing semicolons

            row = [float(x.strip()) for x in row_str.split(',')]
            if num_cols == -1:
                num_cols = len(row)
            elif len(row) != num_cols:
                raise ValueError(f"Row {i+1} has {len(row)} elements, expected {num_cols}.")
            matrix.append(row)

        if not matrix: # If all rows were empty or input_str was just ';'
            return np.array([])

        return np.array(matrix)
    except ValueError as e:
        gr.Warning(f"Could not parse matrix: '{input_str}'. Error: {e}. Expected format: '1,2;3,4'. Ensure all rows have the same number of columns.")
        return np.array([])

def parse_relations(input_str: str) -> list[str]:
    """Parses a comma-separated string of relations into a list of strings."""
    if not input_str:
        return []
    try:
        relations = [r.strip() for r in input_str.split(',')]
        valid_relations = {"<=", ">=", "="}
        if not all(r in valid_relations for r in relations):
            invalid_rels = [r for r in relations if r not in valid_relations]
            gr.Warning(f"Invalid relation(s) found: {', '.join(invalid_rels)}. Allowed relations are: '<=', '>=', '='.")
            return []
        return relations
    except Exception as e: # Catch any other unexpected errors during parsing
        gr.Warning(f"Error parsing relations: '{input_str}'. Error: {e}")
        return []

def parse_bounds(input_str: str) -> list[tuple]:
    """
    Parses a string representing variable bounds into a list of tuples.
    Format: "lower1,upper1; lower2,upper2; ..." (e.g., "0,None; 0,10; None,None")
    'None' (case-insensitive) is used for no bound.
    """
    if not input_str:
        return []
    bounds_list = []
    try:
        pairs = input_str.split(';')
        for i, pair_str in enumerate(pairs):
            if not pair_str.strip(): continue # Allow for trailing semicolons or empty entries

            parts = pair_str.split(',')
            if len(parts) != 2:
                raise ValueError(f"Bound pair '{pair_str}' (entry {i+1}) does not have two elements. Expected format 'lower,upper'.")

            lower_str, upper_str = parts[0].strip().lower(), parts[1].strip().lower()

            lower = None if lower_str == 'none' else float(lower_str)
            upper = None if upper_str == 'none' else float(upper_str)

            if lower is not None and upper is not None and lower > upper:
                raise ValueError(f"Lower bound {lower} cannot be greater than upper bound {upper} for pair '{pair_str}' (entry {i+1}).")

            bounds_list.append((lower, upper))
        return bounds_list
    except ValueError as e:
        gr.Warning(f"Could not parse bounds: '{input_str}'. Error: {e}. Expected format: 'lower1,upper1; lower2,upper2; ...' e.g., '0,None; 0,10'. Use 'None' for no bound.")
        return []
    except Exception as e: # Catch any other unexpected parsing errors
        gr.Warning(f"Unexpected error parsing bounds: '{input_str}'. Error: {e}")
        return []