Speaking very high level, probably the most interesting and counter-intuitive thing I learned from doing these projects is that adding just a touch of speed modules can go a long way, especially at the lower quality levels. Of course, if the only thing being optimized is legendary outputs per common input, then speed is always bad. But because an upcycler works much better when the buildings and modules are themselves legendary, usually the limiting factor is the (very expensive) crafting machines, rather than the amount of input lines. Adding a touch of speed can give way more throughput for the same number of legendary crafting machines, at the cost of some wasted inputs, which isn't a big deal when you can slap down a few more cheap miners.
Python script: https://github.com/scottmsul/FactorioQualityOptimizer
JS source: https://github.com/scottmsul/upcycle