nusmodifications / nusmods

🏫 Official course planning platform for National University of Singapore.
https://nusmods.com
MIT License
588 stars 319 forks source link

[RFC] Design Discussion for integrating NUS Timetable Optimizer #3294

Open frizensami opened 3 years ago

frizensami commented 3 years ago

This is a fairly long issue - my apologies! I hope it will provide a good base for discussion.


Is your feature request related to a problem? Please describe.

Students have many possibilities each semester when choosing lessons and modules for their timetable. This is especially difficult and time-consuming in earlier academic years.

Therefore, a feature that automatically optimizes a student's NUSMods timetable subject to their preferences might be very useful.


MVP Solution Implementation (NUS Timetable Optimizer)

Description

NUS Timetable Optimizer (GitHub link) is a standalone MVP implementation of this proposed feature. It takes as input a list of modules and a set of user-supplied constraints (e.g., free day / lunch hours / lesson start-end requirements), and outputs a timetable that meets the constraints. If optimization constraints are specified (e.g., compact the timetable as much as possible), the output timetable attempts to maximize/minimize the stated constraints. The list of possible new features are at the project's Issues page, with more to be added.

This issue aims to discuss the possibility of merging its functionality into NUSMods, and if so, to discuss the design considerations around its implementation.

Some results from MVP implementation

Prior work

390 describes a previous attempt to solve this issue, which inspired the current approach. Notable similarities are:

However, we also build upon #390. This is a short description of some of the improvements:




Integration into NUSMods

This section aims to discuss the following design points that I can think of. I can check these off and insert the conclusions as this discussion progresses:


Should / can this be integrated into NUSMods?


Ethical considerations

I and others were concerned that computing optimal timetables would upset the demand-and-supply characteristics of the module registration system. There might be excessive demand for "ideal" lesson configurations, resulting in more students ending up without classes. My thoughts:


Current infrastructure requirements

These are the two things the optimizer requires that might present deployment challenges.

  1. WebAssembly Binary and Initialization z3w.wasm is the WebAssembly binary that is downloaded by each client to run the optimizer locally. A fully uncached download takes 4.3 MB over the network, uncompressing to 18.3 MB. However, this is a one-time cost. The file is cached after this.

This + Initializing the solver takes around 10 seconds on average. image

However, I think this is the best implementation I can think of. Most serverless platforms (Cloudflare, Vercel, Netlify, AWS) have restrictions on solver runtime, so the 1 - 5 second runtime (which can be more for complex optimizations) is too much. Modern mobile and desktop devices are more than capable of running this computation, so I doubt the UX benefit of running the solver on a dedicated server platform is worth it. That option might also be prohibitively expensive.

Currently, this is deployed on a free Netlify instance, taking advantage of of the 100 GB free egress bandwidth. The app is just a statically served React bundle there.

  1. Web Worker Usage I don't think this will be an issue due to the widespread use of Web Workers, but due to the CPU-intensiveness of computation, the optimizer runs on a web worker and communicates results through message-passing.

Where should the optimizer go?

I think the most natural place is on the main timetable page, but hidden behind the beta flag. For instance: image

Showing the optimizer could mean showing constraints below the existing module list (Not a front-end person, please ignore the terrible styling!): image

Every time the user runs the optimizer (say it's a button above the Constraints header), the timetable is arranged. Could add a button to restore the original timetable.

Other options?:


UX Flow

What i'm envisioning:

  1. User selects their modules and lessons as per the normal user flow
  2. User clicks on the Show Optimizer button
  3. If it's their first time, they have to click on an "Initialize Optimizer" button or something similar. This could provide a warning about the download size and init time if that's a concern.
  4. After this, the user can repeatedly change their constraints and run the optimizer. Successful runs will shift their modules around in their main timetable.
  5. We add a button to restore their original timetable, similar to the current import-through-share-link header.

Conclusion

I hope this issue acts as a base for discussing whether this feature is wanted, and how to implement it if so :)

li-kai commented 3 years ago

On the matters of bundle size and performance, I don't think it is a concern. NUS students tend to use modern browsers and relatively fast mobile phones (compared to the avg pop). What does matter, is the UX and how we teach people how to use the constraint solver. As I understand, we have someone working on UX, so I'll defer to them on this.

frizensami commented 3 years ago

Sounds good! I added a WIP PR so that we can prototype quickly.

Probably the two important things out of the lot above are:

frizensami commented 3 years ago

Updated the PR with the current method i have of initializing the solver in z3w.wasm. A subset of changes:

Note: filenames are outdated, this has been simplified a bit

TLDR: usage of Z3 is controlled by z3Manager --> [[ Webworker boundary ]] --> z3Worker (importing the wrapper z3w.js) --> z3w.wasm

frizensami commented 3 years ago

Just an update on this: slowly working on maximizing test coverage on all non-UI code. I just have converter.ts to go for utils. That will hopefully make it easier to iterate on the UI side without worrying about breakages.