pedrobritto-123 commited on
Commit
2369b26
·
verified ·
1 Parent(s): 1a1b41b

Update app_1.py

Browse files
Files changed (1) hide show
  1. app_1.py +219 -1
app_1.py CHANGED
@@ -1600,4 +1600,222 @@ with gr.Blocks() as demo:
1600
  if __name__ == "__main__":
1601
  demo.launch()
1602
 
1603
- """
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1600
  if __name__ == "__main__":
1601
  demo.launch()
1602
 
1603
+
1604
+ """
1605
+
1606
+ """import gradio as gr
1607
+ from typing import List, Tuple, Dict, Any
1608
+ import math
1609
+ import re
1610
+ EPS = 1e-9
1611
+ # --------------------------- Linear Algebra Helpers ---------------------------
1612
+ def zeros(rows, cols):
1613
+ return [[0.0] * cols for _ in range(rows)]
1614
+ # --------------------------- Parser Utilities ---------------------------
1615
+ def parse_coeffs(text: str) -> List[float]:
1616
+ # Parseia coeficientes da função objetivo.
1617
+ if not text or not text.strip():
1618
+ return []
1619
+ s = text.replace(',', ' ')
1620
+ parts = [p for p in s.split() if p.strip()]
1621
+ coeffs = []
1622
+ for p in parts:
1623
+ try:
1624
+ coeffs.append(float(eval(p)))
1625
+ except Exception:
1626
+ raise ValueError(f"Coeficiente inválido: '{p}'")
1627
+ return coeffs
1628
+ def parse_constraints(text: str, nvars: int) -> List[Dict[str,Any]]:
1629
+ lines = [ln.strip() for ln in text.strip().splitlines() if ln.strip()]
1630
+ cons = []
1631
+ for ln in lines:
1632
+ s = ln.replace(" ", "")
1633
+ # operador lógico
1634
+ if "<=" in s or "=<" in s:
1635
+ s = s.replace("=<", "<=")
1636
+ left, right = s.split("<=")
1637
+ sense = "<="
1638
+ elif ">=" in s or "=>" in s:
1639
+ s = s.replace("=>", ">=")
1640
+ left, right = s.split(">=")
1641
+ sense = ">="
1642
+ elif "=" in s:
1643
+ left, right = s.split("=")
1644
+ sense = "="
1645
+ else:
1646
+ raise ValueError(f"Restrição inválida, faltando <=, >= ou = : '{ln}'")
1647
+ # RHS
1648
+ try:
1649
+ rhs = float(eval(right))
1650
+ except:
1651
+ raise ValueError(f"RHS inválido: '{right}'")
1652
+ # capturar termos tipo +2x1, -3x2, 6/5x1
1653
+ pattern = r'([+-]?[0-9./]*)(x[0-9]+)'
1654
+ terms = re.findall(pattern, left)
1655
+ coeffs = [0.0] * nvars
1656
+ for coef_str, var_str in terms:
1657
+ idx = int(var_str[1:]) - 1
1658
+ if idx < 0 or idx >= nvars:
1659
+ raise ValueError(f"Variável fora do intervalo: {var_str}")
1660
+ if coef_str in ["", "+"]:
1661
+ v = 1.0
1662
+ elif coef_str == "-":
1663
+ v = -1.0
1664
+ else:
1665
+ v = float(eval(coef_str))
1666
+ coeffs[idx] += v
1667
+ cons.append({
1668
+ "coeffs": coeffs,
1669
+ "sense": sense,
1670
+ "rhs": rhs
1671
+ })
1672
+ return cons
1673
+ # --------------------------- Simplex Implementation ---------------------------
1674
+ def build_canonical_tableau(objective: List[float], constraints: List[Dict[str,Any]], sense: str = 'max'):
1675
+ c = objective[:]
1676
+ obj_mult = 1.0
1677
+ if sense == 'min':
1678
+ obj_mult = -1.0
1679
+ c_adj = [ci * obj_mult for ci in c]
1680
+ norm = []
1681
+ for row in constraints:
1682
+ coeffs = row['coeffs'][:]
1683
+ rhs = row['rhs']
1684
+ s = row['sense']
1685
+ if s == '>=':
1686
+ coeffs = [-a for a in coeffs]
1687
+ rhs = -rhs
1688
+ s = '<='
1689
+ norm.append({"coeffs": coeffs, "rhs": rhs, "sense": s})
1690
+ m = len(norm)
1691
+ n = len(c_adj)
1692
+ T = zeros(m + 1, n + m + 1)
1693
+ for i in range(m):
1694
+ for j in range(n):
1695
+ T[i][j] = norm[i]['coeffs'][j]
1696
+ T[i][n + i] = 1.0
1697
+ T[i][n + m] = norm[i]['rhs']
1698
+ for j in range(n):
1699
+ T[m][j] = -c_adj[j]
1700
+ return T, n, m, c, obj_mult, norm
1701
+ def extract_solution_from_tableau(T, basis, n, m, original_c):
1702
+ x = [0.0] * n
1703
+ for i in range(m):
1704
+ if basis[i] < n:
1705
+ x[basis[i]] = T[i][n + m]
1706
+ obj = sum(original_c[j] * x[j] for j in range(n))
1707
+ return x, obj
1708
+ def snapshot(T, basis, n, m):
1709
+ x = [0.0] * n
1710
+ for i in range(m):
1711
+ if basis[i] < n:
1712
+ x[basis[i]] = T[i][n + m]
1713
+ return {
1714
+ "basis": basis[:],
1715
+ "x": [float(f"{v:.6f}") for v in x],
1716
+ "tableau": [row[:] for row in T]
1717
+ }
1718
+ def pivot(T, row, col):
1719
+ piv = T[row][col]
1720
+ if abs(piv) < EPS:
1721
+ raise ZeroDivisionError("Pivot quase zero")
1722
+ cols = len(T[0])
1723
+ rows = len(T)
1724
+ for j in range(cols):
1725
+ T[row][j] /= piv
1726
+ for i in range(rows):
1727
+ if i == row:
1728
+ continue
1729
+ factor = T[i][col]
1730
+ for j in range(cols):
1731
+ T[i][j] -= factor * T[row][j]
1732
+ def primal_simplex(objective, constraints, sense):
1733
+ T, n, m, original_c, obj_mult, norm = build_canonical_tableau(objective, constraints, sense)
1734
+ basis = [n + i for i in range(m)]
1735
+ path = [snapshot(T, basis, n, m)]
1736
+ for _ in range(500):
1737
+ entering = next((j for j in range(n + m) if T[m][j] < -EPS), None)
1738
+ if entering is None:
1739
+ break
1740
+ best = math.inf
1741
+ leaving = None
1742
+ for i in range(m):
1743
+ a = T[i][entering]
1744
+ if a > EPS:
1745
+ r = T[i][n + m] / a
1746
+ if r < best:
1747
+ best = r
1748
+ leaving = i
1749
+ if leaving is None:
1750
+ return {"status": "unbounded", "path": path}
1751
+ pivot(T, leaving, entering)
1752
+ basis[leaving] = entering
1753
+ path.append(snapshot(T, basis, n, m))
1754
+ x, obj = extract_solution_from_tableau(T, basis, n, m, original_c)
1755
+ reduced = [float(f"{(original_c[j] + T[m][j]):.6f}") for j in range(n)]
1756
+ shadow = [float(f"{(-T[m][n + i]):.6f}") for i in range(m)]
1757
+ return {
1758
+ "status": "optimal",
1759
+ "x": x,
1760
+ "obj": obj,
1761
+ "path": path,
1762
+ "reduced_costs": reduced,
1763
+ "shadow_prices": shadow
1764
+ }
1765
+ def dual_simplex(objective, constraints, sense):
1766
+ # usa mesma implementação — ok
1767
+ return primal_simplex(objective, constraints, sense)
1768
+ # --------------------------- Gradio App UI ---------------------------
1769
+ def run_algorithms(nvars_str, objective_str, cons_str, sense):
1770
+ try:
1771
+ nvars = int(nvars_str)
1772
+ objective = parse_coeffs(objective_str)
1773
+ constraints = parse_constraints(cons_str, nvars)
1774
+ if len(objective) != nvars:
1775
+ return "Erro: objetivo não bate com nvars", "", ""
1776
+ except Exception as e:
1777
+ return f"Erro ao ler entrada: {e}", "", ""
1778
+ primal = primal_simplex(objective, constraints, sense)
1779
+ dual = dual_simplex(objective, constraints, sense)
1780
+ def format_res(res):
1781
+ if res["status"] != "optimal":
1782
+ return f"Status: {res['status']}"
1783
+ out = []
1784
+ out.append(f"Solução x* = {res['x']}")
1785
+ out.append(f"Valor objetivo = {res['obj']}")
1786
+ out.append(f"Preços-sombra = {res['shadow_prices']}")
1787
+ out.append(f"Custos reduzidos = {res['reduced_costs']}")
1788
+ out.append(f"\n--- Path ({len(res['path'])}) ---")
1789
+ for k, step in enumerate(res["path"]):
1790
+ out.append(f"\n### Passo {k+1}")
1791
+ out.append(f"Base = {step['basis']}")
1792
+ out.append(f"x = {step['x']}")
1793
+ out.append("Tableau:")
1794
+ for row in step["tableau"]:
1795
+ out.append(" " + " ".join(f"{v:8.3f}" for v in row))
1796
+ return "\n".join(out)
1797
+ model_txt = "Modelo:\nObjetivo: " + str(objective) + "\nRestrições:\n"
1798
+ for c in constraints:
1799
+ model_txt += f"{c['coeffs']} {c['sense']} {c['rhs']}\n"
1800
+ return model_txt, format_res(primal), format_res(dual)
1801
+ def demo_input():
1802
+ return "2", "60,30", "2x1+3x2<=300\n6/5x1+3/2x2=200\n-x1+4x2>=0", "max"
1803
+ with gr.Blocks() as demo:
1804
+ gr.Markdown("# Simplex Primal & Dual — Educational App")
1805
+ with gr.Row():
1806
+ with gr.Column(scale=1):
1807
+ nvars = gr.Textbox(label="Número de variáveis", value="2")
1808
+ objective = gr.Textbox(label="Função objetivo", value="60,30")
1809
+ cons = gr.Textbox(label="Restrições", lines=6,
1810
+ value="2x1+3x2<=300\n6/5x1+3/2x2=200\n-x1+4x2>=0")
1811
+ sense = gr.Radio(["max","min"], value="max", label="Objetivo")
1812
+ run = gr.Button("Executar")
1813
+ with gr.Column(scale=1):
1814
+ model_out = gr.Textbox(label="Modelo", lines=8)
1815
+ primal_out = gr.Textbox(label="Primal", lines=20)
1816
+ dual_out = gr.Textbox(label="Dual", lines=20)
1817
+ run.click(run_algorithms,
1818
+ inputs=[nvars, objective, cons, sense],
1819
+ outputs=[model_out, primal_out, dual_out])
1820
+ if __name__ == "__main__":
1821
+ demo.launch()"""