rmcclellan
For those interested in an open source design embodying these techniques, I have an open source hardware design here: https://github.com/russellmcc/dco with a blog write-up here: https://www.russellmcc.com/posts/2013-12-01-DCO.html .
Also of relevance is an open source hardware design for the later roland alpha juno digital oscillator design: https://github.com/russellmcc/alphaosc https://www.russellmcc.com/posts/2019-06-14-Alpha-DCO.html
For anyone interested, I'd recommend checking out "The Infinite Jukebox", which has a similar goal, but perhaps a more robust approach: http://infinitejukebox.playlistmachinery.com
If I had to guess at why your approach didn't work well on recorded music, it's probably because most of the time, there is more than a single event happening at a time, so picking out just the highest FFT bin is probably not a very robust "fingerprint" of that part of the music. The infinite jukebox uses timbral features as the fingerprint, rather than just a single note.
With "modern" techniques, the performance ceiling is a bit higher - whether that benefit is worth it depends on a lot of factors.
Also, I think build time is super important in most contexts - what I think is less important is runtime speed when you’ve disabled all optimizations.
One part that really struck me as odd is the focus on non-optimized performance. To me, this is an important consideration, but not nearly as important as optimized performance. Using techniques like ranges can definitely slow down debug performance, but much of the time it _dramatically increases_ optimized performance vs. naive techniques.
How do ranges speed up optimized builds? One of the best techniques for very high performance code is separation of specifying the algorithm and scheduling the computation. What I mean by this is techniques like [eigen](http://eigen.tuxfamily.org/index.php?title=Main_Page) and [halide](http://halide-lang.org) where you can control _what_ gets done and _how_ it gets done separately. Being able to modify execution orders like this is critical for ensuring that you're using your single-core parallelism and cache space in an efficient way. This sort of control is exactly what you get out of range view transformers.
http://www.haskell.org/ghc/docs/7.6.2/html/libraries/base/Un...
Show HN: Sound Effect Generator in HTML5
http://swopec.hhs.se/hastef/abs/hastef0671.htm
Calculating the equillibrium strategy for rational actors is difficult because each player doesn't know how many other players there are. In the paper above, game theorists calculate it and show that the distributions seen in the lottery match up fairly well to a rational strategy.
The point of multi-armed bandit situations is that there is a trade-off to be made between gaining new knowledge and exploiting existing knowledge. This comes up in your charts - the "MAB"s always have better conversion rates, because they balance between the two modes. The "A/B testing" always gain more information quickly because they ignore exploitation and only focus on exploration.
I should say also that multi-armed bandit algorithms also aren't supposed to be run as a temporary "campaign" - they are "set it and forget it". In epsilon-greedy, you never stop exploring, even after the campaign is over. In this way, you don't need to achieve "statistical significance" because you're never taking the risk of choosing one path for all time. In traditional A/B testing, there's always the risk of picking the wrong choice.
You aren't comparing A/B testing to a multi-armed bandit algorithm because both are multi-armed bandit algorithms. You're in a bandit situation either way. The strategy you were already using for your A/B tests is a different common bandit strategy called "epsilon-first" by wikipedia, and there is a bit of literature on how it compares to epsilon-greedy.
http://en.wikipedia.org/wiki/Multi-armed_bandit#Common_bandi...
http://en.wikipedia.org/wiki/Whitespace_(programming_languag...
The biggest difference for me is the difference in the calling convention. In 32 bit, all arguments generally are placed on the stack for "standard" calls. In 64 bit, different OSes have different conventions:
http://en.wikipedia.org/wiki/X86_calling_conventions#x86-64_... (note that OS X and linux use the "System V" calling conventions)
As a thought experiment, let's consider a pulse that has been band-limited to 20kHz. Are you arguing that the analog output of a (filtered, idealized) DAC would look different depending on whether the dac was running at 44.1kHz vs 192kHz? If so, I don't think many people would agree with you.
Any difference in the "timing" of the output wave would have to come from energy that falls above nyquist of the slower sample rate. So, while I agree with you that the timing would be sharper, this is exactly caused by "higher frequencies", not by some other sort of timing improvement.
Said another way, two band limited pulse signals with different onset times, no matter how arbitrarily close, will result in different sampled signals.
I think perhaps another reason why beginners find monads so hard to understand, especially those coming from a math background, is that >>= is a bizarre presentation of monads. I think, for example, defining a monad as an applicative with a join operation would have been a much better idea - most monads, like Maybe or [], make the most sense to me as "containers" that can be joined. The bind operator never really made intuitive sense to me when thinking about a monad as a container with a structure. Plus, to me, m (m a) -> m a is a lot easier to recognize than m a -> (a -> m b) -> m b.
This is especially true since applicatives are now becoming a very popular language idiom. It seems unfair to beginners to make them try to understand applicatives and then make them learn an unrelated typeclass for monads, when mathematically the two are very similar objects.
Such complicated control flows should be treated as a major, fundamental problem. Keeping them in place will cause bugs and prevent future contributors from having confidence that their changes are correct. The problem of complicated control flow is too deep to be solved with a band-aid like this, although perhaps syntactically it looks a bit nicer. In fact, this is exactly what people did before the so-called "structured programming adepts" came around, except using gotos instead of continues. It didn't work so well back then, and it doesn't work so well now.
So, academically, even the "virtual human" approach doesn't work since it doesn't answer correctly for every single program. Practically, you're right, having a virtual human would be good enough for most uses.
That said, I wouldn't want to use a virtual human for this due to ethical concerns :-).
If you restrict yourself to a turing incomplete language, checking a specification no longer reduces to the halting problem. In fact, there are many systems that do exactly this, and most of these systems are perfectly capable of sorting a list and proving that the list is sorted.
However, I think the real point is that there are at least dozens of smart people who are working on this exact problem all day, every day. The OP shows neither a deep understanding of why previous attempts at this have failed or really, any knowledge at all about the state of the field of programming language research.
"Allow weaker passwords and limit login attempts" is not the solution either, because it gives an attacker who has discovered my user id but not my password the ability to lock my account.
"What’s worse, a weak password, or a password that sits on your desk?"
Contrary to what is said in the article, a weak password is worse - no question. A password that sits on my desk is only available to people who break into my home. If they do that, they probably have access to other documents of some importance.
A password that is weak can allow anyone access to my account, from anywhere.