Can you tell me what the zstd invocation is that corresponds to the default invocation of bzip3, which uses block size 16 MiB (according to the man page)?
I got some really good results with bzip3 compression Wikipedia XML dumps, and I would like to check if it's actually better or if I was just calling zstd wrong.
If you want a 16MB window, use `--long=24` (2^24 is 16M). (I believe this is larger than the default window for zstd level 3, but smaller than the default window at higher compression levels.)
>iv. Never use the passive where you can use the active.
Orwell himself routinely ignores it, even in the first sentence of the essay:
>Most people who bother with the matter at all would admit that the English language is in a bad way, but it is generally assumed that we cannot by conscious action do anything about it.
The second clause could be rewritten in active voice by changing it to "but people generally assume". But this would make the writing worse, and Orwell, as a good writer, probably didn't even consider the option of making it worse, and therefore didn't notice the passive voice.
Passive voice is an essential tool for all good writers of English. I always give the example of the opening of Pride and Prejudice [0]:
>It is a truth universally acknowledged, that a single man in possession of a good fortune, must be in want of a wife.
The joke doesn't work in active voice. If you attribute this acknowledgement to some specific group of people then it's simply false, not a comedic exaggeration.
Technically, I think, that first sentence, by Austen, uses a passive participle but does not use a passive voice for any finite verb. I don't think that advice to avoid "the passive" is intended to apply to that situation.
For example, nobody would seriously suggest avoiding the passive participle in a sentence like "Put the broken plate in the bin". ("Put the plate that someone broke into the bin"?)
There's a rather simple reason this is so: A thought is typically most powerfully expressed in a sentence that puts the most surprising or notable word last, immediately before the period. Ideally, without any qualifying adjective/adverb.
And "... a wife." really turns on the ears, no?
So advice to prefer active voice is not wrong -- but the skilled writer adds other values into the balance.
> It's a bit of a pet peeve when people include quotes on a blog post without linking or otherwise references their source.
You’re peeved with good reason. It’s the blog equivalent of posting a screenshot of an article to social media. People, please post your sources! In the age of misinformation, that’s more important than ever.
You shouldn't have to click away from a blog post to understand what the blog post is about. It should start with a clear self-contained introduction.
atproto.com contains a succinct discription:
> Atproto is a big-world open social protocol. Users publish JSON records into repositories. The changestreams of those records then sync across the network to drive applications.
Still a bit abstract, but OK. Personally I would include that AT protocol stands for Authenticated Transfer Protocol and that it is the protocol powering Bluesky.
> When the data fed into an AI model is based on real data you can get predictability. When the AI inputs start coming from the AI outputs the wobble is introduced which results inevitably into delirium.
This is asserted without evidence. There is absolutely no proof that AI requires humans in the loop to function or improve itself.
Compare it with Deepmind's go-playing program, AlphaGo, which mainly involved training a neural network on a large database of high-level human games. It defeated one of the top-ranked players in the world, Lee Sedol, but arguably it was drawing from human experience just like you described.
But it didn't stop there. After that, Deepmind developed AlphaGo Zero, a version that was trained exclusively through self-play, with no human feedback in the loop. That's what you would call "AI inputs coming from AI outputs" but it didn't have the result of “resulting in delirium”: instead, it became orders of magnitudes stronger than the original version (which it defeated in a 100 to 0 competition after 3 days of training).
This shows that AI can improve itself without having access to any human knowledge, and indeed transcend human performance by orders of magnitudes. There is absolutely nothing to suggest that general AI cannot improve itself the same way.
People who claim otherwise are engaging in wishful thinking; they just assert their conclusion, but have no rational arguments to back it up.
You have no evidence that self improvement can work at generalized tasks. Go is a simple game with a clear win condition, but deep strategy and near infinite permutations of how a game plays out. Winning a game of Go is a task well suited to machine learning.
One might say you are engaging in wishful thinking by believing it’ll just continue to work across all domains. The world is much bigger than a Go board.
> You have no evidence that self improvement can work at generalized tasks.
I never made that claim. I just said it's way too early to rule it out: there is no logical reason why AIs will (always) need to have a human in the loop, and we don't have enough experience with LLMs to know what their true limits are.
I referenced AlphaGo not because the game of Go is exactly like every other task AI might perform in the future, but because the evolution from AlphaGo (which was trained on human games) to AlphaGo Zero (which was not) shows that at least in certain domains, it's not only possible to take the human out of the loop, it can actually make AI perform better.
I'm not claiming this will definitely be possible in every other domain, but people who state it definitely won't be, are jumping the gun.
Both programs had programmed in to their routines the rules of go (and for Alpha Zero the rules of chess and shogi). The programs then followed an optimization program. Absent the extremely specific "rules of this game" set by a human none of the programs work.
Amusingly, all three games are in the game theory sense trivial because they provably have a correct solution (probably a draw for chess), but the search space is so large that it is unlikely we will ever collectively invest the resources to discover the answer.
AlphaZero works in simple and fully observable environments like board games.
RLVR for LLMs works for coding and math domains which can be verified by code.
AlphaZero, RLVR and other RL methods don't work for learning dextrous manipulation for robotics, for example. Learning in robotics depends on human data.
The key word in that paper is “indiscriminate”, as in:
> We find that _indiscriminate_ use of model-generated content in training causes irreversible defects in the resulting models
If you view AI training as lossy compression of their training data, then lossily compressing the same data repeatedly will result in data degredation; this is well known from other domains (try repeatedly compressing a JPEG image, for example).
That means it's extremely important that there is some content curation in the loop. But there is no reason to believe this content curation must be done by humans, or that it must exclude all AI-generated content by default.
For example, the recent LLM-generated disproof of the Jacobian conjecture would probably be beneficial to include in the training data, despite being the result of an LLM.
That paper has had a pretty turbulent reception and looks pretty conclusively wrong at this point.
It used an incorrect theoretical framing that assumed that data was being replaced rather than accumulated as a result of more training (see https://arxiv.org/abs/2404.01413 which explores this). This is incorrect because this simply isn't how real-world datasets are created via synthetic data generation (which generally accumulate more data over time rather than replace their data). As a result most of the theoretical results were invalid.
Empirical evidence has also cast a considerable amount of doubt on the paper. For example, Microsoft Phi-4 was an empirical test in specifically what happens if the majority of your training data is synthetic rather than human and it turns out that Phi-4 did significantly better than previous models which relied primarily on human data.
There's some nuance to all of this in how exactly you do this, but the original claims of the paper are looking really shaky at this point.
You are referring to gans which have complete understanding of the rules and an api interface to leverage interacting with the world.
While I think there could be an argument made here you are mixing apples and rocks if you believe ChatGPT is using gans.
I hate to be that person but you are showing that you are unable to differentiate between linear regressions, clustering, gradient descent, and generative adversarial networks. You are over your ski-tips and don't see itc
Lambda expressions in C++ are simply syntactic sugar for defining function objects (aka functors): structs that overload operator() so you can call them as functions. Once you realize this, their features and limitations become immediately clear.
For example, here is a typical use of a lambda expression to filter a vector of values:
#include <iostream>
#include <vector>
int main() {
std::vector<int> v = {3, 1, 4, 1, 5, 9, 2, 6, 5};
int threshold = 5;
std::erase_if(v, [&](int i) { return i < threshold; });
// prints 5 9 6 5
for (int i : v) std::cout << i << '\n';
}
The lambda expression is essentially shorthand for:
...
int threshold = 5;
struct lambda_t {
int &threshold;
bool operator()(int i) {
return i < threshold;
}
};
std::erase_if(v, lambda_t{threshold});
...
You could always do this in C++. The added value of the lambda expression syntax is that the compiler generates the boilerplate, and generates a unique name for lambda_t.
The important takeaway is that every lambda expression corresponds with a unique type that is _not_ a function type, but a class type. Consequently, lambda expressions can only be passed to template functions like std::erase_if, which are parameterized with the callback type.
You cannot pass a lambda expression to a function that expects a function pointer (e.g. bool(*)(int) in this example), and that's where they differ from GCC-style nested functions, which actually behave like functions. It also explains why lambda expressions don't need a trampoline.
As an aside, you _can_ pass lambdas to non-generic functions using a type-erasing wrapper like std::function, but std::function is itself a class type too, so that still doesn't allow you to convert it to a plain function pointer.
Finally, you can of course assign a name to a lambda expression value, using this common pattern:
auto greet = [](const char *name) { std::cout << "Hello " << name << "!\n"; }
greet("Alice");
greet("Bob");
(Note that `auto` is necessary here because there is no way to explicitly refer to the compiler-generated name for the lambda type.)
This is the closest you can get to a local function definition in C++. Admittedly the syntax is a little odd. You might wonder why there wasn't some additional syntactic sugar to make the definition look more normal. I suspect that wasn't a random decision, but rather intentionally avoiding conflicts with existing language extensions like GCC's local function syntax.
> lambda expressions can only be passed to template functions
> there is no way to explicitly refer to the compiler-generated name for the lambda type.
"Voldemort" types. While intellectually I get the explanation for why C++/Rust lambdas are like this, I still strongly dislike them. Occasionally being unable to even articulate what something is feels like a failure in language design.
C recently got type inference via the "auto" keyword and it seemed like almost immediately there was a proposal to add voldemort types to the language.
I know it's not the same, but you can "kind of" name them by using them as a template parameter, then, scoped to the template, you can reference them under the template parameter name.
Anyway, I don't see it mentioned anywhere in this discussion, but imo the area where c++ lambdas shine is the way they interact with copy constructors and move constructors.
Regarding function syntax in C++: GCC's C++ frontend does not support nested functions. But more importantly, even if it did, I do not think there would be any conflict at all. While lambdas are lowered to function objects with an unique anonymous type in C++, the semantics of a lambda that uses lvalue capture
auto f = [&](int x) - > int { return x + z; };
is the same as GCC's nested function
int f(int x) { return x + z; }
except that latter can be converted via a trampoline to a regular function pointer (and maybe the observable type). But you could do just the same with a lambda using a trampoline! In any case, there is no conflict, either this conversion is allowed and one needs some hack to make it work such as a trampoline or it is not.
So in C++ you could simply lower such nested functions to lambdas and it would cause no confusion with GCC's nested functions at all, because from a user's point of view they would work identically.
For the non-capturing case: mainly to improve readability by allowing utility functions to be defined close to where they are used and with short names.
For the capturing case: to access context that is not available through global variables or function arguments, i.e., the same reason why closures are useful in other languages.
Here's an example, where I have a list of points that I want to sort based on distance to a chosen target point. I can use qsort() which takes an arbitrary comparison function, but has no way to provide context to that function beyond the input arguments:
#include <stdio.h>
#include <stdlib.h>
int main() {
struct Point {
int x, y;
} points[3] = {
{ 3, 1 },
{ 2, 2 },
{ 5, 7 } };
struct Point target = { 4, 5 };
long dsq(const struct Point *p) {
long dx = p->x - target.x, dy = p->y - target.y;
return dx*dx + dy*dy;
}
int compare(const void *p, const void *q) {
long a = dsq(p), b = dsq(q);
return (a > b) - (a < b);
}
qsort(points, 3, sizeof(struct Point), compare);
for (int i = 0; i < 3; ++i) {
printf("%d,%d\n", points[i].x, points[i].y);
}
}
Note here that dsq() is a local function that accesses the `target` variable in the local function scope.
The usual workaround in standard C is to pass the necessary context as a function argument. That's why qsort_r() exists, which takes a context argument to be passed to compare(), but that's a non-standard GNU extension.
This practice of passing context pointers around is ubiquitous in C code, and it works, but it can get messy especially if you need access to multiple variables or variables from more than one nested scope. There is also a type safety issue: these context pointers are necessarily passed as void* which means they have to be cast back to the real type before use, which is where bugs can be introduced if the caller and receiver disagree on the actual type.
int main() {
struct Point {
int x, y;
} points[3] = {
{ 3, 1 },
{ 2, 2 },
{ 5, 7 }
};
struct Point target = { 4, 5 };
long dsq(const struct Point *p) {
long dx = p->x - target.x, dy = p->y - target.y;
return dx*dx + dy*dy;
}
typedef typeof(dsq) dsq_f;
int compare(const void *p, const void *q, void *data) {
wide(dsq_f) *dsq = data;
long a = CALL(*dsq, (p)), b = CALL(*dsq, (q));
return (a > b) - (a < b);
}
qsort_r(points, 3, sizeof(struct Point), compare, &CLOSURE(dsq_f, dsq));
for (int i = 0; i < 3; ++i)
printf("%d,%d\n", points[i].x, points[i].y);
}
There are slightly different ways how to define the helper macros, I am still experimenting a bit. Here you could avoid the typedef if defined differently. But ideally, there would be native language support that avoids these macros.
Fair. If you only have one object to access such as the target pointer, then it probably makes not much difference with void-pointer based APIs such as qsort_r (for new APIs it would add type safety). Where it removes more boilerplate code is when you have several such objects and would have to create an extra data structure to access them.
It was really cool! The ease of getting started was definitely one of the selling points for the “home computers” of that era (GW-BASIC ran on IBM compatible PCs instead, but the appeal of BASIC was the same). Brevity was an important feature since a lot of people obtained programs by typing them over from a magazine or recording them from the radio. And of course, there was no such thing as auto-complete (let alone AI generation).
That being said, SDL isn't actually that bad either. A minimal example is about 40 lines of code [1], not counting comments and blank lines, but including lines with just a curly brace which you could easily remove if you were concerned about size. A slightly more serious implementation of Snake runs about 345 lines of code [2].
And to be fair, DONKEY.BAS is also cheating slightly on the line metric by stuffing lines full of statements, like for example:
A$=INKEY$:IF A$=CHR$(27) THEN 1298 ELSE POKE 106,0:IF LEN(A$)>0 THEN LINE (CX,CY)-(CX+28,CY+44),0,BF:CX=252-CX:PUT (CX,CY),CAR%,PRESET:SOUND 200,1
Yeah for the rendering a smooth set of RGB shifting colors using SIN you could do it in a few lines of QBASIC.
The only thing is that since the SDL example uses a 640x480 resolution, which corresponds to SCREEN 12, and in QBASIC it only gives you access to 16 indexed colors at once.
So you have to "cheat" by redefining a single entry (like index 1) throughout the loop with calculated RGB using the PALETTE command. It's basically the equivalent of palette color cycling used in some older games.
reply