This notebook contains a prelmininary analyses of the curricula and degree plans associated with undergraduate chemical engineering programs around the country. In order to execute the analyses provided in this notebook, you need to load the following Julia packages:
using CurricularAnalytics, CurricularVisualization
#using CurricularOptimization # this package requires special access rights, if you commented out, you won't be able to run the optimzation-related functions
using Glob
using CSV
using DataFrames
using Statistics
The WebIO Jupyter extension was not detected. See the WebIO Jupyter integration documentation for more information.
The analyses in this notebook makes use of the Curricular Analytics toolbox built using the Julia programming language and available as open source software [1]. If you would like to modify any of these analyses, you may find it useful to read the toolbox documenation, as well as the curricular analytics paper listed in the References section below [2]. The curricula associated with chemcial engineering undergraduate programs at various univiersites were collected from the http://CurricularAnalytics.org website. These curricula were entered by those working at the various institutions that uploaded these curricula. We have not validated them in any way, i.e., we are using them "as is" according to how they were entered into the afforementioned web application. That said, it is realitvely straightforward to check these curricula by visiting the websites of the various universites offering these programs.
UA_ChemE_plan = read_csv("./programs/plans/ChemE-DP-UA.csv")
visualize(UA_ChemE_plan, notebook=true)
SystemError: opening file "./programs/plans/ChemE-DP-UA.csv": No such file or directory Stacktrace: [1] systemerror(p::String, errno::Int32; extrainfo::Nothing) @ Base ./error.jl:168 [2] #systemerror#62 @ ./error.jl:167 [inlined] [3] systemerror @ ./error.jl:167 [inlined] [4] open(fname::String; lock::Bool, read::Nothing, write::Nothing, create::Nothing, truncate::Nothing, append::Nothing) @ Base ./iostream.jl:293 [5] open @ ./iostream.jl:282 [inlined] [6] open(f::CurricularAnalytics.var"#23#24", args::String; kwargs::Base.Iterators.Pairs{Union{}, Union{}, Tuple{}, NamedTuple{(), Tuple{}}}) @ Base ./io.jl:328 [7] open @ ./io.jl:328 [inlined] [8] readfile @ ~/.julia/packages/CurricularAnalytics/CvTk4/src/CSVUtilities.jl:2 [inlined] [9] remove_empty_lines(file_path::String) @ CurricularAnalytics ~/.julia/packages/CurricularAnalytics/CvTk4/src/CSVUtilities.jl:14 [10] read_csv(file_path::String) @ CurricularAnalytics ~/.julia/packages/CurricularAnalytics/CvTk4/src/DataHandler.jl:25 [11] top-level scope @ In[2]:1 [12] eval @ ./boot.jl:360 [inlined] [13] include_string(mapexpr::typeof(REPL.softscope), mod::Module, code::String, filename::String) @ Base ./loading.jl:1094
metrics = basic_metrics(UA_ChemE_plan)
println(String(take!(metrics)))
UndefVarError: UA_ChemE_plan not defined Stacktrace: [1] top-level scope @ In[3]:1 [2] eval @ ./boot.jl:360 [inlined] [3] include_string(mapexpr::typeof(REPL.softscope), mod::Module, code::String, filename::String) @ Base ./loading.jl:1094
metrics = basic_metrics(UA_ChemE_plan.curriculum)
println(String(take!(metrics)))
University of Arizona Curriculum: Chemical Engineering credit hours = 128 number of courses = 45 Blocking Factor -- entire curriculum = 171 max. value = 24, for course(s): MATH 125 - Calculus I w/ Applications Centrality -- entire curriculum = 2196 max. value = 287, for course(s): CHEE 201 - Elements of Chem and Envirn Eng I Delay Factor -- entire curriculum = 215.0 max. value = 8.0, for course(s): MATH 125 - Calculus I w/ Applications, CHEM 151 - Gen Chemistry I, MATH 129 - Calculus II, CHEM 152 - Gen Chemistry II, PHYS 141 - Intro Mechanics, CHEE 201 - Elements of Chem and Envirn Eng I, CHEE 203 - Chem Eng Heat Xfer & Fluid Flow, PHYS 241 - Electricity & Magnetism, CHEE 303 - Chem Eng Mass Xfer, CHEE 402 - Chem Eng Modeling, CHEM 480A - Physical Chem, CHEE 305 - Chem Eng Transport Phenom, CHEE 326 - Chem & Phys Equilibrium, CHEE 301B - Chem Eng Lab II, CHEE 420 - Chem Reaction Eng, CHEE 442 - Chem Eng Design Principles, CHEE 401B - Process Dynamics and Control Lab Complexity -- entire curriculum = 386.0 max. value = 32.0, for course(s): MATH 125 - Calculus I w/ Applications Longest Path(s) -- length = 8, number of paths = 4 path(s): path 1 = MATH 125 - Calculus I w/ Applications -> MATH 129 - Calculus II -> CHEE 201 - Elements of Chem and Envirn Eng I -> CHEE 203 - Chem Eng Heat Xfer & Fluid Flow -> CHEE 303 - Chem Eng Mass Xfer -> CHEE 402 - Chem Eng Modeling -> CHEE 305 - Chem Eng Transport Phenom -> CHEE 301B - Chem Eng Lab II path 2 = CHEM 151 - Gen Chemistry I -> CHEM 152 - Gen Chemistry II -> CHEE 201 - Elements of Chem and Envirn Eng I -> CHEE 203 - Chem Eng Heat Xfer & Fluid Flow -> CHEE 303 - Chem Eng Mass Xfer -> CHEE 402 - Chem Eng Modeling -> CHEE 305 - Chem Eng Transport Phenom -> CHEE 301B - Chem Eng Lab II path 3 = MATH 125 - Calculus I w/ Applications -> MATH 129 - Calculus II -> PHYS 241 - Electricity & Magnetism -> CHEM 480A - Physical Chem -> CHEE 326 - Chem & Phys Equilibrium -> CHEE 420 - Chem Reaction Eng -> CHEE 442 - Chem Eng Design Principles -> CHEE 401B - Process Dynamics and Control Lab path 4 = MATH 125 - Calculus I w/ Applications -> PHYS 141 - Intro Mechanics -> PHYS 241 - Electricity & Magnetism -> CHEM 480A - Physical Chem -> CHEE 326 - Chem & Phys Equilibrium -> CHEE 420 - Chem Reaction Eng -> CHEE 442 - Chem Eng Design Principles -> CHEE 401B - Process Dynamics and Control Lab
Here is the complexity distrubtion of all undergraduate programs at the Unviersity of Arizona
df = DataFrame(CSV.File("./Complexity_x_Grad_UA.csv"));
histogram(df.complexity_score, nbins=50, xlabel="Program Complexity", ylabel="# of programs", label="")
ArgumentError: "./Complexity_x_Grad_UA.csv" is not a valid file Stacktrace: [1] CSV.Header(source::String, header::Int64, normalizenames::Bool, datarow::Int64, skipto::Nothing, footerskip::Int64, transpose::Bool, comment::Nothing, use_mmap::Nothing, ignoreemptylines::Bool, select::Nothing, drop::Nothing, missingstrings::Vector{String}, missingstring::String, delim::Nothing, ignorerepeated::Bool, quotechar::Char, openquotechar::Nothing, closequotechar::Nothing, escapechar::Char, dateformat::Nothing, dateformats::Nothing, decimal::UInt8, truestrings::Vector{String}, falsestrings::Vector{String}, type::Nothing, types::Nothing, typemap::Dict{Type, Type}, categorical::Nothing, pool::Float64, lazystrings::Bool, strict::Bool, silencewarnings::Bool, debug::Bool, parsingdebug::Bool, streaming::Bool) @ CSV ~/.julia/packages/CSV/UIgP3/src/header.jl:92 [2] CSV.File(source::String; header::Int64, normalizenames::Bool, datarow::Int64, skipto::Nothing, footerskip::Int64, transpose::Bool, comment::Nothing, use_mmap::Nothing, ignoreemptylines::Bool, select::Nothing, drop::Nothing, missingstrings::Vector{String}, missingstring::String, delim::Nothing, ignorerepeated::Bool, quotechar::Char, openquotechar::Nothing, closequotechar::Nothing, escapechar::Char, dateformat::Nothing, dateformats::Nothing, decimal::UInt8, truestrings::Vector{String}, falsestrings::Vector{String}, type::Nothing, types::Nothing, typemap::Dict{Type, Type}, categorical::Nothing, pool::Float64, lazystrings::Bool, strict::Bool, silencewarnings::Bool, debug::Bool, parsingdebug::Bool, kw::Base.Iterators.Pairs{Union{}, Union{}, Tuple{}, NamedTuple{(), Tuple{}}}) @ CSV ~/.julia/packages/CSV/UIgP3/src/file.jl:216 [3] CSV.File(source::String) @ CSV ~/.julia/packages/CSV/UIgP3/src/file.jl:216 [4] top-level scope @ In[65]:1 [5] eval @ ./boot.jl:360 [inlined] [6] include_string(mapexpr::typeof(REPL.softscope), mod::Module, code::String, filename::String) @ Base ./loading.jl:1094
= Array{Integer,1}() # curricular complexity score of program
Y = Array{Bool,1}() # did student graduate within 4 years?
Z = Array{Bool,1}() # did student graduate within 6 years?
for row in eachrow(df)
for t in 1:row["four"]
push!(X, row["complexity_score"])
push!(Y, 1); push!(Z, 1)
end
s = row["total_degrees_awarded"] - row["six"]
for t in 1:(row["total_degrees_awarded"] - row["four"])
push!(X, row["complexity_score"])
push!(Y, 0)
s > 0 ? (push!(Z, 1); s=s-1) : push!(Z, 0)
end
end
df_binary = DataFrame(Program_Complexity = X, grad4 = Y, grad6 = Z);
histogram(X, nbins=50, xlabel="Program Complexity", ylabel="# of students", label="")
probit4 = glm(@formula(grad4 ~ Program_Complexity), df_binary, Binomial(), ProbitLink())
probit6 = glm(@formula(grad6 ~ Program_Complexity), df_binary, Binomial(), ProbitLink())
CC_scores = DataFrame(Program_Complexity = 0:10:650)
pred4 = predict(probit4, CC_scores, interval = :confidence)
pred6 = predict(probit6, CC_scores, interval = :confidence)
plot(title="Graduates")
plot!(CC_scores.Program_Complexity, pred4.prediction , seriestype = :scatter, labels="4 years",
ribbon = (pred4.prediction .- pred4.lower, pred4.upper .- pred4.prediction))
plot!(CC_scores.Program_Complexity, pred6.prediction , seriestype = :scatter, labels="6 years",
ribbon = (pred6.prediction .- pred6.lower, pred6.upper .- pred6.prediction))
Below we read each of the stored curricula into an array of curricula that will be used throughout the remainder of this notebook.
currics = Array{Curriculum,1}()
program_files = glob("*", "./programs/curricula")
for program in program_files
curric = read_csv(program)
complexity(curric) # compute the curricular complexity of the curriculum
push!(currics, curric) # store the curriculum in the darray
end
The institutions represented in this chemical engineering curricula data set include:
for c in currics
println(c.institution)
end
American University of Beirut Bucknell University Cal Poly Pomona Drexel University Illinois Institute of Technology Louisiana State University Montana State University Oklahoma State University Rose-Hulman Institute of Technology University of Arizona University of Kentucky University of Nebraska-Lincoln University of Nevada-Reno University of South Carolina University of South Florida Virginia Tech Yale University
First we will analyze the structural properties of a curriculum in the college. The structural properties of a curriculum are determined by the underlying structural properties of its corresponding curriculum graph (i.e., the graph showing the prerequisite relationships between the courses in a curriculum, ignoring term information). Here's the degree plan for the Electrical Engineering program. By hovering your mouse over the courses in this figure, various metrics will be displayed.
metric = "complexity"
stats = basic_statistics(currics, "complexity")
println(String(take!(stats))); flush(stdout)
display(metric_histogram(currics, metric, title="Chemical Engineering Programs", xlabel="$(metric)",
ylabel="# of curricula", xlim=(0,900)))
Metric -- complexity Number of curricula = 17 Mean = 434.6588235294117 STD = 47.211699433543096 Max. = 720.0 Min. = 229.0
There are 120 (semester) credit hour programs at Stanford University, the University of New Mexico, the University of South Florida, and Yale University.
metrics = basic_metrics(AE_plan.curriculum)
println(String(take!(metrics)))
Georgia Institute of Technology Curriculum: Aerospace Engineering credit hours = 137 number of courses = 48 Blocking Factor -- entire curriculum = 209 max. value = 30, for course(s): MATH 1501 - Calculus I Centrality -- entire curriculum = 1731 max. value = 262, for course(s): MATH 1552 - Integral Calculus Delay Factor -- entire curriculum = 229.0 max. value = 7.0, for course(s): MATH 1501 - Calculus I, MATH 1552 - Integral Calculus, MATH 1553 - Intro to Linear Algebra, PHYS 2211 - Intro Physics 1, MATH 2551 - Multivariable Calculus, MATH 2552 - Differential Equations, AE 2010 - Termo and Fluid Fund., AE 2220 - Dynamics, AE 3030 - Aerodynamics, AE 3330 - AE Vehicle Performance, AE 3530 - Sys Dynamics & Vib, AE 3531 - Control Sys Analysis/Design, AE 4341/2/3 - Air/Space/Rotor Design, AE 4531 - Aircraft Flt Dynamics, AE 4532 - Spacecraft Flt Dynamics, AE 4610 - Dynamics & Controls Lab Complexity -- entire curriculum = 438.0 max. value = 37.0, for course(s): MATH 1501 - Calculus I Longest Path(s) -- length = 7, number of paths = 13 path(s): path 1 = MATH 1501 - Calculus I -> MATH 1552 - Integral Calculus -> PHYS 2211 - Intro Physics 1 -> AE 2010 - Termo and Fluid Fund. -> AE 3030 - Aerodynamics -> AE 3330 - AE Vehicle Performance -> AE 4341/2/3 - Air/Space/Rotor Design path 2 = MATH 1501 - Calculus I -> MATH 1552 - Integral Calculus -> MATH 2551 - Multivariable Calculus -> AE 2010 - Termo and Fluid Fund. -> AE 3030 - Aerodynamics -> AE 3330 - AE Vehicle Performance -> AE 4341/2/3 - Air/Space/Rotor Design path 3 = MATH 1501 - Calculus I -> MATH 1553 - Intro to Linear Algebra -> MATH 2551 - Multivariable Calculus -> AE 2010 - Termo and Fluid Fund. -> AE 3030 - Aerodynamics -> AE 3330 - AE Vehicle Performance -> AE 4341/2/3 - Air/Space/Rotor Design path 4 = MATH 1501 - Calculus I -> MATH 1552 - Integral Calculus -> PHYS 2211 - Intro Physics 1 -> AE 2010 - Termo and Fluid Fund. -> AE 3030 - Aerodynamics -> AE 3330 - AE Vehicle Performance -> AE 4531 - Aircraft Flt Dynamics path 5 = MATH 1501 - Calculus I -> MATH 1552 - Integral Calculus -> MATH 2551 - Multivariable Calculus -> AE 2010 - Termo and Fluid Fund. -> AE 3030 - Aerodynamics -> AE 3330 - AE Vehicle Performance -> AE 4531 - Aircraft Flt Dynamics path 6 = MATH 1501 - Calculus I -> MATH 1553 - Intro to Linear Algebra -> MATH 2551 - Multivariable Calculus -> AE 2010 - Termo and Fluid Fund. -> AE 3030 - Aerodynamics -> AE 3330 - AE Vehicle Performance -> AE 4531 - Aircraft Flt Dynamics path 7 = MATH 1501 - Calculus I -> MATH 1552 - Integral Calculus -> MATH 2552 - Differential Equations -> AE 2220 - Dynamics -> AE 3530 - Sys Dynamics & Vib -> AE 3531 - Control Sys Analysis/Design -> AE 4531 - Aircraft Flt Dynamics path 8 = MATH 1501 - Calculus I -> MATH 1553 - Intro to Linear Algebra -> MATH 2552 - Differential Equations -> AE 2220 - Dynamics -> AE 3530 - Sys Dynamics & Vib -> AE 3531 - Control Sys Analysis/Design -> AE 4531 - Aircraft Flt Dynamics path 9 = MATH 1501 - Calculus I -> MATH 1552 - Integral Calculus -> PHYS 2211 - Intro Physics 1 -> AE 2010 - Termo and Fluid Fund. -> AE 3030 - Aerodynamics -> AE 3330 - AE Vehicle Performance -> AE 4532 - Spacecraft Flt Dynamics path 10 = MATH 1501 - Calculus I -> MATH 1552 - Integral Calculus -> MATH 2551 - Multivariable Calculus -> AE 2010 - Termo and Fluid Fund. -> AE 3030 - Aerodynamics -> AE 3330 - AE Vehicle Performance -> AE 4532 - Spacecraft Flt Dynamics path 11 = MATH 1501 - Calculus I -> MATH 1553 - Intro to Linear Algebra -> MATH 2551 - Multivariable Calculus -> AE 2010 - Termo and Fluid Fund. -> AE 3030 - Aerodynamics -> AE 3330 - AE Vehicle Performance -> AE 4532 - Spacecraft Flt Dynamics path 12 = MATH 1501 - Calculus I -> MATH 1552 - Integral Calculus -> MATH 2552 - Differential Equations -> AE 2220 - Dynamics -> AE 3530 - Sys Dynamics & Vib -> AE 3531 - Control Sys Analysis/Design -> AE 4610 - Dynamics & Controls Lab path 13 = MATH 1501 - Calculus I -> MATH 1553 - Intro to Linear Algebra -> MATH 2552 - Differential Equations -> AE 2220 - Dynamics -> AE 3530 - Sys Dynamics & Vib -> AE 3531 - Control Sys Analysis/Design -> AE 4610 - Dynamics & Controls Lab
metrics = basic_metrics(EE_plan.curriculum)
println(String(take!(metrics)))
Georgia Institute of Technology Curriculum: Electrical Engineering - Electronic Devices and Circuit Technology credit hours = 129 number of courses = 44 Blocking Factor -- entire curriculum = 127 max. value = 19, for course(s): MATH 1551 - Differential Calculus Centrality -- entire curriculum = 792 max. value = 124, for course(s): ECE 2040 - Circuit Analysis Delay Factor -- entire curriculum = 185.0 max. value = 8.0, for course(s): MATH 1551 - Differential Calculus, MATH 1552 - Integral Calculus, PHYS 2211 - Intro Physics 1, PHYS 2212 - Intro. Physics 2, ECE 2040 - Circuit Analysis, ECE 3025 - Electromagnetics, Senior Design Sequence, Senior Design Sequence Complexity -- entire curriculum = 312.0 max. value = 27.0, for course(s): MATH 1551 - Differential Calculus Longest Path(s) -- length = 8, number of paths = 1 path(s): path 1 = MATH 1551 - Differential Calculus -> MATH 1552 - Integral Calculus -> PHYS 2211 - Intro Physics 1 -> PHYS 2212 - Intro. Physics 2 -> ECE 2040 - Circuit Analysis -> ECE 3025 - Electromagnetics -> Senior Design Sequence -> Senior Design Sequence
curricula = Array{Curriculum,1}()
metric = "complexity"
for (key, val) in plans
push!(curricula, val.curriculum)
end
display(metric_histogram(curricula, metric, title=" Programs", xlabel="$(metric)", ylabel="# of curricula", xlim=(0,500)))
The following function will find prerequisites in a curriculum. These are redundant prerequisites that are unnecessary in a curriculum. For example, if a curriculum has the prerequisite relationships c1→c2→c3 and c1→c3, and c1 and c2 are not co-requisites, then c1→c3 is redundant and therefore extraneous. Extraneous prerequisites do not effect the curricular complexity metric, they simply are unnecessary clutter in a curriculum or degree plan.
for plan in plans
extraneous_requisites(plan[2].curriculum, print=true)
end
Georgia Institute of Technology: curriculum Aerospace Engineering has extraneous requisites: -Statics has redundant requisite Integral Calculus Georgia Institute of Technology: curriculum Electrical Engineering - Electronic Devices and Circuit Technology has extraneous requisites: -Digital Design Lab has redundant requisite Fund. of Digital System Design -Microelectronic Circuits has redundant requisite Differential Equations -Electromagnetics has redundant requisite Differential Equations -Measurements, Circuits and Microelectronics Lab has redundant requisite Digital Design Lab
The following function can be used to find "dead end" courses in a curricula. Dead end courses are those that appear at the end of a path (i.e., sink vertices), and are not a part of a course associated with the major. E.g., in the case of the ECE curriculum above, these would be courses at the end of a path that do not have the "ECE" or "ENGR" prefix. One might consider these courses dead ends, as their course outcomes are not (formally) used by any major-specific course, i.e., by any course with the prefix "ECE."
prefixes = Dict{String, Array{String,1}}()
prefixes["Electrical Engineering"] = ["ECE"];
prefixes["Electrical Engineering - Electronic Devices and Circuit Technology"] = ["ECE"];
prefixes["Aerospace Engineering"] = ["AE"];
for plan in plans
de = dead_ends(plan[2].curriculum, prefixes[plan[2].curriculum.name])
println("\nDead end courses in the $(plan[2].curriculum.name) curriculum:")
for course in de[2]
println("$(course.prefix) $(course.num): $(course.name)")
end
end
Dead end courses in the Aerospace Engineering curriculum: ENGL 1102: English Composition II ECE 3741: Circuits /Electronics Lab AE 4341/2/3: Air/Space/Rotor Design Dead end courses in the Electrical Engineering curriculum: Dead end courses in the Electrical Engineering - Electronic Devices and Circuit Technology curriculum: ENGL 1102: English Composition II
The Curricular Analytics toolbox contains a number of functions that will create different degree plans for a curriculum depending upon various optimization criteria. In order to use these functions, you must first install the Gourbi solver, called Gurobi Optimizer. Gurobi is a commercial product, and requires a license key; however, academic licenses are available at no cost.
# Uncomment the following two lines if the Gurobi package has not yet been included in your Julia environment.
#using Pkg
#Pkg.add("Gurobi")
using Gurobi
metrics = basic_metrics(EE_plan)
println(String(take!(metrics)))
Curriculum: Electrical Engineering - Electronic Devices and Circuit Technology Degree Plan: 2021-22 Plan total credit hours = 129 number of terms = 8 max. credits in a term = 17, in term 1 min. credits in a term = 14, in term 8 avg. credits per term = 16.125, with std. dev. = 1.0532687216470449
EE_new_1 = optimize_plan(EE_plan.curriculum, 8, 12, 18, balance_obj);
visualize(EE_new_1, notebook=true)
Academic license - for non-commercial use only An optimal solution was found with objective value = 14.0
WebIO not detected.
Please read the troubleshooting guide for more information on how to resolve this issue.
https://juliagizmos.github.io/WebIO.jl/latest/troubleshooting/not-detected/
metrics = basic_metrics(EE_new_1)
println(String(take!(metrics)))
Curriculum: Electrical Engineering - Electronic Devices and Circuit Technology Degree Plan: total credit hours = 129 number of terms = 8 max. credits in a term = 17, in term 2 min. credits in a term = 16, in term 1 avg. credits per term = 16.125, with std. dev. = 0.33071891388307384
#curric = deepcopy(EE_plan.curriculum)
#convert_ids(curric)
#toxic = Array{Pair{Course,Course},1}()
# Differential Calc is toxic to Linear Algebra
#push!(toxic, course(curric, "MATH", "1551", "Differential Calculus", "") => course(curric, "MATH", "1554", "Linear Algebra", ""))
EE_new_2 = optimize_plan(EE_plan.curriculum, 8, 12, 18, req_distance_obj);
visualize(EE_new_2, notebook=true)
Academic license - for non-commercial use only An optimal solution was found with objective value = 35.0
WebIO not detected.
Please read the troubleshooting guide for more information on how to resolve this issue.
https://juliagizmos.github.io/WebIO.jl/latest/troubleshooting/not-detected/
metrics = basic_metrics(EE_new_2)
println(String(take!(metrics)))
Curriculum: Electrical Engineering - Electronic Devices and Circuit Technology Degree Plan: total credit hours = 129 number of terms = 8 max. credits in a term = 18, in term 4 min. credits in a term = 12, in term 2 avg. credits per term = 16.125, with std. dev. = 1.8328597873268975
EE_new_3 = optimize_plan(EE_plan.curriculum, 8, 12, 18, [balance_obj, req_distance_obj]);
visualize(EE_new_3, notebook=true)
Academic license - for non-commercial use only An optimal solution was found with objective value = 14.0
WebIO not detected.
Please read the troubleshooting guide for more information on how to resolve this issue.
https://juliagizmos.github.io/WebIO.jl/latest/troubleshooting/not-detected/
metrics = basic_metrics(EE_new_3)
println(String(take!(metrics)))
Curriculum: Electrical Engineering - Electronic Devices and Circuit Technology Degree Plan: total credit hours = 129 number of terms = 8 max. credits in a term = 17, in term 7 min. credits in a term = 16, in term 1 avg. credits per term = 16.125, with std. dev. = 0.33071891388307384
#EE_new_4 = optimize_plan(EE_plan.curriculum, 8, 12, 18, [balance_obj, req_distance_obj], toxic_courses=toxic);
#visualize(EE_new_4, notebook=true)
[1] Heileman, G. L., Abdallah, C.T., Slim, A., and Hickman, M. (2018). Curricular analytics: A framework for quantifying the impact of curricular reforms and pedagogical innovations. www.arXiv.org, arXiv:1811.09676 [cs.CY].
[2] Heileman, G. L., Free, H. W., Abar, O. and Thompson-Arjona, W. G, (2019). CurricularAnalytics.jl Toolbox. https://github.com/heileman/CurricularAnalytics.jl.