Skip to content

Instantly share code, notes, and snippets.

@apple-phi
Created June 18, 2024 16:32
Show Gist options
  • Save apple-phi/f974c6ba72b6585746d6dd5ea79da2e3 to your computer and use it in GitHub Desktop.
Save apple-phi/f974c6ba72b6585746d6dd5ea79da2e3 to your computer and use it in GitHub Desktop.
Part II module selection heuristic
[Area.Mechanical]
min = 4
required = [{core = 4}]
core = """4A2 Computational Fluid Dynamics
4A3 Turbomachinery I
4A7 Aircraft Aerodynamics and Design
4A9 Molecular Thermodynamics
4A10 Flow Instability
4A12 Turbulence and Vortex Dynamics
4A13 Combustion and Engines
4B5 Quantum and Nano-technologies
4B13 Electronic Sensors and Instrumentation
4B19 Renewable Electrical Power
4C2 Designing with Composites
4C3 Advanced Functional Materials and Devices
4C4 Design Methods
4C5 Design Case Studies
4C6 Advanced Linear Vibrations
4C7 Random and Non-linear Vibrations
4C8 Vehicle Dynamics
4C9 Continuum Mechanics
4C11 Data-driven and Learning Based Methods in Mechanics and Materials
4D6 Dynamics in Civil Engineering
4D2 Advanced Structural Design
4F1 Control System Design
4G1 Mathematical Biology of the Cell
4G5 Materials and Molecules: Modelling, Simulation and Machine Learning
4G6 Cellular and Molecular Biomechanics
4I10 Nuclear Reactor Engineering
4I11 Advanced Fission and Fusion Systems
4I14 Biosensors and Bioelectronics
4M12 Partial Differential Equations and Variational Methods
4M16 Nuclear Power Engineering
4M17 Practical Optimization
4M19 Advanced Building Physics
4M22 Climate Change Mitigation
4M23 Electricity and Environment (TPE22)
4M24 Computational Statistics and Machine Learning"""
[Area.Energy]
min = 4
required = [{core = 4}]
core = """4A2 Computational Fluid Dynamics
4A3 Turbomachinery
4A9 Molecular Thermodynamics
4A13 Combustion and Engines
4B19 Renewable Electric Power
4D13 Architectural Engineering
4I10 Nuclear Reactor Engineering
4I11 Advanced Fission and Fusion Systems
4M16 Nuclear Power Engineering
4M22 Climate Change Mitigation
4M23 Electricity and Environment"""
[Area.Aero]
min = 4
required = [{core = 4}, {core=3, companion = 2}]
core = """4A2 Computational Fluid Dynamics
4A3 Turbomachinery I
4A4 Aircraft Stability and Control
4A7 Aircraft Aerodynamics and Design
4A9 Molecular Thermodynamics
4A10 Flow Instability
4A12 Turbulence and Vortex Dynamics
4A13 Combustion and Engines
4A15 Acoustics"""
companion = """4B13 Electronic Sensors and Instrumentation
4B23 Optical Fibre Communication
4B24 Radio frequency Systems
4C2 Designing with Composites
4C4 Design Methods
4C5 Design Case Studies
4C6 Advanced Linear Vibrations
4C7 Random and Non-linear Vibrations
4C9 Continuum Mechanics
4F1 Control System Design
4F2 Robust and Non-linear Control
4F3 An Optimisation Based Approve to Control
4M24 Computational Statistics and Machine Learning"""
[Area.Civil]
min = 4
required = [{core = 4}]
core = """4C11 Data-driven and Learning Based Methods in Mechanics and Materials
4D2 Advanced Structural Design
4D4 Construction Engineering
4D5 Foundation Engineering
4D6 Dynamics in Civil Engineering
4D7 Concrete and Prestressed Concrete
4D9 Offshore Geotechnical Engineering
4D10 Structural Steelwork
4D13 Architectural Engineering
4D16 Construction Management
4M19 Advanced Building Physics
4M22 Climate Change Mitigation
4M24 Computational Statistics and Machine Learning"""
[Area.EEE]
min = 4
required = [{core = 4}]
core = """4B2 Power Micro Electronics
4B5 Quantum and Nano-technologies
4B11 Photonic Systems
4B13 Electronic Sensors and Instrumentation
4B19 Renewable Electrical Power
4B23 Optical Fibre Communication
4B24 Radio Frequency Systems
4B25 Embedded Systems for the Internet of Things
4B27 Internet of Everything
4C3 Advanced Functional Materials and Devices
4F5 Advanced Information Theory and Coding
4I14 Biosensors and Bioelectronics"""
[Area.ICE]
min = 4
required = [{core = 4}]
core = """4B23 Optical Fibre Communication
4B25 Embedded Systems for the Internet of Things
4C11 Data-driven and Learning Based Methods in Mechanics and Materials
4F1 Control System Design
4F2 Robust and Non-linear Control
4F3 An Optimisation Based Approach to Control
4F5 Advanced Information Theory and Coding
4F8 Image Processing and Image Coding
4F10 Deep Learning and Structured data
4F12 Computer Vision
4F13 Probabilistic Machine Learning
4F14 Computer Systems
4G10 Brain Machine Interfaces
4M17 Practical Optimization
4M21 Software Engineering and Design
4M24 Computational Statistics and Machine Learning
4M26 Algorithms and Data Structures"""
[Area.EIS]
min = 6
required = [{core = 6}]
core = """4B2 Power micro electronics
4B5 Quantum and Nano-technologies
4B11 Photonic systems
4B13 Electronic sensors and instrumentation
4B19 Renewable electrical power
4B23 Optical Fibre Communication
4B24 Radio Frequency Systems
4B25 Embedded Systems for the Internet of Things
4B27 Internet of Everything
4C3 Advanced Functional Materials and Devices
4F1 Control system design
4F2 Robust and non-linear control
4F3 An Optimisation Based Approve to Control
4F5 Advanced Information Theory and Coding
4F8 Image processing and image coding
4F10 Deep Learning and Structured data
4F12 Computer vision
4F13 Probabilistic Machine learning
4F14 Computer systems
4G10 Brain Machine Interfaces
4M12 Partial differential equations and variational methods
4M17 Practical optimization
4M21 Software Engineering and Design
4M26 Algorithms and data structures"""
[Area.Control]
min = 4
required = [{core = 4}]
core = """4A4 Aircraft stability and control
4B11 Photonic systems
4B13 Electronic sensors and instrumentation
4B24 Radio Frequency Systems
4B25 Embedded Systems for the Internet of Things
4B27 Internet of Everything
4C6 Advanced linear vibrations
4C7 Random and non-linear vibrations
4F1 Control system design
4F2 Robust and non-linear control
4F3 An Optimisation Based Approve to Control
4F5 Advanced Information Theory and Coding
4F8 Image processing and image coding
4F10 Deep Learning and Structured data
4F12 Computer vision
4F13 Probabilistic Machine learning
4G10 Brain Machine Interfaces
4M21 Software Engineering and Design"""
[Area.Bio]
min = 4
required = [{core = 2}]
core = """4G1 Mathematical Biology of the Cell
4G3 Computational Neuroscience
4G5 Materials and Molecules: Modelling, Simulation and Machine Learning
4G6 Cellular and Molecular Biomechanics
4G7 Control and Molecular Biomechanics
4G9 Biomedical Engineering
4G10 Brain Machine Interfaces
4I14 Biosensors and Bioelectronics"""
companion = """4B13 Electronic Sensors and Instrumentation
4C4 Design Methods
4C5 Design Case Studies
4C9 Continuum Mechanics
4F8 Image Processing and Image Coding
4F12 Computer Vision
4F13 Probabilistic Machine Learning
4I8 Medical Physics"""
[Modules]
4A2 = {assumed = ["3A1", "3A3"], useful = []}
4A3 = {assumed = ["3A1", "3A3"], useful = []}
4A4 = {assumed = [], useful = []}
4A7 = {assumed = ["3A1", "3A3"], useful = []}
4A9 = {assumed = [], useful = ["3A1", "3A5"]}
4A10 = {assumed = ["3A1"], useful = []}
4A12 = {assumed = ["3A1"], useful = ["3A3"]}
4A13 = {assumed = [], useful = ["3A5", "3A6"]}
4A15 = {assumed = [], useful = []}
4B2 = {assumed = [], useful = ["3B3", "3B5"]}
4B5 = {assumed = ["3B5"], useful = []}
4B11 = {assumed = [], useful = ["3B6"]}
4B13 = {assumed = ["3B1"], useful = []}
4B19 = {assumed = ["3B3", "3B4", "3B6"], useful = []}
4B23 = {assumed = [], useful = ["3F4", "3B6"]}
4B24 = {assumed = ["3B1"], useful = []}
4B25 = {assumed = [], useful = ["3B2"]}
4B27 = {assumed = [], useful = []}
4C2 = {assumed = [], useful = []}
4C3 = {assumed = [], useful = ["3B5"]}
4C4 = {assumed = [], useful = []}
4C5 = {assumed = [], useful = ["4C4"]}
4C6 = {assumed = ["3C6"], useful = []}
4C7 = {assumed = [], useful = ["3C6"]}
4C8 = {assumed = [], useful = ["3C5", "3C6"]}
4C9 = {assumed = ["3C7"], useful = ["3D7"]}
4C11 = {assumed = ["3C7"], useful = ["3D7"]}
4D2 = {assumed = ["3D3", "3D4"], useful = []}
4D4 = {assumed = [], useful = ["3D1", "3D2", "4D16"]}
4D5 = {assumed = ["3D2"], useful = []}
4D6 = {assumed = [], useful = ["3D2", "3D4", "3D7"]}
4D7 = {assumed = ["2P8", "3D3"], useful = []}
4D9 = {assumed = ["3D2"], useful = []}
4D10 = {assumed = ["3D4"], useful = ["3D3"]}
4D13 = {assumed = [], useful = ["3D3", "3D4", "3D8"]}
4D16 = {assumed = [], useful = []}
4E1 = {assumed = [], useful = []}
4E3 = {assumed = [], useful = []}
4E5 = {assumed = [], useful = []}
4E6 = {assumed = [], useful = []}
4E11 = {assumed = [], useful = []}
4E12 = {assumed = [], useful = []}
4F1 = {assumed = [], useful = ["3F1", "3F2"]}
4F2 = {assumed = ["3F2"], useful = []}
4F3 = {assumed = [], useful = ["3F1", "3F2"]}
4F5 = {assumed = ["3F7"], useful = ["3F1", "3F4"]}
4F8 = {assumed = ["3F1"], useful = ["3F3", "3F7"]}
4F10 = {assumed = [], useful = ["3F1", "3F3", "3F8"]}
4F12 = {assumed = [], useful = []}
4F13 = {assumed = [], useful = ["3F3"]}
4F14 = {assumed = [], useful = []} # Assumes Part I Digital circuits and computing
4G1 = {assumed = [], useful = []}
4G3 = {assumed = [], useful = ["3G2", "3G3"]}
4G5 = {assumed = [], useful = []}
4G6 = {assumed = [], useful = ["3C7"]}
4G7 = {assumed = [], useful = ["3G1", "3G2", "3G3", "3F0"]}
4G9 = {assumed = [], useful = []}
4G10 = {assumed = [], useful = ["3M1", "3G3", "3F2", "3F8"]}
4I1 = {assumed = [], useful = []}
4I8 = {assumed = [], useful = ["3G4"]}
4I10 = {assumed = ["4M16"], useful = []}
4I11 = {assumed = ["4M16"], useful = []}
4I14 = {assumed = [], useful = ["3G3"]}
4M1 = {assumed = [], useful = []}
4M3 = {assumed = [], useful = []}
4M12 = {assumed = [], useful = []}
4M16 = {assumed = [], useful = []}
4M17 = {assumed = ["3M1"], useful = []}
4M19 = {assumed = ["3D8"], useful = []}
4M21 = {assumed = [], useful = []}
4M22 = {assumed = [], useful = []}
4M23 = {assumed = [], useful = []}
4M24 = {assumed = ["3F3", "3F8", "3M1"], useful = []}
4M26 = {assumed = [], useful = []}
import tomlkit as tk
import pulp
with open("data.toml") as f:
data = tk.load(f)
# Define the problem
prob = pulp.LpProblem("Maximize_Specializations", pulp.LpMaximize)
# Extract modules and specializations
modules = set()
specializations = {}
for area, details in data["Area"].items():
core_modules = details["core"].split("\n")
companion_modules = (
details.get("companion", "").split("\n") if "companion" in details else []
)
modules.update(core_modules)
modules.update(companion_modules)
specializations[area] = {
"min": details["min"],
"required": details["required"],
"core": core_modules,
"companion": companion_modules,
}
# Variables
x = pulp.LpVariable.dicts("Module", modules, 0, 1, pulp.LpBinary)
y = pulp.LpVariable.dicts("Specialization", specializations.keys(), 0, 1, pulp.LpBinary)
# Variables for 3rd year modules
prev_modules = set()
for mod in modules:
prev_modules.update(data["Modules"][mod.split(" ")[0]]["assumed"])
y_prev = pulp.LpVariable.dicts("PrevModule", prev_modules, 0, 1, pulp.LpBinary)
# Objective function
prob += (
pulp.lpSum([y[spec] for spec in specializations]),
"Maximize the number of specializations",
)
# Constraints
for spec, details in specializations.items():
min_modules = details["min"]
core_modules = details["core"]
companion_modules = details["companion"]
# Minimum total modules constraint
prob += (
pulp.lpSum([x[mod] for mod in core_modules + companion_modules])
>= min_modules * y[spec],
f"MinModules_{spec}",
)
# Additional required constraints
for req in details["required"]:
core_req = req.get("core", 0)
companion_req = req.get("companion", 0)
if core_req > 0:
prob += (
pulp.lpSum([x[mod] for mod in core_modules]) >= core_req * y[spec],
f"CoreReq_{spec}_{core_req}",
)
if companion_req > 0:
prob += (
pulp.lpSum([x[mod] for mod in companion_modules])
>= companion_req * y[spec],
f"CompanionReq_{spec}_{companion_req}",
)
# Add the constraint to limit the total number of modules chosen to 8
prob += pulp.lpSum([x[mod] for mod in modules]) <= 8, "MaxModules"
# Add constraints for assumed modules from the previous year
for mod in modules:
for assumed_mod in data["Modules"][mod.split(" ")[0]]["assumed"]:
prob += y_prev[assumed_mod] >= x[mod], f"Assumed_{mod}_{assumed_mod}"
# Add the constraint to select exactly 9 modules from the previous year
prob += pulp.lpSum([y_prev[mod] for mod in prev_modules]) == 9, "PrevModules"
# Solve the problem
prob.solve()
# Output the results
print("Status:", pulp.LpStatus[prob.status])
for v in prob.variables():
print(v.name, "=", v.varValue)
# Print the selected modules and specializations
selected_modules = [mod for mod in modules if x[mod].varValue == 1]
qualified_specializations = [spec for spec in specializations if y[spec].varValue == 1]
selected_prev_modules = [mod for mod in prev_modules if y_prev[mod].varValue == 1]
print("Selected Modules:", selected_modules)
print("Qualified Specializations:", qualified_specializations)
print("Selected Previous Year Modules:", selected_prev_modules)
# Print how each specialization's requirements are met
for spec in qualified_specializations:
print(f"Area.{spec}")
details = specializations[spec]
min_modules = details["min"]
core_modules = details["core"]
companion_modules = details["companion"]
# Check minimum total modules requirement
selected_modules_count = sum(
x[mod].varValue for mod in core_modules + companion_modules
)
print(
f" Minimum total modules ({min_modules}): {selected_modules_count} modules selected"
)
# Check additional requirements
for req in details["required"]:
core_req = req.get("core", 0)
companion_req = req.get("companion", 0)
if core_req > 0:
selected_core_modules = sum(x[mod].varValue for mod in core_modules)
print(
f" Core modules requirement ({core_req}): {selected_core_modules} core modules selected"
)
if companion_req > 0:
selected_companion_modules = sum(
x[mod].varValue for mod in companion_modules
)
print(
f" Companion modules requirement ({companion_req}): {selected_companion_modules} companion modules selected"
)
for mod in core_modules + companion_modules:
if x[mod].varValue == 1:
prerequisites = data["Modules"][mod.split(" ")[0]]["assumed"]
print(f" - {mod}" + (f" {prerequisites}" if prerequisites else ""))
import matplotlib.pyplot as plt
import numpy as np
modules = list(data["Modules"].keys())
prev_modules = list(sorted(prev_modules))
# Initialize the matrix for the table
matrix = np.zeros((len(modules), len(prev_modules)))
# Populate the matrix based on the relationships
for i, (mod_4, details_4) in enumerate(data["Modules"].items()):
for j, mod_3 in enumerate(prev_modules):
if mod_3 in details_4["assumed"]:
matrix[i, j] = 2 # assumed relationship
if mod_3 in details_4["useful"]:
matrix[i, j] = 1 # useful relationship
# Create the plot
fig = plt.figure(1)
ax = plt.subplot()
# Define the colors for the matrix
cmap = plt.cm.get_cmap("coolwarm", 3)
cax = ax.matshow(matrix.T, cmap=cmap)
ax = cax.axes
# Set the axis labels
ax.set_yticks(np.arange(len(prev_modules)))
ax.set_xticks(np.arange(len(modules)))
ax.set_yticklabels(prev_modules)
ax.set_xticklabels([m.split(" ")[0] for m in modules], rotation=90)
# Add a colorbar
# cbar = fig.colorbar(cax, ticks=[0, 1, 2])
# cbar.ax.set_yticklabels(["No relation", "Assumed", "Useful"], rotation=90)
# Display the plot
# plt.subplots_adjust(left=0.2, right=0.8, top=0.8, bottom=0.2)
# plt.tight_layout()
plt.grid(True, linewidth=0.2)
plt.show()
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment