"""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 []