246 karma · joined January 2, 2019
Sunlight gives us vitamin D and nitric oxide (which improves blood flow and reduces hypertension). Vitamin D is crucial for the functioning of our immune systems, and the 1000IU dosage of many supplements is laughably small. A light skinned person in a singlet standing outside at noon for 30 minutes will produce between 10,000IU and 20,000IU in their skin. I would recommend supplementing 5,000IU vitamin D while also getting some exposure in the morning or afternoon (but avoiding the sun when it is high in the sky).
Apart from the OCaml compiler, everything else is fairly typical of the spectrum of roles you can find at the very large high frequency firms. And mid-sized firms are similar yet again, minus the basic research. I would say it is definitely worth working in this industry if anything above sounds interesting to you.
Replacing some fruit with vegetables instead, and choosing less sweet fruit like various berries or melons may be a good idea for most people.
Details here: https://youtu.be/Kvh4D_osFXs
You can even combine this with the two usual methods for low acidity coffee that you mentioned (cold brewing and using dark roasts). I haven't actually tried this combo yet but I'm keen to!
> "... if there was actually a simple transformation, I would just transform it in the first place and use a linear model"
The first level of usefulness of the kernel trick is that it allows us to bypass this. Even when we know the transformation, bypassing the explicit transformation can be vastly more computationally efficient.
Say our data comes as x = (x_1, ..., x_n) but we suspect that better features would be the the second degree terms: T(x) = (x_i x_j)_{1 <= i <= j <= n}. So T maps R^n to R^{n^2}. So our data matrix could go from 10^3 wide to 10^6 wide (terrible!). And then we want to compute the inner products of two samples mapped into this higher dimensional space R^{n^2}, which will be an O(n^2) operation.
Alternatively, if we focus in on the fact that we really only need the inner product of the transformed samples (not actually the transformed samples themselves), we see that what we want is:
Sum_{1<=i<=j<=n} (x_i x_j) (x'_i x'_j) = [Sum_{1<= i <= n} x_i x'_i ]^2 = <x,x'>^2
where <x,x'> is the normal inner product in R^n. So we can define k(x,x') = <x,x'>^2, and computing k(x,x') like this is only an O(n) operation (whereas not using the kernel trick and going the explicit transformation route leads to O(n^2) operations for computing inner products in the higher dimensional space).
So we've seen that, even when the transformation to be applied is simple and known, avoiding it with the kernel trick can vastly improve the speed and memory usage of the model.
The second level of understanding the kernel trick is observing that a kernel is simply measuring similarity between two samples in some way. We can conjure kernel functions that create a notion of similarity that we want to try out (or suspect would be good for our data), without ever having to think about what kind of transformation of the data would lead to an inner product in a higher dimension space that leads to that similarity.
Let's make one right now. Say we want two samples x and x' to be similar if they are close (in R^n) and not similar if they are not close, but we really want to exaggerate this. We may imagine there's some threshold (that if two samples are 1 unit away from each other, that's quite similar, but being 3 units away isn't 1/3rd as similar but far far less similar) we really want to "peak" similarity in a tight radius. Then we could use k(x,x') = exp(- |x-x'|^2), since this only has a value near 1 if x and x' are quite close and drops off rapidly to 0 as x and x' get further apart. How rapidly should the similarity drop off as they get further apart? That's probably a parameter we may want to experiment with, let's go with k(x,x') = exp(- gamma * |x-x'|^2) instead. We've just invented Radial Basis Function (RBF) kernels (or Gaussian kernels) ! Do we have any idea what explicit transformation we would do to our data to get an inner product in a higher dimensional space that leads to this same function k(x,x')? Nope. Regardless, do we have a notion of similarity that may be very useful for our data? Yup.
So the kernel trick transforms the harder problem of thinking up a transformation to a higher dimensional space where the data can be easily separated, into the easier problem of thinking up good notions of similarity between samples. But you're right - you still need to have some type of understanding of your data to intuit what a good kernel function will be for your problem. That's part of the art (unfortunately, less of a science) of being good at training SVMs. If you have no idea at all, most people will go with a Gaussian kernel and just see how that goes. Knowing all the common kernels and when to use which is basically the SVM equivalent of hyperparameter tuning in NNs - the model doesn't learn itself which ones are good, despite that there are some common-wisdom good defaults, and you can squeeze out some extra performance by knowing how to select the good ones from experience (or brute force searching all options). I need some practice in being more concise, but hopefully some of this helps.
As someone who graduated recently and is going through this process right now - I always thought I would be set because I'm a decent problem solver, aced all my algorithms and data structures classes and generally could solve most interview style problems I came across. I've learned that this is not enough. An organic problem solving process might involve trying several promising approaches, or starting with a suboptimal algorithm and realising improvements to it, and then you might figure out an optimal solution. In many of these interviews the time constraints can be absurd, you basically have to have done the questions or variants of them recently to be able to write down the optimal solution in your first iteration.
Today my friend had a first round online screening from Atlassian - 5 questions in 90 minutes, and none of them were trivial warm up level questions. Compound this with the fact that it's often harder to solve problems and think creatively when you're under time pressure in an interview, and you realise that your only option is to do 200+ Leetcode problems and just hope your interview overlaps with those problems.
I have been consistent. I agreed above that is buuble sort was one part of a program that you only call on elements of size up to 10 and the input of the program, n, is something else then the bubble sort piece is O(1). But if n refers to the size of an array input into a bubble sort, then it is not O(1). Big-O considers what happens when the size of the _input_ grows. For a comparison sort we consider what happens where the _number_ of elements goes to infinity, but the elements themselves are assumed to bounded (e.g. 32 bit ints). This ensures comparison is O(1) not matter which two elements of the array you chosen from an arbitrarily large array. I don't see why you think the addition involved in a comparison sort wouldn't be O(1) as the addition addition that is required to increment pointers by 1.
> No operations on arbitrarily large numbers are constant on the number of digits, but that is not a good model for predicting actual runtimes of actual programs that use doubles. When I use ints or longs or doubles, it is not just appropriate to use O(1) for the basic arithmetic operations, it is incorrect to assume larger complexity when that larger complexity does not apply to your program.
You're describing the common situation when analysing a program is that the input of the program is some parameter (E.g. the size of an array) and all the integer arithmetic that arises during that program is on ints or doubles, so the program executes correctly _even as_ the input grows.
The key difference for this project Euler example is that there the input n is actually an integer that we do the main arithmetic on. The point of the program is to sum integers up to n. As I've explained before, if you then say "but practically we limit n to ints so it's O(1)" then _any_ function I write whose only input is an int is O(1) and the notion is meaningless.
Time complexity is usually for specific algorithms, though it can also be studied for a general problem itself (e.g. any comparison sort is at least O(n log n), regardless of algorithm or implementation). It is precisely a concept that applies to arbitrarily large inputs, that condition is at the core of its very definition.
If I designed a hardware board that runs bubble sort on any array that fits into its 16GB of memory and gave documentation printing out its (large) constant predictable run time, that still wouldn't make it correct to say Bubble sort is a constant time operation.
>Your bubble sort example is contrived, but the answer is that it is okay to call a sort of 10 elements constant if that’s one component of a system and it doesn’t grow as the size of your input grows...if the sort inside doesn’t change as your input changes, then that piece is constant.
We aren't talking about running on 10 elements and it staying at 10 elements as the size of the input grows (that would indeed be O(1)). For the original example in the link, we are talking about a piece (arithmeticSum) whose input is n, which tautologically does grow as the size of the input grows.
I thought it was very ironic that soon after that sentence, the author claims the arithmeticSum method is O(1) when it is actually O(log(n) log(log(n))).
Many people seem to assume that multiplication is a constant time operation. There is actually immense "hidden complexity" in doing multiplication of arbitrarily large integers efficiently. David Harvey proved last year that multiplication of two n bit integers can be done in O(n log n). It is still an open conjecture that this is the best possible.