Systems_of_Equations / src /streamlit_app.py
NavyDevilDoc's picture
Update src/streamlit_app.py
03f144d verified
import streamlit as st
import numpy as np
import matplotlib.pyplot as plt
import plotly.graph_objects as go
import plotly.express as px
from plotly.subplots import make_subplots
import pandas as pd
from sys_of_eqn_solver import SystemSolver
import random
# Page configuration
st.set_page_config(
page_title="Systems of Equations - Algebra II",
page_icon="πŸ“Š",
layout="wide",
initial_sidebar_state="expanded"
)
# Initialize session state
if 'solver' not in st.session_state:
st.session_state.solver = SystemSolver()
if 'show_steps' not in st.session_state:
st.session_state.show_steps = True
# Header
st.title("πŸ“Š Systems of Linear Equations - Algebra II Tutorial")
st.markdown("*Learn to solve systems of equations using multiple methods with real-time visualization*")
# Sidebar configuration
with st.sidebar:
st.header("βš™οΈ Configuration")
# System size selection
system_size = st.selectbox(
"Select System Size:",
["2x2 System", "3x3 System"],
help="Choose between 2 equations with 2 variables or 3 equations with 3 variables"
)
# Method selection
if system_size == "2x2 System":
available_methods = ["All Methods", "Graphical", "Substitution", "Elimination", "Matrix"]
else:
available_methods = ["All Methods", "Matrix", "Elimination"]
selected_method = st.selectbox("Solution Method:", available_methods)
# Display options
st.subheader("Display Options")
show_steps = st.checkbox("Show detailed steps", value=st.session_state.show_steps)
show_verification = st.checkbox("Show solution verification", value=True)
if system_size == "2x2 System":
show_graph = st.checkbox("Show graphical solution", value=True)
graph_range = st.slider("Graph range", min_value=5, max_value=20, value=10)
# Quick examples
st.subheader("πŸ“š Quick Examples")
if st.button("🎯 Unique Solution"):
if system_size == "2x2 System":
st.session_state.example_coeffs = [[2, 1], [1, -1]]
st.session_state.example_constants = [7, 1]
else:
st.session_state.example_coeffs = [[1, 2, -1], [2, 1, 1], [1, -1, 2]]
st.session_state.example_constants = [3, 7, 4]
if st.button("πŸ”„ Infinite Solutions"):
if system_size == "2x2 System":
st.session_state.example_coeffs = [[2, 4], [1, 2]]
st.session_state.example_constants = [6, 3]
else:
st.session_state.example_coeffs = [[1, 2, 3], [2, 4, 6], [1, 2, 3]]
st.session_state.example_constants = [6, 12, 6]
if st.button("❌ No Solution"):
if system_size == "2x2 System":
st.session_state.example_coeffs = [[2, 4], [1, 2]]
st.session_state.example_constants = [6, 4]
else:
st.session_state.example_coeffs = [[1, 2, 3], [2, 4, 6], [1, 2, 3]]
st.session_state.example_constants = [6, 12, 7]
if st.button("🎲 Random System"):
if system_size == "2x2 System":
st.session_state.example_coeffs = [[random.randint(1, 5), random.randint(1, 5)],
[random.randint(1, 5), random.randint(1, 5)]]
st.session_state.example_constants = [random.randint(1, 15), random.randint(1, 15)]
else:
st.session_state.example_coeffs = [[random.randint(1, 4), random.randint(1, 4), random.randint(1, 4)],
[random.randint(1, 4), random.randint(1, 4), random.randint(1, 4)],
[random.randint(1, 4), random.randint(1, 4), random.randint(1, 4)]]
st.session_state.example_constants = [random.randint(1, 12), random.randint(1, 12), random.randint(1, 12)]
# Main content area
if system_size == "2x2 System":
st.header("2Γ—2 System of Linear Equations")
# Input section
col1, col2 = st.columns(2)
with col1:
st.subheader("πŸ“ Enter Your System")
# Use example values if they exist
if 'example_coeffs' in st.session_state and len(st.session_state.example_coeffs) == 2:
default_coeffs = st.session_state.example_coeffs
default_constants = st.session_state.example_constants
else:
default_coeffs = [[2, 1], [1, -1]]
default_constants = [7, 1]
# Equation 1
st.markdown("**Equation 1:** `a₁x + b₁y = c₁`")
eq1_col1, eq1_col2, eq1_col3 = st.columns(3)
with eq1_col1:
a1 = st.number_input("a₁", value=float(default_coeffs[0][0]), step=0.1, key="a1")
with eq1_col2:
b1 = st.number_input("b₁", value=float(default_coeffs[0][1]), step=0.1, key="b1")
with eq1_col3:
c1 = st.number_input("c₁", value=float(default_constants[0]), step=0.1, key="c1")
# Equation 2
st.markdown("**Equation 2:** `aβ‚‚x + bβ‚‚y = cβ‚‚`")
eq2_col1, eq2_col2, eq2_col3 = st.columns(3)
with eq2_col1:
a2 = st.number_input("aβ‚‚", value=float(default_coeffs[1][0]), step=0.1, key="a2")
with eq2_col2:
b2 = st.number_input("bβ‚‚", value=float(default_coeffs[1][1]), step=0.1, key="b2")
with eq2_col3:
c2 = st.number_input("cβ‚‚", value=float(default_constants[1]), step=0.1, key="c2")
# Display the system
st.markdown("### Your System:")
if a1 >= 0 and b1 >= 0:
eq1_str = f"{a1}x + {b1}y = {c1}"
elif a1 >= 0 and b1 < 0:
eq1_str = f"{a1}x - {abs(b1)}y = {c1}"
elif a1 < 0 and b1 >= 0:
eq1_str = f"-{abs(a1)}x + {b1}y = {c1}"
else:
eq1_str = f"-{abs(a1)}x - {abs(b1)}y = {c1}"
if a2 >= 0 and b2 >= 0:
eq2_str = f"{a2}x + {b2}y = {c2}"
elif a2 >= 0 and b2 < 0:
eq2_str = f"{a2}x - {abs(b2)}y = {c2}"
elif a2 < 0 and b2 >= 0:
eq2_str = f"-{abs(a2)}x + {b2}y = {c2}"
else:
eq2_str = f"-{abs(a2)}x - {abs(b2)}y = {c2}"
st.latex(eq1_str)
st.latex(eq2_str)
with col2:
# Solve the system
coefficients = [[a1, b1], [a2, b2]]
constants = [c1, c2]
method_map = {
"All Methods": "all",
"Graphical": "graphical",
"Substitution": "substitution",
"Elimination": "elimination",
"Matrix": "matrix"
}
result = st.session_state.solver.solve_2x2_system(
coefficients, constants, method_map[selected_method]
)
# System type indicator
system_type = result['system_type']
if system_type == "unique_solution":
st.success("βœ… **Unique Solution** (Consistent Independent)")
elif system_type == "infinite_solutions":
st.info("πŸ”„ **Infinite Solutions** (Consistent Dependent)")
else:
st.error("❌ **No Solution** (Inconsistent)")
# Display solutions based on selected method
if selected_method != "All Methods":
method_key = f"{method_map[selected_method]}_solution"
if method_key in result:
solution_data = result[method_key]
st.subheader(f"πŸ” {selected_method} Method")
if show_steps and 'steps' in solution_data:
with st.expander("Show Detailed Steps", expanded=True):
for i, step in enumerate(solution_data['steps']):
st.write(f"{i+1}. {step}")
if 'solution' in solution_data and solution_data['solution'] is not None:
if isinstance(solution_data['solution'], dict):
st.markdown("### 🎯 Solution:")
col1, col2 = st.columns(2)
with col1:
st.metric("x =", f"{solution_data['solution']['x']:.4f}")
with col2:
st.metric("y =", f"{solution_data['solution']['y']:.4f}")
# Graphical visualization
if show_graph and ('graphical_solution' in result or selected_method == "All Methods"):
st.header("πŸ“ˆ Graphical Solution")
fig = go.Figure()
# Generate x values for plotting
x_vals = np.linspace(-graph_range, graph_range, 400)
# Plot first line
if b1 != 0:
y1_vals = (c1 - a1 * x_vals) / b1
fig.add_trace(go.Scatter(
x=x_vals, y=y1_vals,
mode='lines',
name=eq1_str,
line=dict(color='blue', width=3)
))
else:
# Vertical line
x_vert = c1 / a1 if a1 != 0 else 0
fig.add_vline(x=x_vert, line_dash="solid", line_color="blue",
annotation_text=f"x = {x_vert:.2f}")
# Plot second line
if b2 != 0:
y2_vals = (c2 - a2 * x_vals) / b2
fig.add_trace(go.Scatter(
x=x_vals, y=y2_vals,
mode='lines',
name=eq2_str,
line=dict(color='red', width=3)
))
else:
# Vertical line
x_vert = c2 / a2 if a2 != 0 else 0
fig.add_vline(x=x_vert, line_dash="solid", line_color="red",
annotation_text=f"x = {x_vert:.2f}")
# Plot intersection point
if 'graphical_solution' in result and result['graphical_solution']['intersection']:
intersection = result['graphical_solution']['intersection']
fig.add_trace(go.Scatter(
x=[intersection['x']], y=[intersection['y']],
mode='markers',
name=f"Solution: ({intersection['x']:.3f}, {intersection['y']:.3f})",
marker=dict(color='green', size=12, symbol='circle')
))
fig.update_layout(
title="Graphical Solution of System",
xaxis_title="x",
yaxis_title="y",
xaxis=dict(range=[-graph_range, graph_range], gridcolor='lightgray'),
yaxis=dict(range=[-graph_range, graph_range], gridcolor='lightgray'),
plot_bgcolor='white',
showlegend=True
)
st.plotly_chart(fig, use_container_width=True)
else: # 3x3 System
st.header("3Γ—3 System of Linear Equations")
# Input section for 3x3 system
col1, col2 = st.columns([1, 1])
with col1:
st.subheader("πŸ“ Enter Your 3Γ—3 System")
# Use example values if they exist
if 'example_coeffs' in st.session_state and len(st.session_state.example_coeffs) == 3:
default_coeffs = st.session_state.example_coeffs
default_constants = st.session_state.example_constants
else:
default_coeffs = [[1, 2, -1], [2, 1, 1], [1, -1, 2]]
default_constants = [3, 7, 4]
# Create input grid for 3x3 system
st.markdown("**System of equations:** `Ax = b`")
equations = []
coefficients = []
constants = []
for i in range(3):
st.markdown(f"**Equation {i+1}:** `a{i+1}₁x + a{i+1}β‚‚y + a{i+1}₃z = b{i+1}`")
cols = st.columns(4)
row_coeffs = []
with cols[0]:
val = st.number_input(f"a{i+1}₁", value=float(default_coeffs[i][0]), step=0.1, key=f"a{i+1}1")
row_coeffs.append(val)
with cols[1]:
val = st.number_input(f"a{i+1}β‚‚", value=float(default_coeffs[i][1]), step=0.1, key=f"a{i+1}2")
row_coeffs.append(val)
with cols[2]:
val = st.number_input(f"a{i+1}₃", value=float(default_coeffs[i][2]), step=0.1, key=f"a{i+1}3")
row_coeffs.append(val)
with cols[3]:
val = st.number_input(f"b{i+1}", value=float(default_constants[i]), step=0.1, key=f"b{i+1}")
constants.append(val)
coefficients.append(row_coeffs)
# Format equation string
eq_parts = []
for j, coeff in enumerate(row_coeffs):
var = ['x', 'y', 'z'][j]
if j == 0:
eq_parts.append(f"{coeff}{var}")
else:
if coeff >= 0:
eq_parts.append(f" + {coeff}{var}")
else:
eq_parts.append(f" - {abs(coeff)}{var}")
equations.append(''.join(eq_parts) + f" = {constants[i]}")
st.markdown("### Your System:")
for eq in equations:
st.latex(eq)
with col2:
# Solve 3x3 system
method_map = {"All Methods": "all", "Matrix": "matrix", "Elimination": "elimination"}
result = st.session_state.solver.solve_3x3_system(
coefficients, constants, method_map[selected_method]
)
# System type indicator
system_type = result['system_type']
if system_type == "unique_solution":
st.success("βœ… **Unique Solution** (Consistent Independent)")
elif system_type == "infinite_solutions":
st.info("πŸ”„ **Infinite Solutions** (Consistent Dependent)")
else:
st.error("❌ **No Solution** (Inconsistent)")
# Display solutions
if selected_method != "All Methods":
method_key = f"{method_map[selected_method]}_solution"
if method_key in result:
solution_data = result[method_key]
st.subheader(f"πŸ” {selected_method} Method")
if show_steps and 'steps' in solution_data:
with st.expander("Show Detailed Steps", expanded=True):
for i, step in enumerate(solution_data['steps']):
st.write(f"{i+1}. {step}")
if 'solution' in solution_data and solution_data['solution'] is not None:
if isinstance(solution_data['solution'], dict):
st.markdown("### 🎯 Solution:")
col1, col2, col3 = st.columns(3)
with col1:
st.metric("x =", f"{solution_data['solution']['x']:.4f}")
with col2:
st.metric("y =", f"{solution_data['solution']['y']:.4f}")
with col3:
st.metric("z =", f"{solution_data['solution']['z']:.4f}")
# Show all methods if selected
if selected_method == "All Methods":
st.header("πŸ”„ All Solution Methods")
methods_to_show = []
if system_size == "2x2 System":
methods_to_show = ['matrix_solution', 'elimination_solution', 'substitution_solution', 'graphical_solution']
else:
methods_to_show = ['matrix_solution', 'elimination_solution']
tabs = st.tabs([method.replace('_solution', '').title() for method in methods_to_show])
for i, method_key in enumerate(methods_to_show):
with tabs[i]:
if method_key in result:
solution_data = result[method_key]
if 'error' in solution_data:
st.error(f"Error: {solution_data['error']}")
else:
if show_steps and 'steps' in solution_data:
st.subheader("πŸ“‹ Steps:")
for j, step in enumerate(solution_data['steps']):
st.write(f"{j+1}. {step}")
if 'solution' in solution_data and solution_data['solution'] is not None:
if isinstance(solution_data['solution'], dict):
st.subheader("🎯 Solution:")
if system_size == "2x2 System":
col1, col2 = st.columns(2)
with col1:
st.metric("x =", f"{solution_data['solution']['x']:.4f}")
with col2:
st.metric("y =", f"{solution_data['solution']['y']:.4f}")
else:
col1, col2, col3 = st.columns(3)
with col1:
st.metric("x =", f"{solution_data['solution']['x']:.4f}")
with col2:
st.metric("y =", f"{solution_data['solution']['y']:.4f}")
with col3:
st.metric("z =", f"{solution_data['solution']['z']:.4f}")
# Solution verification
if show_verification and system_size == "2x2 System":
if 'matrix_solution' in result and result['matrix_solution']['solution']:
st.header("βœ… Solution Verification")
solution = result['matrix_solution']['solution']
x_val, y_val = solution['x'], solution['y']
# Check each equation
check1 = a1 * x_val + b1 * y_val
check2 = a2 * x_val + b2 * y_val
col1, col2 = st.columns(2)
with col1:
st.subheader("Equation 1 Check:")
st.write(f"{a1}({x_val:.4f}) + {b1}({y_val:.4f}) = {check1:.4f}")
if abs(check1 - c1) < 1e-6:
st.success(f"βœ… {check1:.4f} = {c1} βœ“")
else:
st.error(f"❌ {check1:.4f} β‰  {c1}")
with col2:
st.subheader("Equation 2 Check:")
st.write(f"{a2}({x_val:.4f}) + {b2}({y_val:.4f}) = {check2:.4f}")
if abs(check2 - c2) < 1e-6:
st.success(f"βœ… {check2:.4f} = {c2} βœ“")
else:
st.error(f"❌ {check2:.4f} β‰  {c2}")
# Educational notes
with st.expander("πŸ“š Educational Notes"):
if system_size == "2x2 System":
st.markdown("""
### 2Γ—2 Systems - Key Concepts:
**Types of Solutions:**
- **Unique Solution**: Lines intersect at exactly one point (det β‰  0)
- **Infinite Solutions**: Lines are identical (same slope, same y-intercept)
- **No Solution**: Lines are parallel (same slope, different y-intercepts)
**Solution Methods:**
1. **Graphical**: Plot both lines and find intersection point
2. **Substitution**: Solve one equation for a variable, substitute into the other
3. **Elimination**: Add/subtract equations to eliminate a variable
4. **Matrix/Cramer's Rule**: Use determinants to find solution
**When to Use Each Method:**
- **Graphical**: Good for visualization and understanding
- **Substitution**: Best when one variable has coefficient 1 or -1
- **Elimination**: Good when coefficients are easy to work with
- **Matrix**: Most systematic, especially for larger systems
""")
else:
st.markdown("""
### 3Γ—3 Systems - Key Concepts:
**Types of Solutions:**
- **Unique Solution**: System has exactly one solution (det β‰  0)
- **Infinite Solutions**: rank(A) = rank([A|b]) < 3
- **No Solution**: rank(A) β‰  rank([A|b])
**Solution Methods:**
1. **Matrix Method**: Use matrix operations and determinants
2. **Gaussian Elimination**: Systematic row operations to solve
**Key Skills:**
- Forward elimination to create upper triangular matrix
- Back substitution to find solution
- Recognition of inconsistent and dependent systems
""")
# Footer
st.markdown("---")
st.markdown("*Built with Streamlit for Algebra II students β€’ Use the sidebar to explore different examples and methods*")