Spaces:
Sleeping
Sleeping
Update app_1.py
Browse files
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()"""
|