*Someone from the House Permanent Select Committee on Intelligence recently contacted me about a hearing they’re having on the subject of deep fakes. I can’t attend the hearing, but the conversation got me thinking about the subject of deep fakes, and I made a few quick notes….*

The idea of modifying images is as old as photography. At first, it had to be done by hand (sometimes with airbrushing). By the 1990s, it was routinely being done with image manipulation software such as Photoshop. But it’s something of an art to get a convincing result, say for a person inserted into a scene. And if, for example, the lighting or shadows don’t agree, it’s easy to tell that what one has isn’t real.

What about videos? If one does motion capture, and spends enough effort, it’s perfectly possible to get quite convincing results—say for animating aliens, or for putting dead actors into movies. The way this works, at least in a first approximation, is for example to painstakingly pick out the keypoints on one face, and map them onto another.

What’s new in the past couple of years is that this process can basically be automated using machine learning. And, for example, there are now neural nets that are simply trained to do “face swapping”:

In essence, what these neural nets do is to fit an internal model to one face, and then apply it to the other. The parameters of the model are in effect learned from looking at lots of real-world scenes, and seeing what’s needed to reproduce them. The current approaches typically use generative adversarial networks (GANs), in which there’s iteration between two networks: one trying to generate a result, and one trying to discriminate that result from a real one.

Today’s examples are far from perfect, and it’s not too hard for a human to tell that something isn’t right. But even just as a result of engineering tweaks and faster computers, there’s been progressive improvement, and there’s no reason to think that within a modest amount of time it won’t be possible to routinely produce human-indistinguishable results.

OK, so maybe a human won’t immediately be able to tell what’s real and what’s not. But why not have a machine do it? Surely there’s some signature of something being “machine generated”. Surely there’s something about a machine-generated image that’s statistically implausible for a real image.

Well, not naturally. Because, in fact, the whole way the machine images are generated is by having models that as faithfully as possible reproduce the “statistics” of real images. Indeed, inside a GAN there’s explicitly a “fake or not” discriminator. And the whole point of the GAN is to iterate until the discriminator can’t tell the difference between what’s being generated, and something real.

Could one find some other feature of an image that the GAN isn’t paying attention to—like whether a face is symmetric enough, or whether writing in the background is readable? Sure. But at this level it’s just an arms race: having identified a feature, one puts it into the model the neural net is using, and then one can’t use that feature to discriminate any more.

There are limitations to this, however. Because there’s a limit to what a typical neural net can learn. Generally, neural nets do well at tasks like image recognition that humans do without thinking. But it’s a different story if one tries to get neural nets to do math, and for example factor numbers.

Imagine that in modifying a video one has to fill in a background that’s showing some elaborate computation—say a mathematical one. Well, then a standard neural net basically doesn’t stand a chance.

Will it be easy to tell that it’s getting it wrong? It could be. If one’s dealing with public-key cryptography, or digital signatures, one can certainly imagine setting things up so that it’s very hard to generate something that is correct, but easy to check whether it is.

But will this kind of thing show up in real images or videos? My own scientific work has actually shown that irreducibly complex computation can be quite ubiquitous even in systems with very simple rules—and presumably in many systems in nature. Watch a splash in water. It takes a complex computation to figure out the details of what’s going to happen. And while a neural net might be able to get something that basically looks like a splash, it’d be vastly harder for it to get the details of a particular splash right.

But even though in the abstract computational irreducibility may be common, we humans, in our evolution and the environments we set up for ourselves, tend to end up doing our best to avoid it. We have shapes with smooth curves. We build things with simple geometries. We try to make things evolvable or understandable. And it’s this avoidance of computational irreducibility that makes it feasible for neural nets to successfully model things like the visual scenes in which we typically find ourselves.

One can disrupt this, of course. Just put in the picture a display that’s showing some sophisticated computation (even, for example, a cellular automaton). If someone tries to fake some aspect of this with a neural net, it won’t (at least on its own) feasibly be able to get the details right.

I suspect that in the future of human technology—as we mine deeper in the computational universe—irreducible computation will be much more common in what we build. But as of now, it’s still rare in typical human-related situations. And as a result, we can expect that neural nets will successfully be able to model what’s going on well enough to at least fool other neural nets.

So if there’s no way to analyze the bits in an image to tell if it’s a real photograph, does that mean we just can’t tell? No. Because we can also think about metadata associated with the image—and about the provenance of the image. When was the image created? By whom? And so on.

So let’s say we create an image. How can we set things up so that we can prove when we did it? Well, in modern times it’s actually very easy. We take the image, and compute a cryptographic hash from it (effectively by applying a mathematical operation that derives a number from the bits in the image). Then we take this hash and put it on a blockchain.

The blockchain acts as a permanent ledger. Once we’ve put data on it, it can never be changed, and we can always go back and see what the data was, and when it was added to the blockchain.

This setup lets us prove that the image was created no later than a certain time. If we want to prove that the image wasn’t created earlier, then when we create the hash for the image, we can throw in a hash from the latest block on our favorite blockchain.

OK, but what about knowing who created the image? It takes a bit of cryptographic infrastructure—very similar to what’s done in proving the authenticity of websites. But if one can trust some “certificate authority” then one can associate a digital signature to the image that validates who created it.

But how about knowing where the image was taken? Assuming one has a certain level of access to the device or the software, GPS can be spoofed. If one records enough about the environment when the image was taken, then it gets harder and harder to spoof. What were the nearby Wi-Fi networks? The Bluetooth pings? The temperature? The barometric pressure? The sound level? The accelerometer readings? If one has enough information collected, then it becomes easier to tell if something doesn’t fit.

There are several ways one could do this. Perhaps one could just detect anomalies using machine learning. Or perhaps one could use actual models of how the world works (the path implied by the accelerometer isn’t consistent with the equations of mechanics, etc.). Or one could somehow tie the information to some public computational fact. Was the weather really like that in the place the photo was said to be taken? Why isn’t there a shadow from such-and-such a plane going overhead? Why is what’s playing on the television not what it should be? Etc.

But, OK, even if one just restricts oneself to creation time and creator ID, how can one in practice validate them?

The best scheme seems to be something like how modern browsers handle website security. The browser tries to check the cryptographic signature of the website. If it matches, the browser shows something to say the website is secure; if not, it shows some kind of warning.

So let’s say an image comes with data on its creation time and creator ID. The data could be metadata (say EXIF data), or it could be a watermark imprinted on the detailed bits in the image. Then the image viewer (say in the browser) can check whether the hash on a blockchain agrees with what the data provided by the image implies. If it does, fine. And the image viewer can make the creation time and creator ID available. If not, the image viewer should warn the user that something seems to be wrong.

Exactly the same kind of thing can be done with videos. It just requires video players computing hashes on the video, and comparing to what’s on a blockchain. And by doing this, one can guarantee, for example, that one’s seeing a whole video that was made at a certain time.

How would this work in practice? Probably people often wouldn’t want to see all the raw video taken at some event. But a news organization, for example, could let people click through to it if they wanted. And one can easily imagine digital signature mechanisms that could be used to guarantee that an edited video, for example, contained no content not in certain source videos, and involved, say, specified contiguous chunks from these source videos.

So, where does this leave us with deep fakes? Machine learning on its own won’t save us. There’s not going to be a pure “fake or not” detector that can run on any image or video. Yes, there’ll be ways to protect oneself against being “faked” by doing things like wearing a live cellular automaton tie. But the real way to combat deep fakes, I think, is to use blockchain technology—and to store on a public ledger cryptographic hashes of both images and sensor data from the environment where the images were acquired. The very presence of a hash can guarantee when an image was acquired; “triangulating” from sensor and other data can give confidence that what one is seeing was something that actually happened in the real world.

Of course, there are lots of technical details to work out. But in time I’d expect image and video viewers could routinely check against blockchains (and “data triangulation computations”), a bit like how web browsers now check security certificates. And today’s “pics or it didn’t happen” will turn into “if it’s not on the blockchain it didn’t happen”.

]]>We’re on an exciting path these days with the Wolfram Language. Just three weeks ago we launched the Free Wolfram Engine for Developers to help people integrate the Wolfram Language into large-scale software projects. Now, today, we’re launching the Wolfram Function Repository to provide an organized platform for functions that are built to extend the Wolfram Language—and we’re opening up the Function Repository for anyone to contribute.

The Wolfram Function Repository is something that’s made possible by the unique nature of the Wolfram Language as not just a programming language, but a full-scale computational language. In a traditional programming language, adding significant new functionality typically involves building whole libraries, which may or may not work together. But in the Wolfram Language, there’s so much already built into the language that it’s possible to add significant functionality just by introducing individual new functions—which can immediately integrate into the coherent design of the whole language.

To get it started, we’ve already got 532 functions in the Wolfram Function Repository, in 26 categories:

Just like the 6000+ functions that are built into the Wolfram Language, each function in the Function Repository has a documentation page, with a description and examples:

Go to the page, click to copy the “function blob”, paste it into your input, and then use the function just like a built-in Wolfram Language function (all necessary downloading etc. is already handled automatically in Version 12.0):

✕
ResourceFunction["LogoQRCode"]["wolfr.am/E72W1Chw", CloudGet["https://wolfr.am/EcBjBfzw"]] |

And what’s critical here is that in introducing `LogoQRCode` you don’t, for example, have to set up a “library to handle images”: there’s already a consistent and carefully designed way to represent and work with images in the Wolfram Language—that immediately fits in with everything else in the language:

✕
Table[ImageTransformation[ ResourceFunction["LogoQRCode"]["wolfr.am/E72W1Chw", ColorNegate[CloudGet["https://wolfr.am/EcBjBfzw"]]], #^k &], {k, 1, 2, .25}] |

I’m hoping that—with the help of the amazing and talented community that’s grown up around the Wolfram Language over the past few decades—the Wolfram Function Repository is going to allow rapid and dramatic expansion in the range of (potentially very specialized) functions available for the language. Everything will leverage both the content of the language, and the design principles that the language embodies. (And, of course, the Wolfram Language has a 30+ year history of design stability.)

Inside the functions in the Function Repository there may be tiny pieces of Wolfram Language code, or huge amounts. There may be calls to external APIs and services, or to external libraries in other languages. But the point is that when it comes to user-level functionality everything will fit together, because it’s all based on the consistent design of the Wolfram Language—and every function will automatically “just work”.

We’ve set it up to be as easy as possible to contribute to the Wolfram Function Repository—essentially just by filling out a simple notebook. There’s automation that helps ensure that everything meets our design guidelines. And we’re focusing on coverage, not depth—and (though we’re putting in place an expert review process) we’re not insisting on anything like the same kind of painstaking design analysis or the same rigorous standards of completeness and robustness that we apply to built-in functions in the language.

There are lots of tradeoffs and details. But our goal is to optimize the Wolfram Function Repository both for utility to users, and for ease of contribution. As it grows, I’ve no doubt that we’ll have to invent new mechanisms, not least for organizing a large number of functions, and finding the ones one wants. But it’s very encouraging to see that it’s off to such a good start. I myself contributed a number of functions to the initial collection. Many are based on code that I’ve had for a long time. It only took me minutes to submit them to the Repository. But now that they’re in the Repository, I can—for the first time ever—immediately use the functions whenever I want, without worrying about finding files, loading packages, etc.

We’ve had ways for people to share Wolfram Language code since even before the web (our first major centralized effort was MathSource, built for Mathematica in 1991, using CD-ROMs, etc.). But there’s something qualitatively different—and much more powerful—about the Wolfram Function Repository.

We’ve worked very hard for more than 30 years to maintain the design integrity of the Wolfram Language, and this has been crucial in allowing the Wolfram Language to become not just a programming language, but a full-scale computational language. And now what the Wolfram Function Repository does is to leverage all this design effort to let new functions be added that fit consistently into the framework of the language.

Inside the implementation of each function, all sorts of things can be going on. But what’s critical is that to the user, the function is presented in a very definite and uniform way. In a sense, the built-in functions of the Wolfram Language provide 6000+ consistent examples of how functions should be designed (and our livestreamed design reviews include hundreds of hours of the process of doing that design). But more than that, what ultimately makes the Wolfram Function Repository able to work well is the symbolic character of the Wolfram Language, and all the very rich structures that are already built into the language. If you’ve got a function that deals with images—or sparse arrays, or molecular structures, or geo positions, or whatever—there’s already a consistent symbolic representation of those in the language, and by using that, your function is immediately compatible with other functions in the system.

Setting up a repository that really works well is an interesting meta-design problem. Give too little freedom and one can’t get the functionality one wants. Give too much freedom and one won’t be able to maintain enough consistency. We’ve had several previous examples that have worked very well. The Wolfram Demonstrations Project—launched in 2007 and now (finally) running interactively on the web—contains more than 12,000 contributed interactive demonstrations. The Wolfram Data Repository has 600+ datasets that can immediately be used in the Wolfram Language. And the Wolfram Neural Net Repository adds neural nets by the week (118 so far) that immediately plug into the `NetModel` function in the Wolfram Language.

All these examples have the feature that the kind of thing that’s being collected is well collimated. Yes, the details of what actual Demonstration or neural net or whatever one has can vary a lot, but the fundamental structure for any given repository is always the same. So what about a repository that adds extensions to the Wolfram Language? The Wolfram Language is set up to be extremely flexible—so it can basically be extended and changed in any way. And this is tremendously important in making it possible to quickly build all sorts of large-scale systems in the Wolfram Language. But with this flexibility comes a cost. Because the more one makes use of it, the more one ends up with a separated tower of functionality—and the less one can expect that (without tremendous design effort) what one builds will consistently fit in with everything else.

In traditional programming languages, there’s already a very common problem with libraries. If you use one library, it might be OK. But if you try to use several, there’s no guarantee that they fit together. Of course, it doesn’t help that in a traditional programming language—as opposed to a full computational language—there’s no expectation of even having consistent built-in representations for anything but basic data structures. But the problem is bigger than that: whenever one builds a large-scale tower of functionality, then without the kind of immense centralized design effort that we’ve put into the Wolfram Language, one won’t be able to achieve the consistency and coherence needed for everything to always work well together.

So the idea of the Wolfram Function Repository is to avoid this problem by just adding bite-sized extensions in the form of individual functions—that are much easier to design in a consistent way. Yes, there are things that cannot conveniently be done with individual functions (and we’re soon going to be releasing a streamlined mechanism for distributing larger-scale packages). But with everything that’s already built into the Wolfram Language there’s an amazing amount that individual functions can do. And the idea is that with modest effort it’s possible to create very useful functions that maintain enough design consistency that they fit together and can be easily and widely used.

It’s a tradeoff, of course. With a larger-scale package one can introduce a whole new world of functionality, which can be extremely powerful and valuable. But if one wants to have new functionality that will fit in with everything else, then—unless one’s prepared to spend immense design effort—it’ll have to be smaller scale. The idea of the Wolfram Function Repository is to hit a particular sweet spot that allows for powerful functionality to be added while making it manageably easy to maintain good design consistency.

We’ve worked hard to make it easy to contribute to the Wolfram Function Repository. On the desktop (already in Version 12.0), you can just go to File > New > Repository Item > Function Repository Item and you’ll get a “Definition Notebook” (programmatically, you can also use `CreateNotebook["FunctionResource"]`):

There are two basic things you have to do: first, actually give the code for your function and, second, give documentation that shows how the function should be used.

Press the Open Sample button at the top to see an example of what you need to do:

Essentially, you’re trying to make something that’s like a built-in function in the Wolfram Language. Except that it can be doing something much more specific than a built-in function ever would. And the expectations for how complete and robust it is are much lower.

But you’ll need a name for your function, that fits in with Wolfram Language function naming principles. And you’ll need documentation that follows the same pattern as for built-in functions. I’ll say more later about these things. But for now, just notice that in the row of buttons at the top of the Definition Notebook there’s a Style Guidelines button that explains more about what to do, and there’s a Tools button that provides tools—especially for formatting documentation.

When you think you’re ready, press the Check button. It’s OK if you haven’t gotten all the details right yet. Because Check will automatically go through and do lots of style and consistency checks. Often it will make immediate suggestions for you to approve (“This line should end with a colon” and it’ll offer to put the colon in). Sometimes it will ask you to add or change something yourself. We’ll be continually adding to the automatic functionality of Check, but basically its goal to try to ensure that anything you submit to the Function Repository is already guaranteed to follow as many of the style guidelines as possible.

OK, so after you run Check, you can use Preview. Preview generates a preview of the documentation page that you’ve defined for your function. You can choose to create a preview either in a desktop notebook, or in the cloud. If you don’t like something you see in the preview, just go back and fix it, and press Preview again.

Now you’re ready to deploy your function. The Deploy button provides four options:

The big thing you can do is to submit your function to the Wolfram Function Repository, so it’s available to everyone forever. But you can also deploy your function for more circumscribed use. For example, you can have the function just deployed locally on your computer, so it will be available whenever you use that particular computer. Or you can deploy it to your cloud account, so it will be available to you whenever you’re connected to the cloud. You can also deploy a function publicly through your cloud account. It won’t be in the central Wolfram Function Repository, but you’ll be able to give anyone a URL that’ll let them get your function from your account. (In the future, we’ll also be supporting organization-wide central repositories.)

OK, let’s say you’re ready to actually submit your function to the Wolfram Function Repository. Then, needless to say, you press Submit to Repository. So what happens then? Well, your submission immediately goes into a queue for review and approval by our team of curators.

As your submission goes through the process (which will typically take a few days) you’ll get status messages—as well as maybe suggestions. But as soon as your function is approved, it’ll immediately be published in the Wolfram Function Repository, and available for anyone to use. (And it’ll show up in New Functions digests, etc. etc.)

We have very high standards for the completeness, robustness—and overall quality—of the 6000+ functions that we’ve painstakingly built into the Wolfram Language over the past 30+ years. The goal of the Wolfram Function Repository is to leverage all the structure and functionality that already exists in the Wolfram Language to add as many as possible, much more lightweight, functions.

Yes, functions in the Wolfram Function Repository need to follow the design principles of the Wolfram Language—so they fit in with other functions, and with users’ expectations about how functions should work. But they don’t need to have the same completeness or robustness.

In the built-in functions of the Wolfram Language, we work hard to make things be as general as possible. But in the Wolfram Function Repository, there’s nothing wrong with having a function that just handles some very specific, but useful, case. `SendMailFromNotebook` can accept notebooks in one specific format, and produce mail in one specific way. `PolygonalDiagram` makes diagrams only with particular colors and labeling. And so on.

Another thing about built-in functions is that we go to great pains to handle all the corner cases, to deal with bad input properly, and so on. In the Function Repository it’s OK to have a function that just handles the main cases—and ignores everything else.

Obviously it’s better to have functions that do more, and do it better. But the optimization for the Function Repository—as opposed to for the built-in functions of the Wolfram Language—is to have more functions, covering more functionality, rather than to deepen each function.

What about testing the functions in the Function Repository? The expectations are considerably lower than for built-in functions. But—particularly when functions depend on external resources such as APIs—it’s important to be continually running regression tests, which is what automatically happens behind the scenes. In the Definition Notebook, you can explicitly give (in the Additional Information section) as many tests as you want, defined either by input and output lines or by full symbolic `VerificationTest` objects. In addition, the system tries to turn the documentation examples you give into tests (though this can sometimes be quite tricky, e.g. for a function whose result depends on random numbers, or the time of day).

There’ll be a whole range of implementation complexity to the functions in the Function Repository. Some will be just a single line of code; others might involve thousands or tens of thousands of lines, probably spread over many subsidiary functions. When is it worth adding a function that takes only very little code to define? Basically, if there’s a good name for the function—that people would readily understand if they saw it in a piece of code—then it’s worth adding. Otherwise, it’s probably better just to write the code again each time you need to use it.

The primary purpose of the Function Repository (as its name suggests) is to introduce new functions. If you want to introduce new data, or new entities, then use the Wolfram Data Repository. But what if you want to introduce new kinds of objects to compute with?

There are really two cases. You might want a new kind of object that’s going to be used in new functions in the Function Repository. And in that case, you can always just write down a symbolic representation of it, and use it in the input or output of functions in the Function Repository.

But what if you want to introduce an object and then define how existing functions in the Wolfram Language should operate on it? Well, the Wolfram Language has always had an easy mechanism for that, called upvalues. And with certain restrictions (particularly for functions that don’t evaluate their arguments), the Function Repository lets you just introduce a function, and define upvalues for it. (To set expectations: getting a major new construct fully integrated everywhere in the Wolfram Language is typically a very significant undertaking, that can’t be achieved just with upvalues—and is the kind of thing we do as part of the long-term development of the language, but isn’t what the Function Repository is set up to deal with.)

But, OK, so what can be in the code for functions in the Function Repository? Anything built into the Wolfram Language, of course (at least so long as it doesn’t pose a security risk). Also, any function from the Function Repository. But there are other possibilities, too. A function in the Function Repository can call an API, either in the Wolfram Cloud or elsewhere. Of course, there’s a risk associated with this. Because there’s no guarantee that the API won’t change—and make the function in the Function Repository stop working. And to recognize issues like this, there’s always a note on the documentation page (under Requirements) for any function that relies on more than just built-in Wolfram Language functionality. (Of course, when real-world data is involved, there can be issues even with this functionality—because actual data in the world changes, and even sometimes changes its definitions.)

Does all the code for the Wolfram Function Repository have to be written in the Wolfram Language? The code inside an external API certainly doesn’t have to be. And, actually, nor even does local code. In fact, if you find a function in pretty much any external language or library, you should be able to make a wrapper that allows it to be used in the Wolfram Function Repository. (Typically this will involve using `ExternalEvaluate` or `ExternalFunction` in the Wolfram Language code.)

So what’s the point of doing this? Basically, it’s to leverage the whole integrated Wolfram Language system and its unified design. You get the underlying implementation from an external library or language—but then you’re using the Wolfram Language’s rich symbolic structure to create a convenient top-level function that makes it easy for people to use whatever functionality has been implemented. And, at least in a perfect world, all the details of loading libraries and so on will be automatically taken care of through the Wolfram Language. (In practice, there can sometimes be issues getting external languages set up on a particular computer system—and in the cloud there are additional security issues to worry about.)

By the way, when you first look at typical external libraries, they often seem far too complicated to just be covered by a few functions. But in a great many cases, most of the complexity comes from building up the infrastructure needed for the library—and all the functions to support that. When one’s using the Wolfram Language, however, the infrastructure is usually already built in, and so one doesn’t need to expose all those support functions—and one only needs to create functions for the few “topmost” applications-oriented functions in the library.

If you’ve written functions that you use all the time, then send them in to the Wolfram Function Repository! If nothing else, it’ll be much easier for you to use the functions yourself. And, of course, if you use the functions all the time, it’s likely other people will find them useful too.

Of course, you may be in a situation where you can’t—or don’t want to—share your functions, or where they access private resources. And in such cases, you can just deploy the functions to your own cloud account, setting permissions for who can access them. (If your organization has a Wolfram Enterprise Private Cloud, then this will soon be able to host its own private Function Repository, which can be administered within your organization, and set to force review of submissions, or not.)

Functions you submit to the Wolfram Function Repository don’t have to be perfect; they just have to be useful. And—a bit like the “Bugs” section in classic Unix documentation—there’s a section in the Definition Notebook called “Author Notes” in which you can describe limitations, issues, etc. that you’re already aware of about your function. In addition, when you submit your function you can include Submission Notes that’ll be read by the curation team.

Once a function is published, its documentation page always has two links at the bottom: “Send a message about this function”, and “Discuss on Wolfram Community”. If you send a message (say reporting a bug), you can check a box saying you want your message and contact information to be passed to the author of the function.

Often you’ll just want to use functions from the Wolfram Function Repository like built-in functions, without looking inside them. But if you want to “look inside”, there’s always a Source Notebook button at the top. Press it and you’ll get your own copy of the original Definition Notebook that was submitted to the Function Repository. Sometimes you might just want to look at this as an example. But you can also make your own modifications. Maybe you’ll want to deploy these on your computer or in your cloud account. Or maybe you’ll want to submit these to the Function Repository, perhaps as a better version of the original function.

In the future, we might support Git-style forking in the Function Repository. But for now, we’re keeping it simpler, and we’re always having just one canonical version of each function. And basically (unless they abandon it and don’t respond to messages) the original author of the function gets to control updates to it—and gets to submit new versions, which are then reviewed and, if approved, published.

OK, so how does versioning work? Right now, as soon as you use a function from the Function Repository its definition will get permanently stored on your computer (or in your cloud account, if you’re using the cloud). If there’s a new version of the function, then when you next use the function, you’ll get a message letting you know this. And if you want to update to the new version, you can do that with `ResourceUpdate`. (The “function blob” actually stores more information about versioning, and in the future we’re planning on making this conveniently accessible.)

One of the great things about the Wolfram Function Repository is that any Wolfram Language program anywhere can use functions from it. If the program appears in a notebook, it’s often nice to format Function Repository functions as easy-to-read “function blobs” (perhaps with appropriate versioning set).

But you can always refer to any Function Repository function using a textual `ResourceFunction[...]`. And this is convenient if you’re directly writing code or scripts for the Wolfram Engine, say with an IDE or textual code editor. (And, yes, the Function Repository is fully compatible with the Free Wolfram Engine for Developers.)

Inside the Wolfram Function Repository it’s using exactly the same Resource System framework as all our other repositories (Data Repository, Neural Net Repository, Demonstrations Project, etc.) And like everything else in the Resource System, a `ResourceFunction` is ultimately based on a `ResourceObject`.

Here’s a `ResourceFunction`:

✕
ResourceFunction["StringIntersectingQ"] |

It’s somewhat complicated inside, but you can see some of what’s there using `Information`:

✕
Information[ResourceFunction["StringIntersectingQ"]] |

So how does setting up a resource function work? The simplest is the purely local case. Here’s an example that takes a function (here, just a pure function) and defines it as a resource function for this session:

✕
DefineResourceFunction[1 + # &, "AddOne"] |

Once you’ve made the definition, you can use the resource function:

✕
ResourceFunction["AddOne"][100] |

Notice that in this function blob, there’s a black icon . This indicates the function blob refers to an in-memory resource function defined for your current session. For a resource function that’s permanently stored on your computer, or in a cloud account, there’s a gray icon . And for an official resource function in the Wolfram Function Repository there’s an orange icon .

OK, so what happens when you use the Deploy menu in a Definition Notebook? First, it’ll take everything in the Definition Notebook and make a symbolic `ResourceObject` out of it. (And if you’re using a textual IDE—or a program—you can also explicitly create the `ResourceObject`.)

Deploying locally on your computer uses `LocalCache` on the resource object to store it as a `LocalObject` in your file system. Deploying in your cloud account uses `CloudDeploy` on the resource object, and deploying publicly in the cloud uses `CloudPublish`. In all cases, `ResourceRegister` is also used to register the name of the resource function so that `ResourceFunction["`*name*`"]` will work.

If you press Submit to Function Repository, then what’s happening underneath is that `ResourceSubmit` is being called on the resource object. (And if you’re using a textual interface, you can call `ResourceSubmit` directly.)

By default, the submission is made under the name associated with your Wolfram ID. But if you’re submitting on behalf of a group or an organization, then you can set up a separate Publisher ID, and you can instead use this as the name to associate with your submissions.

Once you’ve submitted something to the Function Repository, it’ll go into the queue for review. If you get comments back, they’ll usually be in the form of a notebook with extra “comment cells” added. You can always check on the status of your submission by going to the Resource System Contributor Portal. But as soon as it’s approved, you’ll be notified (by email), and your submission will be live on the Wolfram Function Repository.

At first, it might seem like it should be possible to take a Definition Notebook and just put it verbatim into the Function Repository. But actually there are quite a few subtleties—and handling them requires doing some fairly sophisticated metaprogramming, symbolically processing both the code defining the function, and the Definition Notebook itself. Most of this happens internally, behind the scenes. But it has some consequences that are worth understanding if you’re going to contribute to the Function Repository.

Here’s one immediate subtlety. When you fill out the Definition Notebook, you can just refer to your function everywhere by a name like `MyFunction`—that looks like an ordinary name for a function in the Wolfram Language. But for the Function Repository documentation, this gets replaced by `ResourceFunction["MyFunction"]`—which is what users will actually use.

Here’s another subtlety: when you create a resource function from a Definition Notebook, all the dependencies involved in the definition of the function need to be captured and explicitly included. And to guarantee that the definitions remain modular, one needs to put everything in a unique namespace. (Needless to say, the functions that do all this are in the Function Repository.)

Usually you’ll never see any evidence of the internal context used to set up this namespace. But if for some reason you return an unevaluated symbol from the innards of your function, then you’ll see that the symbol is in the internal context. However, when the Definition Notebook is processed, at least the symbol corresponding to the function itself is set up to be displayed elegantly as a function blob rather than as a raw symbol in an internal context.

The Function Repository is about defining new functions. And these functions may have options. Often these options will be ones (like, say, `Method` or `ImageSize`) that have already been used for built-in functions, and for which built-in symbols already exist. But sometimes a new function may need new options. To maintain modularity, one might like these options to be symbols defined in a unique internal context (or to be something like whole resource functions in their own right). But to keep things simple, the Function Repository allows new options to be given in definitions as strings. And, as a courtesy to the final user, these definitions (assuming they’ve used `OptionValue` and `OptionsPattern`) are also processed so that when the functions are used, the options can be given not only strings but also as global symbols with the same name.

Most functions just do what they do each time they are called. But some functions need initialization before they can run in a particular session—and to deal with this there’s an Initialization section in the Definition Notebook.

Functions in the Function Repository can immediately make use of other functions that are already in the Repository. But how do you set up definitions for the Function Repository that involve two (or more) functions that refer to each other? Basically you just have to deploy them in your session, so you can refer to them as `ResourceFunction["`*name*`"]`. Then you can create the examples you want, and then submit the functions.

Today we’re just launching the Wolfram Function Repository. But over time we expect it to grow dramatically, and as it grows there are a variety of issues that we know will come up.

The first is about function names and their uniqueness. The Function Repository is designed so that—like for built-in functions in the Wolfram Language—one can refer to any given function just by giving its name. But this inevitably means that the names of functions have to be globally unique across the Repository—so that, for example, there can be only one `ResourceFunction["MyFavoriteFunction"]` in the Repository.

This might seem like a big issue. But it’s worth realizing it’s basically the same issue as for things like internet domains or social network handles. And the point is that one simply has to have a registrar—and that’s one of the roles we’re playing for the Wolfram Function Repository. (For private versions of the Repository, their administrators can be registrars.) Of course an internet domain can be registered without having anything on it, but in the Function Repository the name of a function can only be registered if there’s an actual function definition to go with it.

And part of our role in managing the Wolfram Function Repository is to ensure that the name picked for a function is reasonable given the definition of the function—and that it fits in with Wolfram Language naming conventions. We’ve now had 30+ years of experience in naming built-in functions in the Wolfram Language, and our curation team brings that experience to the Function Repository. Of course, there are always tradeoffs. For example, it might seem nice to have a short name for some function. But it’s better to “name defensively” with a longer, more specific name, because then it’s less likely to collide with something one wants to do in the future.

(By the way, just adding some kind of contributor tag to disambiguate functions wouldn’t achieve much. Because unless one insists on always giving the tag, one will end up having to define a default tag for any given function. Oh, and allocating contributor tags again requires global coordination.)

As the Wolfram Function Repository grows, one of the issues that’s sure to arise is the discoverability of functions. Yes, there’s search functionality (and Definition Notebooks can include keywords, etc.). But for built-in functions in the Wolfram Language there’s all sorts of cross-linking in documentation which helps “advertise” functions. Functions in the Function Repository can link to built-in functions. But what about the other way around? We’re going to be experimenting with various schemes to expose Function Repository functions on the documentation pages for built-in functions.

For built-in functions in the Wolfram Language, there’s also a level of discoverability provided by the network of “guide pages” that give organized lists of functions relevant to particular areas. It’s always complicated to appropriately balance guide pages—and as the Wolfram Language has grown, it’s common for guide pages to have to be completely refactored. It’s fairly easy to put functions from the Function Repository into broad categories, and even to successively break up these categories. But it’s much more valuable to have properly organized guide pages. It’s not yet clear how best to produce these for the whole Function Repository. But for example `CreateResourceObjectGallery` in the Function Repository lets anyone put up a webpage containing their “picks” from the repository:

The Wolfram Function Repository is set up to be a permanent repository of functions, where any function in it will always just work. But of course, there may be new versions of functions. And we fully expect some functions to be obsoleted over time. The functions will still work if they’re used in programs. But their documentation pages will point to new, better functions.

The Wolfram Function Repository is all about providing new functions quickly—and exploring new frontiers for how the Wolfram Language can be used. But we fully expect that some of what’s explored in the Function Repository will eventually make sense to become built-in parts of the core Wolfram Language. We’ve had a slightly similar flow over the past decade from functionality that was originally introduced in Wolfram|Alpha. And one of the lessons is that to achieve the standards of quality and coherence that we insist on for anything built into the Wolfram Language is a lot of work—that usually dwarfs the original implementation effort. But even so, a function in the Function Repository can serve as a very useful proof of concept for a future function built into the Wolfram Language.

And of course the critical thing is that a function in the Function Repository is something that’s available for everyone to use right now. Yes, an eventual built-in function could be much better and stronger. But the Function Repository lets people get access to new functions immediately. And, crucially, it lets those new functions be contributed by anyone.

Earlier in the history of the Wolfram Language this wouldn’t have worked so well. But now there is so much already built into the language—and so strong an understanding of the design principles of the language—that it’s feasible to have a large community of people add functions that will maintain the design consistency to make them broadly useful.

There’s incredible talent in the community of Wolfram Language users. (And, of course, that community includes many of the world’s top people in R&D across a vast range of fields.) I’m hoping that the Wolfram Function Repository will provide an efficient platform for that talent to be exposed and shared. And that together we’ll be able to create something that dramatically expands the domain to which the computational paradigm can be applied.

We’ve taken the Wolfram Language a long way in 30+ years. Now, together, let’s take it much further. And let’s use the Function Repository—as well as things like the Free Wolfram Engine for Developers—as a platform for doing that.

]]>In the mid-1970s, particle physics was hot. Quarks were in. Group theory was in. Field theory was in. And so much progress was being made that it seemed like the fundamental theory of physics might be close at hand.

Right in the middle of all this was Murray Gell-Mann—responsible for not one, but most of the leaps of intuition that had brought particle physics to where it was. There’d been other theories, but Murray’s—with their somewhat elaborate and abstract mathematics—were always the ones that seemed to carry the day.

It was the spring of 1978 and I was 18 years old. I’d been publishing papers on particle physics for a few years, and had gotten quite known around the international particle physics community (and, yes, it took decades to live down my teenage-particle-physicist persona). I was in England, but planned to soon go to graduate school in the US, and was choosing between Caltech and Princeton. And one weekend afternoon when I was about to go out, the phone rang. In those days, it was obvious if it was an international call. “This is Murray Gell-Mann”, the caller said, then launched into a monologue about why Caltech was the center of the universe for particle physics at the time.

Perhaps not as starstruck as I should have been, I asked a few practical questions, which Murray dismissed. The call ended with something like, “Well, we’d like to have you at Caltech”.

A few months later I was indeed at Caltech. I remember the evening I arrived, wandering around the empty 4th floor of Lauritsen Lab—the home of Caltech theoretical particle physics. There were all sorts of names I recognized on office doors, and there were two offices that were obviously the largest: “M. Gell-Mann” and “R. Feynman”. (In between them was a small office labeled “H. Tuck”—which by the next day I’d realized was occupied by Helen Tuck, the lively longtime departmental assistant.)

There was a regular Friday lunch in the theoretical physics group, and as soon as a Friday came around, I met Murray Gell-Mann there. The first thing he said to me was, “It must be a culture shock coming here from England”. Then he looked me up and down. There I was in an unreasonably bright yellow shirt and sandals—looking, in fact, quite Californian. Murray seemed embarrassed, mumbled some pleasantry, then turned away.

I never worked directly with Murray (though he would later describe me to others as “our student”). But I interacted with him frequently while I was at Caltech. He was a strange mixture of gracious and gregarious, together with austere and combative. He had an expressive face, which would wrinkle up if he didn’t approve of what was being said.

Murray always had people and things he approved of, and ones he didn’t—to which he would often give disparaging nicknames. (He would always refer to solid-state physics as “squalid-state physics”.) Sometimes he would pretend that things he did not like simply did not exist. I remember once talking to him about something in quantum field theory called the beta function. His face showed no recognition of what I was talking about, and I was getting slightly exasperated. Eventually I blurted out, “But, Murray, didn’t you invent this?” “Oh”, he said, suddenly much more charming, “You mean g times the psi function. Why didn’t you just say that? Now I understand”. Of course, he had understood all along, but was being difficult about me using the “beta function” term, even though it had by then been standard for years.

I could never quite figure out what it was that made Murray impressed by some people and not others. He would routinely disparage physicists who were destined for great success, and would vigorously promote ones who didn’t seem so promising, and didn’t in fact do well. So when he promoted me, I was on the one hand flattered, but on the other hand concerned about what his endorsement might really mean.

The interaction between Murray Gell-Mann and Richard Feynman was an interesting thing to behold. Both came from New York, but Feynman relished his “working-class” New York accent, while Gell-Mann affected the best pronunciation of words from any language. Both would make surprisingly childish comments about the other.

I remember Feynman insisting on telling me the story of the origin of the word “quark”. He said he’d been talking to Murray one Friday about these hypothetical particles, and in their conversation they’d needed a name for them. Feynman told me he said (no doubt in his characteristic accent), “Let’s call them ‘quacks’”. The next Monday he said Murray came to him very excited and said he’d found the word “quark” in James Joyce. In telling this to me, Feynman then went into a long diatribe about how Murray always seemed to think the names for things were so important. “Having a name for something doesn’t tell you a damned thing”, Feynman said. (Having now spent so much of my life as a language designer, I might disagree). Feynman went on, mocking Murray’s concern for things like what different birds are called. (Murray was an avid bird watcher.)

Meanwhile, Feynman had worked on particles which seemed (and turned out to be) related to quarks. Feynman had called them “partons”. Murray insisted on always referring to them as “put-ons”.

Even though in terms of longstanding contributions to particle physics (if not physics in general) Murray was the clear winner, he always seemed to feel as if he was in the shadow of Feynman, particularly with Feynman’s showmanship. When Feynman died, Murray wrote a rather snarky obituary, saying of Feynman: “He surrounded himself with a cloud of myth, and he spent a great deal of time and energy generating anecdotes about himself”. I never quite understood why Murray—who could have gone to any university in the world—chose to work at Caltech for 33 years in an office two doors down from Feynman.

Murray cared a lot about what people thought of him, but would routinely (and maddeningly to watch) put himself in positions where he would look bad. He was very interested in—and I think very knowledgeable about—words and languages. And when he would meet someone, he would make a point of regaling them with information about the origin of their name (curiously—as I learned only years later—his own name, “Gell-Mann”, had been “upgraded” from “Gellmann”). Now, of course, if there’s one word people tend to know something about, it’s their own name. And, needless to say, Murray sometimes got its origins wrong—and was very embarrassed. (I remember he told a friend of mine named Nathan Isgur a long and elaborate story about the origin of the name “Isgur”, with Nathan eventually saying: “No, it was made up at Ellis Island!”.)

Murray wasn’t particularly good at reading other people. I remember in early 1982 sitting next to Murray in a limo in Chicago that had just picked up a bunch of scientists for some event. The driver was reading the names of the people he’d picked up over the radio. Many were complicated names, which the driver was admittedly butchering. But after each one, Murray would pipe up, and say “No, it’s said ____”. The driver was getting visibly annoyed, and eventually I said quietly to Murray that he should stop correcting him. When we arrived, Murray said to me: “Why did you say that?” He seemed upset that the driver didn’t care about getting the names right.

Occasionally I would ask Murray for advice, though he would rarely give it. When I was first working on one-dimensional cellular automata, I wanted to find a good name for them. (There had been several previous names for the 2D case, one of which—that I eventually settled on—was “cellular automata”.) I considered the name “polymones” (somehow reflecting Leibniz’s monad concept). But I asked Murray—given all his knowledge of words and languages—for a suggestion. He said he didn’t think polymones was much good, but didn’t have any other suggestion.

When I was working on SMP (a forerunner of Mathematica and the Wolfram Language) I asked Murray about it, though at the time I didn’t really understand as I do now the correspondences between human and computational languages. Murray was interested in trying out SMP, and had a computer terminal installed in his office. I kept on offering to show him some things, but he kept on putting it off. I later realized that—bizarrely to me—Murray was concerned about me seeing that he didn’t know how to type. (By the way, at the time, few people did—which is, for example, why SMP, like Unix, had cryptically short command names.)

But alongside the brush-offs and the strangeness, Murray could be personally very gracious. I remember him inviting me several times to his house. I never interacted with either of his kids (who were both not far from my age). But I did interact with his wife, Margaret, who was a very charming English woman. (As part of his dating advice to me, Feynman had explained that both he and Murray had married English women because “they could cope”.)

While I was at Caltech, Margaret got very sick with cancer, and Murray threw himself into trying to find a cure. (He blamed himself for not having made sure Margaret had had more checkups.) It wasn’t long before Margaret died. Murray invited me to the memorial service. But somehow I didn’t feel I could go; even though by then I was on the faculty at Caltech, I just felt too young and junior. I think Murray was upset I didn’t come, and I’ve felt guilty and embarrassed about it ever since.

Murray did me quite a few favors. He was an original board member of the MacArthur Foundation, and I think was instrumental in getting me a MacArthur Fellowship in the very first batch. Later, when I ran into trouble with intellectual property issues at Caltech, Murray went to bat for me—attempting to intercede with his longtime friend Murph Goldberger, who was by then president of Caltech (and who, before Caltech, had been a professor at Princeton, and had encouraged me to go to graduate school there).

I don’t know if I would call Murray a friend, though, for example, after Margaret died, he and I would sometimes have dinner together, at random restaurants around Pasadena. It wasn’t so much that I felt of a different generation from him (which of course I was). It was more that he exuded a certain aloof tension, that made one not feel very sure about what the relationship really was.

At the end of World War II, the Manhattan Project had just happened, the best and the brightest were going into physics, and “subatomic particles” were a major topic. Protons, neutrons, electrons and photons were known, and together with a couple of hypothesized particles (neutrinos and pions), it seemed possible that the story of elementary particles might be complete.

But then, first in cosmic rays, and later in particle accelerators, new particles started showing up. There was the muon, then the mesons (pions and kaons), and the hyperons (Λ, Σ, Ξ). All were unstable. The muon—which basically nobody understands even today—was like a heavy electron, interacting mainly through electromagnetic forces. But the others were subject to the strong nuclear force—the one that binds nuclei together. And it was observed that this force could generate these particles, though always together (Λ with K, for example). But, mysteriously, the particles could only decay through so-called weak interactions (of the kind involved in radioactive beta decay, or the decay of the muon).

For a while, nobody could figure out why this could be. But then around 1953, Murray Gell-Mann came up with an explanation. Just as particles have “quantum numbers” like spin and charge, he hypothesized that they could have a new quantum number that he called strangeness. Protons, neutrons and pions would have zero strangeness. But the Λ would have strangeness -1, the (positive) kaon strangeness +1, and so on. And total strangeness, he suggested, might be conserved in strong (and electromagnetic) interactions, but not in weak interactions. To suggest a fundamentally new property of particles was a bold thing to do. But it was correct: and immediately Murray was able to explain lots of things that had been observed.

But how did the weak interaction that was—among other things—responsible for the decay of Murray’s “strange particles” actually work? In 1957, in their one piece of collaboration in all their years together at Caltech, Feynman and Gell-Mann introduced the so-called V-A theory of the weak interaction—and, once again, despite initial experimental evidence to the contrary, it turned out to be correct. (The theory basically implies that neutrinos can only have left-handed helicity, and that weak interactions involve parity conservation and parity violation in equal amounts.)

As soon as the quantum mechanics of electrons and other particles was formulated in the 1920s, people started wondering about the quantum theory of fields, particularly the electromagnetic field. There were issues with infinities, but in the late 1940s—in Feynman’s big contribution—these were handled through the concept of renormalization. The result was that it was possible to start computing things using quantum electrodynamics (QED)—and soon all sorts of spectacular agreements with experiment had been found.

But all these computations worked by looking at just the first few terms in a series expansion in powers of the interaction strength parameter α≃1/137. In 1954, during his brief time at the University of Illinois (from which he went to the University of Chicago, and then Caltech), Murray, together with Francis Low, wrote a paper entitled “Quantum Electrodynamics at Small Distances” which was an attempt to explore QED to all orders in α. In many ways this paper was ahead of its time—and 20 years later, the “renormalization group” that it implicitly defined became very important (and the psi function that it discussed was replaced by the beta function).

While QED could be investigated through a series expansion in the small parameter α≃1/137, no such program seemed possible for the strong interaction (where the effective expansion parameter would be ≃1). So in the 1950s there was an attempt to take a more holistic approach, based on looking at the whole so-called S-matrix defining overall scattering amplitudes. Various properties of the S-matrix were known—notably analyticity with respect to values of particle momenta, and so-called crossing symmetry associated with exchanging particles and antiparticles.

But were these sufficient to understand the properties of strong interactions? Throughout the 1960s, attempts involving more and more elaborate mathematics were made. But things kept on going wrong. The proton-proton total interaction probability was supposed to rise with energy. But experimentally it was seen to level off. So a new idea (the pomeron) was introduced. But then the interaction probability was found to start rising again. So another phenomenon (multiparticle “cuts”) had to be introduced. And so on. (Ironically enough, early string theory spun off from these attempts—and today, after decades of disuse, S-matrix theory is coming back into vogue.)

But meanwhile, there was another direction being explored—in which Murray Gell-Mann was centrally involved. It all had to do with the group-theory-meets-calculus concept of Lie groups. An example of a Lie group is the 3D rotation group, known in Lie group theory as SO(3). A central issue in Lie group theory is to find representations of groups: finite collections, say of matrices, that operate like elements of the group.

Representations of the rotation group had been used in atomic physics to deduce from rotational symmetry a characterization of possible spectral lines. But what Gell-Mann did was to say, in effect, “Let’s just imagine that in the world of elementary particles there’s some kind of internal symmetry associated with the Lie group SU(3). Now use representation theory to characterize what particles will exist”.

And in 1961, he published his eightfold way (named after Buddha’s Eightfold Way) in which he proposed—periodic-table style—that there should be 8+1 types of mesons, and 10+8 types of baryons (hyperons plus nucleons, such as proton and neutron). For the physics of the time, the mathematics involved in this was quite exotic. But the known particles organized nicely into Gell-Mann’s structure. And Gell-Mann made a prediction: that there should be one additional type of hyperon, that he called the , with strangeness -3, and certain mass and decay characteristics.

And—sure enough—in 1964, the was observed, and Gell-Mann was on his way to the Nobel Prize, which he received in 1969.

At first the SU(3) symmetry idea was just about what particles should exist. But Gell-Mann wanted also to characterize interactions associated with particles, and for this he introduced what he called current algebra. And, by 1964, from his work on current algebra, he’d realized something else: that his SU(3) symmetry could be interpreted as meaning that things like protons were actually composed of something more fundamental—that he called quarks.

What exactly were the quarks? In his first paper on the subject, Gell-Mann called them “mathematical entities”, although he admitted that, just maybe, they could actually be particles themselves. There were problems with this, though. First, it was thought that electric charge was quantized in units of the electron charge, but quarks would have to have charges of 2/3 and -1/3. But even more seriously, one would have to explain why no free quarks had ever been seen.

It so happened that right when Gell-Mann was writing this, a student at Caltech named George Zweig was thinking of something very similar. Zweig (who was at the time visiting CERN) took a mathematically less elaborate approach, observing that the existing particles could be explained as built from three kinds of “aces”, as he called them, with the same properties as Gell-Mann’s quarks.

Zweig became a professor at Caltech—and I’ve personally been friends with him for more than 40 years. But he never got as much credit for his aces idea as he should (though in 1977 Feynman proposed him for a Nobel Prize), and after a few years he left particle physics and started studying the neurobiology of the ear—and now, in his eighties, has started a quant hedge fund.

Meanwhile, Gell-Mann continued pursuing the theory of quarks, refining his ideas about current algebras. But starting in 1968, there was something new: particle accelerators able to collide high-energy electrons with protons (“deep inelastic scattering”) observed that sometimes the electrons could suffer large deflections. There were lots of details, particularly associated with relativistic kinematics, but in 1969 Feynman proposed his parton (or, as Gell-Mann called it, “put-on”) model, in which the proton contained point-like “parton” particles.

It was immediately guessed that partons might be quarks, and within a couple of years this had been established. But the question remained of why the quarks should be confined inside particles such as protons. To avoid some inconsistencies associated with the exclusion principle, it had already been suggested that quarks might come in three “colors”. Then in 1973, Gell-Mann and his collaborators suggested that associated with these colors, quarks might have “color charges” analogous to electric charge.

Electromagnetism can be thought of as a gauge field theory associated with the Lie group U(1). Now Gell-Mann suggested that there might be a gauge field theory associated with an SU(3) color group (yes, SU(3) again, but a different application than in the eightfold way, etc.). This theory became known as quantum chromodynamics, or QCD. And, in analogy to the photon, it involves particles called gluons.

Unlike photons, however, gluons directly interact with each other, leading to a much more complex theory. But in direct analogy to Gell-Mann and Low’s 1954 renormalization group computation for QED, in 1973 the beta function (AKA g times psi function) for QCD was computed, and was found to show the phenomenon of asymptotic freedom—essentially that QCD interactions get progressively weaker at shorter distances.

This immediately explained the success of the parton model, but also suggested that if quarks get further apart, the QCD interactions between them get stronger, potentially explaining confinement. (And, yes, this is surely the correct intuition about confinement, although even to this day, there is no formal proof of quark confinement—and I suspect it may have issues of undecidability.)

Through much of the 1960s, S-matrix theory had been the dominant approach to particle physics. But it was having trouble, and the discovery of asymptotic freedom in QCD in 1973 brought field theory back to the fore, and, with it, lots of optimism about what might be possible in particle physics.

Murray Gell-Mann had had an amazing run. For 20 years he had made a series of bold conjectures about how nature might work—strangeness, V-A theory, SU(3), quarks, QCD—and in each case he had been correct, while others had been wrong. He had had one of the more remarkable records of repeated correct intuition in the whole history of science.

He tried to go on. He talked about “grand unification being in the air”, and (along with many other physicists) discussed the possibility that QCD and the theory of weak interactions might be unified in models based on groups like SU(5) and SO(10). He considered supersymmetry—in which there would be particles that are crosses between things like neutrinos and things like gluons. But quick validations of these theories didn’t work out—though even now it’s still conceivable that some version of them might be correct.

But regardless, the mid-1970s were a period of intense activity for particle physics. In 1974, the

J/ψ particle was discovered, which turned out to be associated with a fourth kind of quark (charm quark). In 1978, evidence of a fifth quark was seen. Lots was figured out about how QCD works. And a consistent theory of weak interactions emerged that, together with QED and QCD, defined what by the early 1980s had become the modern Standard Model of particle physics that exists today.

I myself got seriously interested in particle physics in 1972, when I was 12 years old. I used to carry around a copy of the little Particle Properties booklet—and all the various kinds of particles became, in a sense, my personal friends. I knew by heart the mass of the Λ, the lifetime of the , and a zillion other things about particles. (And, yes, amazingly, I still seem to remember almost all of them—though now they’re all known to much greater accuracy.)

At the time, it seemed to me like the most important discoveries ever were being made: fundamental facts about the fundamental particles that exist in our universe. And I think I assumed that before long everyone would know these things, just as people know that there are atoms and protons and electrons.

But I’m shocked today that almost nobody has, for example, even heard of muons—even though we’re continually bombarded with them from cosmic rays. Talk about strangeness, or the omega-minus, and one gets blank stares. Quarks more people have heard of, though mostly because of their name, with its various uses for brands, etc.

To me it feels a bit tragic. It’s not hard to show Gell-Mann’s eightfold way pictures, and to explain how the particles in them can be made from quarks. It’s at least as easy to explain that there are 6 known types of quarks as to explain about chemical elements or DNA bases. But for some reason—in most countries—all these triumphs of particle physics have never made it into school science curriculums.

And as I was writing this piece, I was shocked at how thin the information on “classic” particle physics is on the web. In fact, in trying to recall some of the history, the most extensive discussion I could find was in an unpublished book I myself wrote when I was 12 years old! (Yes, full of charming spelling mistakes, and a few physics mistakes.)

When I first met Murray in 1978, his great run of intuition successes and his time defining almost everything that was important in particle physics was already behind him. I was never quite sure what he spent his time on. I know he traveled a lot, using physics meetings in far-flung places as excuses to absorb local culture and nature. I know he spent significant time with the JASON physicists-consult-for-the-military-and-get-paid-well-for-doing-so group. (It was a group that also tried to recruit me in the mid-1980s.) I know he taught classes at Caltech—though he had a reputation for being rather disorganized and unprepared, and I often saw him hurrying to class with giant piles of poorly collated handwritten notes.

Quite often I would see him huddled with more junior physicists that he had brought to Caltech with various temporary jobs. Often there were calculations being done on the blackboard, sometimes by Murray. Lots of algebra, usually festooned with tensor indices—with rarely a diagram in sight. What was it about? I think in those days it was most often supergravity—a merger of the idea of supersymmetry with an early form of string theory (itself derived from much earlier work on S-matrix theory).

This was the time when QCD, quark models and lots of other things that Murray had basically created were at their hottest. Yet Murray chose not to work on them—for example telling me after hearing a talk I gave on QCD that I should work on more worthwhile topics.

I’m guessing Murray somehow thought that his amazing run of intuition would continue, and that his new theories would be as successful as his old. But it didn’t work out that way. Though when I would see Murray, he would often tell me of some amazing physics that he was just about to crack, often using elaborate mathematical formalism that I didn’t recognize.

By the time I left Caltech in 1983, Murray was spending much of his time in New Mexico, around Santa Fe and Los Alamos—particularly getting involved in what would become the Santa Fe Institute. In 1984, I was invited to the inaugural workshop discussing what was then called the Rio Grande Institute might do. It was a strange event, at which I was by far the youngest participant. And as chance would have it, in connection with the republication of the proceedings of that event, I just recently wrote an account of what happened there, which I will soon post.

But in any case, Murray was co-chairing the event, and talking about his vision for a great interdisciplinary university, in which people would study things like the relations between physics and archaeology. He talked in grand flourishes about covering the arts and sciences, the simple and the complex, and linking them all together. It didn’t seem very practical to me—and at some point I asked what the Santa Fe Institute would actually concentrate on if it had to make a choice.

People asked what I would suggest, and I (somewhat reluctantly, because it seemed like everyone had been trying to promote their pet area) suggested “complex systems theory”, and my ideas about the emergence of complexity from things like simple programs. The audio of the event records some respectful exchanges between Murray and me, though more about organizational matters than content. But as it turned out, complex systems theory was indeed what the Santa Fe Institute ended up concentrating on. And Murray himself began to use “complexity” as a label for things he was thinking about.

I tried for years (starting when I first worked on such things, in 1981) to explain to Murray about cellular automata, and about my explorations of the computational universe. He would listen politely, and pay lip service to the relevance of computers and experiments with them. But—as I later realized—he never really understood much at all of what I was talking about.

By the late 1980s, I saw Murray only very rarely. I heard, though, that through an agent I know, Murray had got a big advance to write a book. Murray always found writing painful, and before long I heard that the book had gone through multiple editors (and publishers), and that Murray thought it responsible for a heart attack he had. I had hoped that the book would be an autobiography, though I suspected that Murray might not have the introspection to produce that. (Several years later, a *New York Times* writer named George Johnson wrote what I considered a very good biography of Murray, which Murray hated.)

But then I heard that Murray’s book was actually going to be about his theory of complexity, whatever that might be. A few years went by, and, eventually, in 1994, to rather modest fanfare, Murray’s book *The Quark and the Jaguar* appeared. Looking through it, though, it didn’t seem to contain anything concrete that could be considered a theory of complexity. George Zweig told me he’d heard that Murray had left people like me and him out of the index to the book, so we’d have to read the whole book if we wanted to find out what he said about us.

At the time, I didn’t bother. But just now, in writing this piece, I was curious to find out what, if anything, Murray actually did say about me. In the printed book, the index goes straight from “Winos” to Woolfenden. But online I can find that there I am, on page 77 (and, bizarrely, I’m also in the online index): “As Stephen Wolfram has emphasized, [a theory] is a compressed package of information, applicable to many cases”. Yes, that’s true, but is that really all Murray got out of everything I told him? (George Zweig, by the way, isn’t mentioned in the book at all.)

In 2002, I’d finally finished my own decade-long basic science project, and I was getting ready to publish my book *A New Kind of Science*. In recognition of his early support, I’d mentioned Murray in my long list of acknowledgements in the book, and I thought I’d reach out to him and see if he’d like to write a back-cover blurb. (In the end, Steve Jobs convinced me not to have any back-cover blurbs: “Isaac Newton didn’t have blurbs on the *Principia*; nor should you on your book”.)

Murray responded politely: “It is exciting to know that your magnum opus, reflecting so much thought, research, and writing, will finally appear. I should, of course, be delighted to receive the book and peruse it, and I might be able to come up with an endorsement, especially since I expect to be impressed”. But he said, “I find it difficult to write things under any conditions, as you probably know”.

I sent Murray the book, and soon thereafter was on the phone with him. It was a strange and contentious conversation. Murray was obviously uncomfortable. I was asking him about what he thought complexity was. He said it was “like a child learning a language”. I asked what that meant. We went back and forth talking about languages. I had the distinct sense that Murray thought he could somehow blind me with facts I didn’t know. But—perhaps unfortunately for the conversation—even though *A New Kind of Science* doesn’t discuss languages much, my long efforts in computational language design had made me quite knowledgeable about the topic, and in the conversation I made it quite clear that I wasn’t convinced about what Murray had to say.

Murray followed up with an email: “It was good to talk with you. I found the exchange of ideas very interesting. We seem to have been thinking about many of the same things over the last few years, and apparently we agree on some of them and have quite divergent views on others”. He talked about the book, saying that “Obviously, I can’t, in a brief perusal, come to any deep conclusions about such an impressive tome. It is clear, however, that there are many ideas in it with which, if I understand them correctly, I disagree”.

Then he continued: “Also, my own work of the last decade or so is not mentioned anywhere, even though that work includes discussions of the meaning and significance of simplicity and complexity, the role of decoherent histories in the understanding of quantum mechanics, and other topics that play important roles in *A New Kind of Science*”. (Actually, I don’t think I discussed anything relevant to decoherent histories in quantum mechanics.) He explained that he didn’t want to write a blurb, and ended: “I’m sorry, and I hope that this matter does not present any threat to our friendship, which I hold dear”.

As it turned out, I never talked to Murray about science again. The last time I saw Murray was in 2012 at a peculiar event in New York City for promising high-school students. I said hello. Murray looked blank. I said my name, and held up my name tag. “Do I know you?”, he said. I repeated my name. Still blank. I couldn’t tell if it was a problem of age—or a repeat of the story of the beta function. But, with regret, I walked away.

I have often used Murray as an example of the challenges of managing the arc of a great career. From his twenties to his forties, Murray had the golden touch. His particular way of thinking had success after success, and in many ways, he defined physics for a generation. But by the time I knew him, the easy successes were over. Perhaps it was Murray; more likely, it was just that the easy pickings from his approach were now gone.

I think Murray always wanted to be respected as a scholar and statesman of science—and beyond. But—to his chagrin—he kept on putting himself in situations that played to his weaknesses. He tried to lead people, but usually ended up annoying them. He tried to become a literary-style author, but his perfectionism and insecurity got in the way. He tried to do important work in new fields, but ended up finding that his particular methods didn’t work there. To me, it felt in many ways tragic. He so wanted to succeed as he had before, but he never found a way to do it—and always bore the burden of his early success.

Still, with all his complexities, I am pleased to have known Murray. And though Murray is now gone, the physics he discovered will live on, defining an important chapter in the quest for our understanding of the fundamental structure of our universe.

]]>It happens far too often. I’ll be talking to a software developer, and they’ll be saying how great they think our technology is, and how it helped them so much in school, or in doing R&D. But then I’ll ask them, “So, are you using Wolfram Language and its computational intelligence in your production software system?” Sometimes the answer is yes. But too often, there’s an awkward silence, and then they’ll say, “Well, no. Could I?”

I want to make sure the answer to this can always be: “Yes, it’s easy!” And to help achieve that, we’re releasing today the Free Wolfram Engine for Developers. It’s a full engine for the Wolfram Language, that can be deployed on any system—and called from programs, languages, web servers, or anything.

The Wolfram Engine is the heart of all our products. It’s what implements the Wolfram Language, with all its computational intelligence, algorithms, knowledgebase, and so on. It’s what powers our desktop products (including Mathematica), as well as our cloud platform. It’s what’s inside Wolfram|Alpha—as well as an increasing number of major production systems out in the world. And as of today, we’re making it available for anyone to download, for free, to use in their software development projects.

Many people know the Wolfram Language (often in the form of Mathematica) as a powerful system for interactive computing—and for doing R&D, education, data science and “computational X” for many X. But increasingly it’s also being used “behind the scenes” as a key component in building production software systems. And what the Free Wolfram Engine for Developers now does is to package it so it’s convenient to insert into a whole range of software engineering environments and projects.

It’s worth explaining a bit about how I see the Wolfram Language these days. (By the way, you can run it immediately on the web in the Wolfram Language Sandbox.) The most important thing is to realize that the Wolfram Language as it now exists is really a new kind of thing: a full-scale computational language. Yes, it’s an extremely powerful and productive (symbolic, functional, …) programming language. But it’s much more than that. Because it’s got the unique feature of having a huge amount of computational knowledge built right into it: knowledge about algorithms, knowledge about the real world, knowledge about how to automate things.

We’ve been steadily building up what’s now the Wolfram Language for more than 30 years—and one thing I’m particularly proud of (though it’s hard work; e.g. check out the livestreams!) is how uniform, elegant and stable a design we’ve been able to maintain across the whole language. There are now altogether 5000+ functions in the language, covering everything from visualization to machine learning, numerics, image computation, geometry, higher math and natural language understanding—as well as lots of areas of real-world knowledge (geo, medical, cultural, engineering, scientific, etc.).

In recent years, we’ve also introduced lots of hardcore software engineering capabilities—instant cloud deployment, network programming, web interaction, database connectivity, import/export (200+ formats), process control, unit testing, report generation, cryptography, blockchain, etc. (The symbolic nature of the language makes these particularly clean and powerful.)

The goal of the Wolfram Language is simple, if ambitious: have everything be right there, in the language, and be as automatic as possible. Need to analyze an image? Need geographic data? Audio processing? Solve an optimization problem? Weather information? Generate 3D geometry? Anatomical data? NLP entity identification? Find anomalies in a time series? Send a mail message? Get a digital signature? All these things (and many, many more) are just functions that you can immediately call in any program you write in Wolfram Language. (There are no libraries to hunt down; everything is just integrated into the language.)

Back on the earliest computers, all one had was machine code. But then came simple programming languages. And soon one could also take it for granted that one’s computer would have an operating system. Later also networking, then a user interface, then web connectivity. My goal with the Wolfram Language is to provide a layer of computational intelligence that in effect encapsulates the computational knowledge of our civilization, and lets people take it for granted that their computer will know how to identify objects in an image, or how to solve equations, or what the populations of cities are, or countless other things.

And now, today, what we want to do with the Free Wolfram Engine for Developers is to make this something ubiquitous, and immediately available to any software developer.

The Free Wolfram Engine for Developers implements the full Wolfram Language as a software component that can immediately be plugged into any standard software engineering stack. It runs on any standard platform (Linux, Mac, Windows, RasPi, …; desktop, server, virtualized, distributed, parallelized, embedded). You can use it directly with a script, or from a command line. You can call it from programming languages (Python, Java, .NET, C/C++, …), or from other systems (Excel, Jupyter, Unity, Rhino, …). You can call it through sockets, ZeroMQ, MQTT or its own native WSTP (Wolfram Symbolic Transfer Protocol). It reads and writes hundreds of formats (CSV, JSON, XML, …), and connects to databases (SQL, RDF/SPARQL, Mongo, …), and can call external programs (executables, libraries, …), browsers, mail servers, APIs, devices, and languages (Python, NodeJS, Java, .NET, R, …). Soon it’ll also plug directly into web servers (J2EE, aiohttp, Django, …). And you can edit and manage your Wolfram Language code with standard IDEs, editors and tools (Eclipse, IntelliJ IDEA, Atom, Vim, Visual Studio Code, Git, …).

The Free Wolfram Engine for Developers has access to the whole Wolfram Knowledgebase, through a free Basic subscription to the Wolfram Cloud. (Unless you want real-time data, everything can be cached, so you can run the Wolfram Engine without network connectivity.) The Basic subscription to the Wolfram Cloud also lets you deploy limited APIs in the cloud.

A key feature of the Wolfram Language is that you can run the exact same code anywhere. You can run it interactively using Wolfram Notebooks—on the desktop, in the cloud, and on mobile. You can run it in a cloud API (or scheduled task, etc.), on the public Wolfram Cloud, or in a Wolfram Enterprise Private Cloud. And now, with the Wolfram Engine, you can also easily run it deep inside any standard software engineering stack.

(Of course, if you want to use our whole hyperarchitecture spanning desktop, server, cloud, parallel, embedded, mobile—and interactive, development and production computing—then a good entry point is Wolfram|One, and, yes, there are trial versions available.)

OK, so how does the licensing for Free Wolfram Engine for Developers work? For the past 30+ years, our company has had a very straightforward model: we license our software to generate revenue that allows us to continue our long-term mission of continuous, energetic R&D. We’ve also made many important things available for free—like our main Wolfram|Alpha website, Wolfram Player and basic access to the Wolfram Cloud.

The Free Wolfram Engine for Developers is intended for use in pre-production software development. You can use it to develop a product for yourself or your company. You can use it to conduct personal projects at home, at school or at work. And you can use it to explore the Wolfram Language for future production projects. (Here’s the actual license, if you’re curious.)

When you have a system ready to go into production, then you get a Production License for the Wolfram Engine. Exactly how that works will depend on what kind of system you’ve built. There are options for local individual or enterprise deployment, for distributing the Wolfram Engine with software or hardware, for deploying in cloud computing platforms—and for deploying in the Wolfram Cloud or Wolfram Enterprise Private Cloud.

If you’re making a free, open-source system, you can apply for a Free Production License. Also, if you’re part of a Wolfram Site License (of the type that, for example, most universities have), then you can freely use Free Wolfram Engine for Developers for anything that license permits.

We haven’t worked out all the corners and details of every possible use of the Wolfram Engine. But we are committed to providing predictable and straightforward licensing for the long term (and we’re working to ensure the availability and vitality of the Wolfram Language in perpetuity, independent of our company). We’ve now had consistent pricing for our products for 30+ years, and we want to stay as far away as possible from the many variants of bait-and-switch which have become all too prevalent in modern software licensing.

I’m very proud of what we’ve created with Wolfram Language, and it’s been wonderful to see all the inventions, discoveries and education that have happened with it over decades. But in recent years there’s been a new frontier: the increasingly widespread use of the Wolfram Language inside large-scale software projects. Sometimes the whole project is built in Wolfram Language. Sometimes Wolfram Language is inserted to add some critical computational intelligence, perhaps even just in a corner of the project.

The goal of the Free Wolfram Engine for Developers is to make it easy for anyone to use the Wolfram Language in any software development project—and to build systems that take advantage of its computational intelligence.

We’ve worked hard to make the Free Wolfram Engine for Developers as easy to use and deploy as possible. But if there’s something that doesn’t work for you or your project, please send me mail! Otherwise, please use what we’ve built—and do something great with it!

]]>Today it’s 10 years since we launched Wolfram|Alpha. At some level, Wolfram|Alpha is a never-ending project. But it’s had a great first 10 years. It was a unique and surprising achievement when it first arrived, and over its first decade it’s become ever stronger and more unique. It’s found its way into more and more of the fabric of the computational world, both realizing some of the long-term aspirations of artificial intelligence, and defining new directions for what one can expect to be possible. Oh, and by now, a significant fraction of a billion people have used it. And we’ve been able to keep it private and independent, and its main website has stayed free and without external advertising.

For me personally, the vision that became Wolfram|Alpha has a very long history. I first imagined creating something like it more than 47 years ago, when I was about 12 years old. Over the years, I built some powerful tools—most importantly the core of what’s now Wolfram Language. But it was only after some discoveries I made in basic science in the 1990s that I felt emboldened to actually try building what’s now Wolfram|Alpha.

It was—and still is—a daunting project. To take all areas of systematic knowledge and make them computable. To make it so that any question that can in principle be answered from knowledge accumulated by our civilization can actually be answered, immediately and automatically.

Leibniz had talked about something like this 350 years ago; Turing 70 years ago. But while science fiction (think the *Star Trek* computer) had imagined it, and AI research had set it as a key goal, 50 years of actual work on question-answering had failed to deliver. And I didn’t know for sure if we were in the right decade—or even the right century—to be able to build what I wanted.

But I decided to try. And it took lots of ideas, lots of engineering, lots of diverse scholarship, and lots of input from experts in a zillion fields. But by late 2008 we’d managed to get Wolfram|Alpha to the point where it was beginning to work. Day by day we were making it stronger. But eventually there was no sense in going further until we could see how people would actually use it.

And so it was that on May 18, 2009, we officially opened Wolfram|Alpha up to the world. And within hours we knew it: Wolfram|Alpha really worked! People asked all kinds of questions, and got successful answers. And it became clear that the paradigm we’d invented of generating synthesized reports from natural language input by using built-in computational knowledge was very powerful, and was just what people needed.

Perhaps because the web interface to Wolfram|Alpha was just a simple input field, some people assumed it was like a search engine, finding content on the web. But Wolfram|Alpha isn’t searching anything; it’s computing custom answers to each particular question it’s asked, using its own built-in computational knowledge—that we’ve spent decades amassing. And indeed, quite soon, it became clear that the vast majority of questions people were asking were ones that simply didn’t have answers already written down anywhere on the web; they were questions whose answers had to be computed, using all those methods and models and algorithms—and all that curated data—that we’d so carefully put into Wolfram|Alpha.

As the years have gone by, Wolfram|Alpha has found its way into intelligent assistants like Siri, and now also Alexa. It’s become part of chatbots, tutoring systems, smart TVs, NASA websites, smart OCR apps, talking (toy) dinosaurs, smart contract oracles, and more. It’s been used by an immense range of people, for all sorts of purposes. Inventors have used it to figure out what might be possible. Leaders and policymakers have used it to make decisions. Professionals have used it to do their jobs every day. People around the world have used it to satisfy their curiosity about all sorts of peculiar things. And countless students have used it to solve problems, and learn.

And in addition to the main, public Wolfram|Alpha, there are now all sorts of custom “enterprise” Wolfram|Alphas operating inside large organizations, answering questions using not only public data and knowledge, but also the internal data and knowledge of those organizations.

It’s fun when I run into high-school and college kids who notice my name and ask “Are you related to Wolfram|Alpha?” “Well”, I say, “actually, I am”. And usually there’s a look of surprise, and a slow dawning of the concept that, yes, Wolfram|Alpha hasn’t always existed: it had to be created, and there was an actual human behind it. And then I often explain that actually I first started thinking about building it a long time ago, when I was even younger than them…

When I started building Wolfram|Alpha I certainly couldn’t prove it would work. But looking back, I realize there were a collection of key things—mostly quite unique to us and our company—that ultimately made it possible. Some were technical, some were conceptual, and some were organizational.

On the technical side, the most important was that we had what was then Mathematica, but is now the Wolfram Language. And by the time we started building Wolfram|Alpha, it was clear that the unique symbolic programming paradigm that we’d invented to be the core of the Wolfram Language was incredibly general and powerful—and could plausibly succeed at the daunting task of providing a way to represent all the computational knowledge in the world.

It also helped a lot that there was so much algorithmic knowledge already built into the system. Need to solve a differential equation to compute a trajectory? Just use the built-in `NDSolve` function! Need to solve a difficult recurrence relation? Just use `RSolve`. Need to simplify a piece of logic? Use `BooleanMinimize`. Need to do the combinatorial optimization of finding the smallest number of coins to give change? Use `FrobeniusSolve`. Need to find out how long to cook a turkey of a certain weight? Use `DSolve`. Need to find the implied volatility of a financial derivative? Use `FinancialDerivative`. And so on.

But what about all that actual data about the world? All the information about cities and movies and food and so on? People might have thought we’d just be able to forage the web for it. But I knew very quickly this wouldn’t work: the data—if it even existed on the web—wouldn’t be systematic and structured enough for us to be able to correctly do actual computations from it, rather than just, for example, displaying it.

So this meant there wouldn’t be any choice but to actually dive in and carefully deal with each different kind of data. And though I didn’t realize it with so much clarity at the time, this is where our company had another extremely rare and absolutely crucial advantage. We’ve always been a very intellectual company (no doubt to our commercial detriment)—and among our staff we, for example, have PhDs in a wide range of subjects, from chemistry to history to neuroscience to architecture to astrophysics. But more than that, among the enthusiastic users of our products we count many of the world’s top researchers across a remarkable diversity of fields.

So when we needed to know about proteins or earthquakes or art history or whatever, it was easy for us to find an expert. At first, I thought the main issue would just be “Where is the best source of the relevant data?” Sometimes that source would be very obvious; sometimes it would be very obscure. (And, yes, it was always fun to run across people who’d excitedly say things like: “Wow, we’ve been collecting this data for decades and nobody’s ever asked for it before!”)

But I soon realized that having raw data was only the beginning; after that came the whole process of understanding it. What units are those quantities in? Does -99 mean that data point is missing? How exactly is that average defined? What is the common name for that? Are those bins mutually exclusive or combined? And so on. It wasn’t just enough to have the data; one also had to have an expert-level dialog with whomever had collected the data.

But then there was another issue: people want answers to questions, not raw data. It’s all well and good to know the orbital parameters for a television satellite, but what most people will actually want to know is where the satellite is in the sky at their location. And to work out something like that requires some method or model or algorithm. And this is where experts were again crucial.

My goal from the beginning was always to get the best research-level results for everything. I didn’t consider it good enough to use the simple formula or the rule of thumb. I wanted to get the best answers that current knowledge could give—whether it was for time to sunburn, pressure in the ocean, mortality curves, tree growth, redshifts in the early universe, or whatever. Of course, the good news was that the Wolfram Language almost always had the built-in algorithmic power to do whatever computations were needed. And it was remarkably common to find that the original research we were using had actually been done with the Wolfram Language.

As we began to develop Wolfram|Alpha we dealt with more and more domains of data, and more and more cross-connections between them. We started building streamlined frameworks for doing this. But one of the continuing features of the Wolfram|Alpha project has been that however good the frameworks are, every new area always seems to involve new and different twists—that can be successfully handled only because we’re ultimately using the Wolfram Language, with all its generality.

Over the years, we’ve developed an elaborate art of data curation. It’s a mixture of automation (these days, often using modern machine learning), management processes, and pure human tender loving care applied to data. I have a principle that there always has to be an expert involved—or you’ll never get the right answer. But it’s always complicated to allocate resources and to communicate correctly across the phases of data curation—and to inject the right level of judgement at the right points. (And, yes, in an effort to make the complexities of the world conveniently amenable to computation, there are inevitably judgement calls involved: “Should the Great Pyramid be considered a building?”, “Should Lassie be considered a notable organism or a fictional character?” “What was the occupation of Joan of Arc?”, and so on.)

When we started building Wolfram|Alpha, there’d already been all sorts of thinking about how large-scale knowledge should best be represented computationally. And there was a sense that—much like logic was seen as somehow universally applicable—so also there should be a universal and systematically structured way to represent knowledge. People had thought about ideas based on set theory, graph theory, predicate logic, and more—and each had had some success.

Meanwhile, I was no stranger to global approaches to things—having just finished a decade of work on my book *A New Kind of Science*, which at some level can be seen as being about the theory of all possible theories. But partly because of the actual science I discovered (particularly the idea of computational irreducibility), and partly because of the general intuition I had developed, I had what I now realize was a crucial insight: there’s not going to be a useful general theory of how to represent knowledge; the best you can ever ultimately do is to think of everything in terms of arbitrary computation.

And the result of this was that when we started developing Wolfram|Alpha, we began by just building up each domain “from its computational roots”. Gradually, we did find and exploit all sorts of powerful commonalities. But it’s been crucial that we’ve never been stuck having to fit all knowledge into a “data ontology graph” or indeed any fixed structure. And that’s a large part of why we’ve successfully been able to make use of all the rich algorithmic knowledge about the world that, for example, the exact sciences have delivered.

Perhaps the most obviously AI-like part of my vision for Wolfram|Alpha was that you should be able to ask it questions purely in natural language. When we started building Wolfram|Alpha there was already a long tradition of text retrieval (from which search engines had emerged), as well as of natural language processing and computational linguistics. But although these all dealt with natural language, they weren’t trying to solve the same problem as Wolfram|Alpha. Because basically they were all taking existing text, and trying to extract from it things one wanted. In Wolfram|Alpha, what we needed was to be able to take questions given in natural language, and somehow really understand them, so we could compute answers to them.

In the past, exactly what it meant for a computer to “understand” something had always been a bit muddled. But what was crucial for the Wolfram|Alpha project was that we were finally in a position to give a useful, practical definition: “understanding” for us meant translating the natural language into precise Wolfram Language. So, for example, if a user entered “What was the gdp of france in 1975?” we wanted to interpret this as the Wolfram Language symbolic expression `Entity["Country", "France"][Dated["GDP", 1975]]`.

And while it was certainly nice to have a precise representation of a question like that, the real kicker was that this representation was immediately computable: we could immediately use it to actually compute an answer.

In the past, a bane of natural language understanding had always been the ambiguity of things like words in natural language. When you say “apple”, do you mean the fruit or the company? When you say “3 o’clock”, do you mean morning or afternoon? On which day? When you say “springfield”, do you mean “Springfield, MA” or one of the 28 other possible Springfield cities?

But somehow, in Wolfram|Alpha this wasn’t such a problem. And it quickly became clear that the reason was that we had something that no previous attempt at natural language understanding had ever had: we had a huge and computable knowledgebase about the world. So “apple” wasn’t just a word for us: we had extensive data about the properties of apples as fruit and Apple as a company. And we could immediately tell that “apple vitamin C” was talking about the fruit, “apple net income” about the company, and so on. And for “Springfield” we had data about the location and population and notoriety of every Springfield. And so on.

It’s an interesting case where things were made easier by solving a much larger problem: we could be successful at natural language understanding because we were also solving the huge problem of having broad and computable knowledge about the world. And also because we had built the whole symbolic language structure of the Wolfram Language.

There were still many issues, however. At first, I’d wondered if traditional grammar and computational linguistics would be useful. But they didn’t apply well to the often-not-very-grammatical inputs people actually gave. And we soon realized that instead, the basic science I’d done in *A New Kind of Science* could be helpful—because it gave a conceptual framework for thinking about the interaction of many different simple rules operating on a piece of natural language.

And so we added the strange new job title of “linguistic curator”, and set about effectively curating the semantic structure of natural language, and creating a practical way to turn natural language into precise Wolfram Language. (And, yes, what we did might shed light on how humans understand language—but we’ve been so busy building technology that we’ve never had a chance to explore this.)

OK, so we can solve the difficult problem of taking natural language and turning it into Wolfram Language. And with great effort we’ve got all sorts of knowledge about the world, and we can compute all kinds of things from it. But given a particular input, what output should we actually generate? Yes, there may be a direct answer to a question (“42”, “yes”, whatever). And in certain circumstances (like voice output) that may be the main thing you want. But particularly when visual display is possible, we quickly discovered that people find richer outputs dramatically more valuable.

And so, in Wolfram|Alpha we use the computational knowledge we have to automatically generate a whole report about the question you asked:

We’ve worked hard on both the structure and content of the information presentation. There’d never been anything quite like it before, so everything had to be invented. At the top, there are sometimes “Assumings” (“Which Springfield did you mean?”, etc.)—though the vast majority of the time, our first choice is correct. We found it worked very well to organize the main output into a series of “pods”, often with graphical or tabular contents. Many of the pods have buttons that allow for drilldown, or alternatives.

Everything is generated programmatically. And which pods are there, with what content, and in what sequence, is the result of lots of algorithms and heuristics—including many that I personally devised. (Along the way, we basically had to invent a whole area of “computational aesthetics”: automatically determining what humans will find aesthetic and easy to interpret.)

In most large software projects, one’s building things to precise specifications. But one of the complexities of Wolfram|Alpha is that so much of what it does is heuristic. There’s no “right answer” to exactly what to plot in a particular pod, over what range. It’s a judgement call. And the overall quality of Wolfram|Alpha directly depends on doing a good job at making a vast number of such judgement calls.

But who should make these judgement calls? It’s not something pure programmers are used to doing. It takes real computational thinking skills, and it also usually takes serious knowledge of each content area. Sometimes similar judgement calls get repeated, and one can just say “do it like that other case”. But given how broad Wolfram|Alpha is, it’s perhaps not surprising that there are an incredible number of different things that come up.

And as we approached the launch of Wolfram|Alpha I found myself making literally hundreds of judgement calls every day. “How many different outputs should we generate here?” “Should we add a footnote here?” “What kind of graphic should we produce in that case?”

In my long-running work on designing Wolfram Language, the goal is to make everything precise and perfect. But for Wolfram|Alpha, the goal is instead just to have it behave as people want—regardless of whether that’s logically perfect. And at first, I worried that with all the somewhat arbitrary judgement calls we were making to achieve that, we’d end up with a system that felt very incoherent and unpredictable. But gradually I came to understand a sort of logic of heuristics, and we developed a good rhythm for inventing heuristics that fit together. And in the end—with a giant network of heuristic algorithms—I think we’ve been very successful at creating a system that broadly just automatically does what people want and expect.

Looking back now, more than a decade after the original development of Wolfram|Alpha, it begins to seem even more surprising—and fortuitous—that the project ended up being possible at all. For it is clear now that it critically relied on a whole collection of technical, conceptual and organizational capabilities that we (and I) happened to have developed by just that time. And had even one of them been missing, it would probably have made the whole project impossible.

But even given the necessary capabilities, there was the matter of actually doing the project. And it certainly took a lot of leadership and tenacity from me—as well as all sorts of specific problem solving—to pursue a project that most people (including many of those working on it) thought, at least at first, was impossible.

How did the project actually get started? Well, basically I just decided one day to do it. And, fortunately, my situation was such that I didn’t really have to ask anyone else about it—and as a launchpad I already had a successful, private company without outside investors that had been running well for more than a decade.

From a standard commercial point of view, most people would have seen the Wolfram|Alpha project as a crazy thing to pursue. It wasn’t even clear it was possible, and it was certainly going to be very difficult and very long term. But I had worked hard to put myself in a position where I could do projects just because I thought they were intellectually valuable and important—and this was one I had wanted to do for decades.

One awkward feature of Wolfram|Alpha as a project is that it didn’t work, until it did. When I tried to give early demos, too little worked, and it was hard to see the point of the whole thing. And this led to lots of skepticism, even by my own management team. So I decided it was best to do the project quietly, without saying much about it. And though it wasn’t my intention, things ramped up to the point where a couple hundred people were working completely under the radar (in our very geographically distributed organization) on the project.

But finally, Wolfram|Alpha really started to work. I gave a demo to my formerly skeptical management team, and by the end of an hour there was uniform enthusiasm, and lots of ideas and suggestions.

And so it was that in the spring of 2009, we prepared to launch Wolfram|Alpha.

On March 4, 2009, the wolframalpha.com domain lit up, with a simple:

On March 5, I posted a short (and, in the light of the past decade, satisfyingly prophetic) blog that began:

We were adding features and fixing bugs at a furious pace. And rack by rack we were building infrastructure to actually support the system (yes, below all those layers of computational intelligence there are ultimately computers with power cables and network connectors and everything else):

At the beginning, we had about 10,000 cores set up to run Wolfram|Alpha (back then, virtualization wasn’t an option for the kind of performance we wanted). But we had no real idea if this would be enough—or what strange things missed by our simulations might happen when real people started using the system.

We could just have planned to put up a message on the site if something went wrong. But I thought it would be more interesting—and helpful—to actually show people what was going on behind the scenes. And so we decided to do something very unusual—and livestream to the internet the process of launching Wolfram|Alpha.

We planned our initial go-live to occur on the evening of Friday, May 15, 2009 (figuring that traffic would be lower on a Friday evening). And we built our version of a “Mission Control” to coordinate everything:

There were plenty of last-minute issues, many of them captured on the livestream. But in classic Mission Control style, each of our teams finally confirmed that we were “go for launch”—and at 9:33:50 pm CT, I pressed the big “Activate” button, and soon all network connections were open, and Wolfram|Alpha was live to the world.

Queries immediately started flowing in from around the world—and within a couple of hours it was clear that the concept of Wolfram|Alpha was a success—and that people found it very useful. It wasn’t long before bugs and suggestions started coming in too. And for a decade we’ve been being told we should give answers about the strangest things (“How many teeth does a snail have?” “How many spiders does the average American eat?” “Which superheroes can hold Thor’s hammer?” “What is the volume of a dog’s eyeball?”).

After our initial go-live on Friday evening, we spent the weekend watching how Wolfram|Alpha was performing (and fixing some hair-raising issues, for example about the routing of traffic to our different colos). And then, on Monday May 18, 2009, we declared Wolfram|Alpha officially launched.

So what’s happened over the past decade? Every second, there’s been new data flowing into Wolfram|Alpha. Weather. Stock prices. Aircraft positions. Earthquakes. Lots and lots more. Some things update only every month or every year (think: government statistics). Other things update when something happens (think: deaths, elections, etc.) Every week, there are administrative divisions that change in some country around the world. And, yes, occasionally there’s even a new official country (actually, only South Sudan in the past decade).

Wolfram|Alpha has got both broader and deeper in the past decade. There are new knowledge domains. About cat breeds, shipwrecks, cars, battles, radio stations, mines, congressional districts, anatomical structures, function spaces, glaciers, board games, mythological entities, yoga poses and many, many more. Of course, the most obvious domains, like countries, cities, movies, chemicals, words, foods, people, materials, airlines and mountains were already present when Wolfram|Alpha first launched. But over the past decade, we’ve dramatically extended the coverage of these.

What a decade ago was a small or fragmentary area of data, we’ve now systematically filled out—often with great effort. 140,000+ new kinds of food. 350,000 new notable people. 170+ new properties about 58,000 public companies. 100+ new properties about species (tail lengths, eye counts, etc.). 1.6 billion new data points from the US Census. Sometimes we’ve found existing data providers to work with, but quite often we’ve had to painstakingly curate the data ourselves.

It’s amazing how much in the world can be made computable if one puts in the effort. Like military conflicts, for example, which required both lots of historical work, and lots of judgement. And with each domain we add, we’ve put more and more effort into ensuring that it connects with other domains (What was the geolocation of the battle? What historical countries were involved? Etc.).

From even before Wolfram|Alpha launched, we had a wish list of domains to add. Some were comparatively easy. Others—like military conflicts or anatomical structures—took many years. Often, we at first thought a domain would be easy, only to discover all sorts of complicated issues (I had no idea how many different categories of model, make, trim, etc. are important for cars, for example).

In earlier years, we did experiments with volunteer and crowd-sourced data collection and curation. And in some specific areas this worked well, like local information from different countries (how do shoe sizes work in country X?), and properties of fictional characters (who were Batman’s parents?). But as we’ve built out more sophisticated tools, with more automation—as well as tuning our processes for making judgement calls—it’s become much more difficult for outside talent to be effective.

For years, we’ve been the world’s most prolific reporter of bugs in data sources. But with so much computable data about so many things, as well as so many models about how things work, we’re now in an absolutely unique position to validate, cross-check data—and use the latest machine learning to discover patterns and detect anomalies.

Of course, data is just one part of the Wolfram|Alpha story. Because Wolfram|Alpha is also full of algorithms—both precise and heuristic—for computing all kinds of things. And over the past decade, we’ve added all sorts of new algorithms, based on recent advances in science. We’ve also been able to steadily polish what we have, covering all those awkward corner cases (“Are angle units really dimensionless or not?”, “What is the country code of a satphone?”, and so on).

One of the big unknowns when we first launched Wolfram|Alpha was how people would interact with it, and what forms of linguistic input they would give. Many billions of queries later, we know a lot about that. We know a thousand ways to ask how much wood a woodchuck can chuck, etc. We know all the bizarre variants people use to specify even simple arithmetic with units. Every day we collect the “fallthroughs”—inputs we didn’t understand. And for a decade now we’ve been steadily extending our knowledgebase and our natural language understanding system to address them.

Ever since we first launched what’s now the Wolfram Language 30+ years ago, we’ve supported things that would now be called machine learning. But over the past decade, we’ve also become leaders in modern neural nets and deep learning. And in some specific situations, we’ve now been able to make good use of this technology in Wolfram|Alpha.

But there’s been no magic bullet, and I don’t expect one. If one wants to get data that’s systematically computable, one can’t forage it from the web, even with the finest modern machine learning. One can use machine learning to make suggestions in the data curation pipeline, but in the end, if you want to get the right answer, you need a human expert who can exercise judgement based on the accumulated knowledge of a field. (And, yes, the same is true of good training sets for many machine learning tasks.)

In the natural language understanding we need to do for Wolfram|Alpha, machine learning can sometimes help, especially in speeding things up. But if one wants to be certain about the symbolic interpretation of natural language, then—a bit like for doing arithmetic—to get good reliability and efficiency there’s basically no choice but to use the systematic algorithmic approach that we’ve been developing for many years.

Something else that’s advanced a lot since Wolfram|Alpha was launched is our ability to handle complex questions that combine many kinds of knowledge and computation. To do this has required several things. It’s needed more systematically computable data, with consistent structure across domains. It’s needed an underlying data infrastructure that can handle more complex queries. And it’s needed the ability to handle more sophisticated linguistics. None of these have been easy—but they’ve all steadily advanced.

By this point, Wolfram|Alpha is one of the more complex pieces of software and data engineering that exists in the world. It helps that it’s basically all written in Wolfram Language. But over time, different parts have outgrown the frameworks we originally built for them. And an important thing we’ve done over the past decade is to take what we’ve learned from all our experience, and use it to systematically build a sequence of more efficient and more general frameworks. (And, yes, it’s never easy refactoring a large software system, but the high-level symbolic character of the Wolfram Language helps a lot.)

There’s always new development going on in the Wolfram|Alpha codebase—and in fact we normally redeploy a new version every two weeks. Wolfram|Alpha is a very complex system to test. Partly that’s because what it does is so diverse. Partly that’s because the world it’s trying to represent is a complex place. And partly it’s because human language usage is so profoundly non-modular. (“3 chains” is probably—at least for now—a length measurement, “2 chains” is probably a misspelling of a rapper, and so on.)

What should Wolfram|Alpha know about? My goal has always been to have it eventually know about everything. But obviously one’s got to start somewhere. And when we were first building Wolfram|Alpha we started with what we thought were the “most obvious” areas. Of course, once Wolfram|Alpha was launched, the huge stream of actual questions that people ask have defined a giant to-do list, which we’ve steadily been working through, now for a decade.

When Wolfram|Alpha gets used in a new environment, new kinds of questions come up. Sometimes they don’t make sense (like “Where did I put my keys?” asked of Wolfram|Alpha on a phone). But often they do. Like asking Wolfram|Alpha on a device in a kitchen “Can dogs eat avocado?”. (And, yes, we try to give the best answer current science can provide.)

But I have to admit that, particularly before we launched Wolfram|Alpha, I was personally one of our main sources of “we should know about this” input. I collected reference books, seeing what kinds of things they covered. Wherever I went, I looked for informational posters to see what was on them. And whenever I wondered about pretty much anything, I’d try to see how we could compute about it.

“How long will it take me to read this document?” “What country does that license plate come from?” “What height percentile are my kids at?” “How big is a typical 50-year-old oak tree?” “How long can I stay in the sun today?” “What planes are overhead now?” And on and on. Thousands upon thousands of different kinds of questions.

Often we’d be contacting world experts on different, obscure topics—always trying to get definitive computational knowledge about everything. Sometimes it’d seem as if we’d gone quite overboard, working out details nobody would ever possibly care about. But then we’d see people using those details, and sometimes we’d hear “Oh, yes, I use it every day; I don’t know anyplace else to get this right”. (I’ve sometimes thought that if Wolfram|Alpha had been out before 2008, and people could have seen our simulations, they wouldn’t have been caught with so many adjustable-rate mortgages.)

And, yes, it’s a little disappointing when one realizes that some fascinating piece of computational knowledge that took considerable effort to get right in Wolfram|Alpha will—with current usage patterns—probably only be used a few times in a century. But I view the Wolfram|Alpha project in no small part as a long-term effort to encapsulate the knowledge of our civilization, regardless of whether any of it happens to be popular right now.

So even if few people make queries about caves or cemeteries or ocean zones right now, or want to know about different types of paper, or custom screw threads, or acoustic absorption in different materials, I’m glad we’ve got all these things in Wolfram|Alpha. Because now it’s computational knowledge, that can be used by anyone, anytime in the future.

We’ve put—and continue to put—an immense amount of effort into developing and running Wolfram|Alpha. So how do we manage to support doing that? What’s the business model?

The main Wolfram|Alpha website is simply free for everyone. Why? Because we want it to be that way. We want to democratize computational knowledge, and let anyone anywhere use what we’ve built.

Of course, we hope that people who use the Wolfram|Alpha website will want to buy other things we make. But on the website itself there’s simply no “catch”: we’re not monetizing anything. We’re not running external ads; we’re not selling user data; we’re just keeping everything completely private, and always have.

But obviously there are ways in which we are monetizing Wolfram|Alpha—otherwise we wouldn’t be able to do everything we’re doing. At the simplest level, there are subscription-based Pro versions on the website that have extra features of particular interest to students and professionals. There’s a Wolfram|Alpha app that has extra features optimized for mobile devices. There are also about 50 specialized apps (most for both mobile and web) that support more structured access to Wolfram|Alpha, convenient for students taking courses, hobbyists with particular interests, and professionals with standard workflows they repeatedly follow.

Then there are Wolfram|Alpha APIs—which are widely licensed by companies large and small (there’s a free tier for hobbyists and developers). There are multiple different APIs. Some are optimized for spoken results, some for back-and-forth conversation, some for visual display, and so on. Sometimes the API is used for some very specific purpose (calculus, particular socioeconomic data, tide computations, whatever). But more often it’s just set up to take any natural language query that arrives. (These days, specialized APIs are actually usually better built directly with Wolfram Language, as I’ll discuss a bit later.) Most of the time, the Wolfram|Alpha API runs on our servers, but some of our largest customers have private versions running inside their infrastructure.

When people access Wolfram|Alpha from different parts of the world, we automatically use local conventions for things like units, currency and so on. But when we first built Wolfram|Alpha we fundamentally did it for English language only. I always believed, though, that the methods for natural language understanding that we invented would work for other languages too, despite all their differences in structure. And it turns out that they do.

Each language is a lot of work, though. Even the best automated translation helps only a little; to get reliable results one has to actually build up a new algorithmic structure for each language. But that’s only the beginning. There’s also the issue of automatic natural language generation for output. And then there’s localized data relevant for the countries that use a particular language.

But we’re gradually working on building versions of Wolfram|Alpha for other languages. Nearly five years ago we actually built a full Wolfram|Alpha for Chinese—but, sadly, regulatory issues in China have so far prevented us from deploying it there. Recently we released a version for Japanese (right now set up to handle mainly student-oriented queries). And we’ve got versions for five other languages in various stages of completion (though we’ll typically need local partners to deploy them properly).

Beyond Wolfram|Alpha on the public web, there are also private versions of Wolfram|Alpha. In the simplest case, a private Wolfram|Alpha is just a copy of the public Wolfram|Alpha, but running inside a particular organization’s infrastructure. Data updates flow into the private Wolfram|Alpha from the outside, but no queries for the private Wolfram|Alpha ever need to leave the organization.

Ordinary Wolfram|Alpha deals with public computational knowledge. But the technology of Wolfram|Alpha can also be applied to private data in an organization. And in recent years an important part of the business story of Wolfram|Alpha is what we call Enterprise Wolfram|Alpha: custom versions of Wolfram|Alpha that answer questions using both public computational knowledge, and private knowledge inside an organization.

For years I’ve run into CEOs who look at Wolfram|Alpha and say, “I wish I could do that kind of thing with my corporate data; it’d be so much easier for my company to make decisions…” Well, that’s what Enterprise Wolfram|Alpha is for. And over the past several years we’ve been installing Enterprise Wolfram|Alpha in some of the world’s largest companies in all sorts of industries, from healthcare to financial services, retail, and so on.

For a few years now, there’s been a lot of talk (and advertising) about the potential for “applying AI in the enterprise”. But I think it’s fair to say that with Enterprise Wolfram|Alpha we’ve got a serious, enterprise use of AI up and running right now—delivering very successful results.

The typical pattern is that you ask a question in natural language, and Enterprise Wolfram|Alpha then generates a report about the answer, using a mixture of public and private knowledge. “What were our sales of foo-pluses in Europe between Christmas and New Year?” Enterprise Wolfram|Alpha has public knowledge about what dates we’re talking about, and what Europe is. But then it’s got to figure out the internal linguistics of what foo-pluses are, and then go query an internal sales database about how many were sold. Finally, it’s got to generate a report that gives the answer (perhaps both the number of units and dollar amount), as well as, probably, a breakdown by country (perhaps normalized by GDP), comparisons to previous years, maybe a time series of sales by day, and so on.

Needless to say, there’s plenty of subtlety in getting a useful result. Like what the definition of Europe is. Or the fact that Christmas (and New Year’s) can be on different dates in different cultures (and, of course, Wolfram|Alpha has all the necessary data and algorithms). Oh, and then one has to start worrying about currency conversion rates (which of course Wolfram|Alpha has)—as well as about conventions about conversion dates that some particular company may use.

Like any sophisticated piece of enterprise software, Enterprise Wolfram|Alpha has to be configured for each particular customer, and we have a business unit called Wolfram Solutions that does that. The goal is always to map the knowledge in an organization to a clear symbolic Wolfram Language form, so it becomes computable in the Wolfram|Alpha system. Realistically, for a large organization, it’s a lot of work. But the good news is that it’s possible—because Wolfram Solutions gets to use the whole curation and algorithm pipeline that we’ve developed for Wolfram|Alpha.

Of course, we can use all the algorithmic capabilities of the Wolfram Language too. So if we have to handle textual data we’re ready with the latest NLP tools, or if we want to be able to make predictions we’re ready with the latest statistics and machine learning, and so on.

Businesses started routinely putting their data onto computers more than half a century ago. But now across pretty much every industry, more acutely than ever, the challenge is to actually use that data in meaningful ways. Eventually everyone will take for granted that they can just ask about their data, like on *Star Trek*. But the point is that with Enterprise Wolfram|Alpha we have the technology to finally make this possible.

It’s a very successful application of Wolfram|Alpha technology, and the business potential for it is amazing. But for us the main limiting factor is that as a business it’s so different from the rest of what we do. Our company is very much focused on R&D—but Enterprise Wolfram|Alpha requires a large-scale customer-facing organization, like a typical enterprise software company. (And, yes, we’re exploring working with partners for this, but setting up such things has proved to be a slow process!)

By the way, people sometimes seem to think that the big opportunity for AI in the enterprise is in dealing with unstructured corporate data (such as free-form text), and finding “needles in haystacks” there. But what we’ve consistently seen is that in typical enterprises most of their data is actually stored in very structured databases. And the challenge, instead, is to answer unstructured queries.

In the past, it’s been basically impossible to do this in anything other than very simple ways. But now we can see why: because you basically need the whole Wolfram|Alpha technology stack to be able to do it. You need natural language understanding, you need computational knowledge, you need automated report generation, and so on. But that’s what Enterprise Wolfram|Alpha has. And so it’s finally able to solve this problem.

But what does it mean? It’s a little bit like when we first introduced Mathematica 30+ years ago. Before then, a typical scientist wouldn’t expect to use a computer themselves for a computation: they’d delegate it to an expert. But one of the great achievements of Mathematica is that it made things easy enough that scientists could actually compute for themselves. And so, similarly, typical executives in companies don’t directly compute answers themselves; instead, they ask their IT department to do it—then hope the results they get back a week later makes sense. But the point is that with Enterprise Wolfram|Alpha, executives can actually get questions answered themselves, immediately. And the consequences of that for making decisions are pretty spectacular.

The Wolfram Language is what made Wolfram|Alpha possible. But over the past decade Wolfram|Alpha has also given back big time to Wolfram Language, delivering both knowledgebase and natural language understanding.

It’s interesting to compare Wolfram|Alpha and Wolfram Language. Wolfram|Alpha is for quick computations, specified in a completely unstructured way using natural language, and generating as output reports intended for human consumption. Wolfram Language, on the other hand, is a precise symbolic language intended for building up arbitrarily complex computations—in a way that can be systematically understood by computers and humans.

One of the central features of the Wolfram Language is that it can deal not only with abstract computational constructs, but also with things in the real world, like cities and chemicals. But how should one specify these real-world things? Documentation listing the appropriate way to specify every city wouldn’t be practical or useful. But what Wolfram|Alpha provided was a way to specify real-world things, using natural language.

Inside Wolfram|Alpha, natural language input is translated to Wolfram Language. And that’s what’s now exposed in the Wolfram Language, and in Wolfram Notebooks. Type + = and a piece of natural language (like “LA”). The output—courtesy of Wolfram|Alpha natural language understanding technology—is a symbolic entity representing Los Angeles. And that symbolic entity is then a precise object that the Wolfram Language can use in computations.

I didn’t particularly anticipate it, but this interplay between the do-it-however-you-want approach of Wolfram|Alpha and the precise symbolic approach of the Wolfram Language is exceptionally powerful. It gets the best of both worlds—and it’s an important element in allowing the Wolfram Language to assume its unique position as a full-scale computational language.

What about the knowledgebase of Wolfram|Alpha, and all the data it contains? Over the past decade we’ve spent immense effort fully integrating more and more of this into the Wolfram Language. It’s always difficult to get data to the point where it’s computable enough to use in Wolfram|Alpha—but it’s even more difficult to make it fully and systematically computable in the way that’s needed for the Wolfram Language.

Imagine you’re dealing with data about oceans. To make it useful for Wolfram|Alpha you have to get it to the point where if someone asks about a specific named ocean, you can systematically retrieve or compute properties of that ocean. But to make it useful for Wolfram Language, you have to get it to the point where someone can do computations about all oceans, with none missing.

A while ago I invented a 10-step hierarchy of data curation. For data to work in Wolfram|Alpha, you have to get it to level 9 in the hierarchy. But to get it to work in Wolfram Language, you have to get it all the way to level 10. And if it takes a few months to get some data to level 9, it can easily take another year to get it to level 10.

So it’s been a big achievement that over the past decade we’ve managed to get the vast majority of the Wolfram|Alpha knowledgebase up to the level where it can be directly used in the Wolfram Language. So all that data is now not only good enough for human consumption, but also good enough that one can systematically build up computations using it.

All the integration with the Wolfram Language means it’s in some sense now possible to “implement Wolfram|Alpha” in a single line of Wolfram Language code. But it also means that it’s easy to make Wolfram Language instant APIs that do more specific Wolfram|Alpha-like things.

There’s an increasing amount of interconnection between Wolfram|Alpha and Wolfram Language. For example, on the Wolfram|Alpha website most output pods have an “Open Code” button, which opens a Wolfram Notebook in the Wolfram Cloud, with Wolfram Language input that corresponds to what was computed in that pod.

In other words, you can use results from Wolfram|Alpha to “seed” a Wolfram Notebook, in which you can then edit or add inputs do a complete, multi-step Wolfram Language computation. (By the way, you can always generate full Wolfram|Alpha output inside a Wolfram Notebook too.)

When Wolfram|Alpha first launched nobody had seen anything like it. A decade later, people have learned to take some aspects of it for granted, and have gotten used to having it available in things like intelligent assistants. But what will the future of Wolfram|Alpha now be?

Over the past decade we’ve progressively strengthened essentially everything about Wolfram|Alpha—to the point where it’s now excellently positioned for steady long-term growth in future decades. But with Wolfram|Alpha as it exists today, we’re now also in a position to start attacking all sorts of major new directions. And—important as what Wolfram|Alpha has achieved in its first decade has been—I suspect that in time it will be dwarfed by what comes next.

A decade ago, nobody had heard of “fake news”. Today, it’s ubiquitous. But I’m proud that Wolfram|Alpha stands as a beacon of accurate knowledge. And it’s not just knowledge that humans can use; it’s knowledge that’s computable, and suitable for computers too.

More and more is being done these days with computational contracts—both on blockchains and elsewhere. And one of the central things such contracts require is a way to know what’s actually happened in the world—or, in other words, a systematic source of computational facts.

But that’s exactly what Wolfram|Alpha uniquely provides. And already the Wolfram|Alpha API has become the *de facto* standard for computational facts. But one’s going to see a lot more of Wolfram|Alpha here in the future.

It’s going to put increasing pressure on the reliability of the computational knowledge in Wolfram|Alpha. Because it won’t be long before there will routinely be whole chains of computational contracts—that do important things in the world—and that trigger as soon as Wolfram|Alpha has delivered some particular fact on which they depend.

We’ve developed all sorts of procedures to validate facts. Some are automated—and depend on “theorems” that must be true about data, or cross-correlations or statistical regularities that should exist. Others ultimately rely on human judgement. (A macabre example is our obituary feed: we automatically detect news reports about deaths of people in our knowledgebase. These are then passed to our 24/7 site monitors, who confirm, or escalate the judgement call if needed. Somehow I’m on the distribution list for confirmation requests—and over the past decade there’ve been far too many times when this is how I’ve learned that someone I know has died.)

We take our responsibility as the world’s source of computational facts very seriously, and we’re planning more and more ways to add checks and balances—needless to say, defining what we’re doing using computational contracts.

When we first started developing Wolfram|Alpha, nobody was talking about computational contracts (though, to be fair, I had already thought about them as a potential application of my computational ideas). But now it turns out that Wolfram|Alpha is central to what can be done with them. And as a core component in the long history of the development of systematic knowledge, I think it’s inevitable that over time there will be all sorts of important uses of Wolfram|Alpha that we can’t yet foresee.

In the early days of artificial intelligence, much of what people imagined AI would be like is basically what Wolfram|Alpha has now delivered. So what can now be done with this?

We can certainly put “general knowledge AI” everywhere. Not just in phones and cars and televisions and smart speakers, but also in augmented reality and head- and ear-mounted devices and many other places too.

One of the Wolfram|Alpha APIs we provide is a “conversational” one, that can go back and forth clarifying and extending questions. But what about a full Wolfram|Alpha Turing test–like bot? Even after all these years, general-purpose bots have tended to be disappointing. And if one just connects Wolfram|Alpha to them, there tends to be quite a mismatch between general bot responses and “smart facts” from Wolfram|Alpha. (And, yes, in a Turing test competition, the presence of Wolfram|Alpha is a dead giveaway—because it knows much more than any human would.) But with progress in my symbolic discourse language–and probably some modern machine learning—I suspect it’ll be possible to make a more successful general-purpose bot that’s more integrated with Wolfram|Alpha.

But what I think is critical in many future applications of Wolfram|Alpha is to have additional sources of data and input. If one’s making a personal intelligent assistant, for example, then one wants to give it access to as much personal history data (messages, sensor data, video, etc.) as possible. (We already did early experiments on this back in 2011 with Facebook data.)

Then one can use Wolfram|Alpha to ask questions not only about the world in general, but also about one’s own interaction with it, and one’s own history. One can ask those questions explicitly with natural language—or one can imagine, for example, preemptively delivering answers based on video or some other aspect of one’s current environment.

Beyond personal uses, there are also organizational and enterprise ones. And indeed we already have Enterprise Wolfram|Alpha—making use of data inside organizations. So far, we’ve been building Enterprise Wolfram|Alpha systems mainly for some of the world’s largest companies—and every system has been unique and extensively customized. But in time—especially as we deal with smaller organizations that have more commonality within a particular industry—I expect that we’ll be able to make Enterprise Wolfram|Alpha systems that are much more turnkey, effectively by curating the possible structures of businesses and their IT systems.

And, to be clear, the potential here is huge. Because basically every organization in the world is today collecting data. And Enterprise Wolfram|Alpha will provide a realistic way for anyone in an organization to ask questions about their data, and make decisions based on it.

There are so many sources of data for Wolfram|Alpha that one can imagine. It could be photographs from drones or satellites. It could be video feeds. It could be sensor data from industrial equipment or robots. It could be telemetry from inside a game or a virtual world (like from our new UnityLink). It could be the results of a simulation of some system (say in Wolfram SystemModeler). But in all cases, one can expect to use the technology of Wolfram|Alpha to provide answers to free-form questions.

One can think of Wolfram|Alpha as enabling a kind of AI-powered human interface. And one can imagine using it not only to ask questions about existing data, but also as a way to control things, and to get actions taken. We’ve done experiments with Wolfram|Alpha-based interfaces to complex software systems. But one could as well do this with consumer devices, industrial systems, or basically anything that can be controlled through a connection to a computer.

Not everything is best done with pure Wolfram|Alpha—or with something like natural language. Many things are better done with the full computational language that we have in the Wolfram Language. But when we’re using this language, we’re of course still using the Wolfram|Alpha technology stack.

Wolfram|Alpha is already well on its way to being a ubiquitous presence in the computational infrastructure of the world. And between its direct use, and its use in Wolfram Language, I think we can expect that in the future we’ll all end up routinely encountering Wolfram|Alphas all the time.

For many decades our company—and I—have been single-mindedly pursuing the goal of realizing the potential of computation and the computational paradigm. And in doing this, I think we’ve built a very unique organization, with very unique capabilities.

And looking back a decade after the launch of Wolfram|Alpha, I think it’s no surprise that Wolfram|Alpha has such a unique place in the world. It is, in a sense, the kind of thing that our company is uniquely built to create and develop.

I’ve wanted Wolfram|Alpha for nearly 50 years. And it’s tremendously satisfying to have been able to create what I think will be a defining intellectual edifice in the long history of systematic knowledge. It’s been a good first decade for Wolfram|Alpha. And I begin its second decade with great enthusiasm for the future and for everything that can be done with Wolfram|Alpha.

Happy 10th birthday, Wolfram|Alpha.

]]>I’ve sometimes found it a bit of a struggle to explain what the Wolfram Language really is. Yes, it’s a computer language—a programming language. And it does—in a uniquely productive way, I might add—what standard programming languages do. But that’s only a very small part of the story. And what I’ve finally come to realize is that one should actually think of the Wolfram Language as an entirely different—and new—kind of thing: what one can call a *computational language*.

So what is a computational language? It’s a language for expressing things in a computational way—and for capturing computational ways of thinking about things. It’s not just a language for telling computers what to do. It’s a language that both computers and humans can use to represent computational ways of thinking about things. It’s a language that puts into concrete form a computational view of everything. It’s a language that lets one use the computational paradigm as a framework for formulating and organizing one’s thoughts.

It’s only recently that I’ve begun to properly internalize just how broad the implications of having a computational language really are—even though, ironically, I’ve spent much of my life engaged precisely in the consuming task of building the world’s only large-scale computational language.

It helps me to think about a historical analog. Five hundred years ago, if people wanted to talk about mathematical ideas and operations, they basically had to use human natural language, essentially writing out everything in terms of words. But the invention of mathematical notation about 400 years ago (starting with +, ×, =, etc.) changed all that—and began to provide a systematic structure and framework for representing mathematical ideas.

The consequences were surprisingly dramatic. Because basically it was this development that made modern forms of mathematical thinking (like algebra and calculus) feasible—and that launched the mathematical way of thinking about the world as we know it, with all the science and technology that’s come from it.

Well, I think it’s a similar story with computational language. But now what’s happening is that we’re getting a systematic way to represent—and talk about—computational ideas, and the computational way of thinking about the world. With standard programming languages, we’ve had a way to talk about the low-level operation of computers. But with computational language, we now have a way to apply the computational paradigm directly to almost anything: we have a language and a notation for doing computational X, for basically any field “X” (from archaeology to zoology, and beyond).

There’ve been some “mathematical X” fields for a while, where typically the point is to formulate things in terms of traditional mathematical constructs (like equations), that can then “mechanically” be solved (at least, say, with Mathematica!). But a great realization of the past few decades has been that the computational paradigm is much broader: much more can be represented computationally than just mathematically.

Sometimes one’s dealing with very simple abstract programs (and, indeed, I’ve spent years exploring the science of the computational universe of such programs). But often one’s interested in operations and entities that relate to our direct experience of the world. But the crucial point here is that—as we’ve learned in building the Wolfram Language—it’s possible to represent such things in a computational way. In other words, it’s possible to have a computational language that can talk about the world—in computational terms.

And that’s what’s needed to really launch all those possible “computational X” fields.

Let’s say we want to talk about planets. In the Wolfram Language, planets are just symbolic entities:

✕
EntityList[EntityClass["Planet", All]] |

We can compute things about them (here, the mass of Jupiter divided by the mass of Earth):

✕
Entity["Planet", "Jupiter"]["Mass"]/Entity["Planet", "Earth"]["Mass"] |

Let’s make an image collage in which the mass of each planet determines how big it’s shown:

✕
ImageCollage[ EntityClass["Planet", All]["Mass"] -> EntityClass["Planet", All]["Image"]] |

To talk about the real world in computational terms, you have to be able to compute things about it. Like here, the Wolfram Language is computing the current position (as I write this) of the planet Mars:

✕
Entity["Planet", "Mars"][EntityProperty["Planet", "HelioCoordinates"]] |

And here it’s making a 3D plot of a table of its positions for each of the next 18 months from now:

✕
ListPointPlot3D[Table[ Entity["Planet", "Mars"][ Dated[EntityProperty["Planet", "HelioCoordinates"], Now + Quantity[n, "Months"]]], {n, 18}]] |

Let’s do another example. Take an image, and find the human faces in it:

✕
FacialFeatures[CloudGet["https://wolfr.am/DpadWvjE"], "Image"] |

As another example of computation-meets-the-real-world, we can make a histogram (say, in 5-year bins) of the estimated ages of people in the picture:

✕
Histogram[ FacialFeatures[CloudGet["https://wolfr.am/DpadWvjE"], "Age"], {5}] |

It’s amazing what ends up being computable. Here are rasterized images of each letter of the Greek alphabet distributed in “visual feature space”:

✕
FeatureSpacePlot[Rasterize /@ Alphabet["Greek"]] |

Yes, it is (I think) impressive what the Wolfram Language can do. But what’s more important here is to see how it lets one specify what to do. Because this is where computational language is at work—giving us a way to talk computationally about planets and human faces and visual feature spaces.

Of course, once we’ve formulated something in computational language, we’re in a position (thanks to the whole knowledgebase and algorithmbase of the Wolfram Language) to actually do a computation about it. And, needless to say, this is extremely powerful. But what’s also extremely powerful is that the computational language itself gives us a way to formulate things in computational terms.

Let’s say we want to know how efficient the Roman numeral system was. How do we formulate that question computationally? We might think about knowing the string lengths of Roman numerals, and comparing them to the lengths of modern integers. It’s easy to express that in Wolfram Language. Here’s a Roman numeral:

✕
RomanNumeral[188] |

And here’s its string length:

✕
StringLength[RomanNumeral[188]] |

Now here’s a plot of all Roman numeral lengths up to 200, divided by the corresponding integer lengths—with callouts automatically showing notable values:

✕
ListLinePlot[Table[ Callout[StringLength[RomanNumeral[n]]/IntegerLength[n], n], {n, 200}]] |

It’s easy enough to make a histogram for all numbers up to 1000:

✕
Histogram[Table[ StringLength[RomanNumeral[n]]/IntegerLength[n], {n, 1000}]] |

But of course in actual usage, some numbers are more common than others. So how can we capture that? Well, here’s one (rather naive) computational approach. Let’s just analyze the Wikipedia article about arithmetic, and see what integers it mentions. Again, that computational concept is easy to express in the Wolfram Language: finding cases of numbers in the article, then selecting those that are interpreted as integers:

✕
Select[IntegerQ][ TextCases[WikipediaData["arithmetic"], "Number" -> "Interpretation"]] |

There are some big numbers, with Roman-numeral representations for which the notion of “string length” doesn’t make much sense:

✕
RomanNumeral[7485696] |

And then there’s 0, for which the Romans didn’t have an explicit representation. But restricting to “Roman-stringable” numbers, we can make our histogram again:

✕
Histogram[ Map[StringLength[RomanNumeral[#]]/IntegerLength[#] &][ Select[IntegerQ[#] && 0 < # < 5000 &][ TextCases[WikipediaData["arithmetic"], "Number" -> "Interpretation"]]]] |

And what’s crucial here is that—with Wolfram Language—we’re in a position to formulate our thinking in terms of computational concepts, like `StringLength` and `TextCases` and `Select` and `Histogram`. And we’re able to use the computational language to express our computational thinking—in a way that humans can read, and the computer can compute from.

As a practical matter, the examples of computational language we’ve just seen look pretty different from anything one would normally do with a standard programming language. But what is the fundamental difference between a computational language and a programming language?

First and foremost, it’s that a computational language tries to intrinsically be able to talk about whatever one might think about in a computational way—while a programming language is set up to intrinsically talk only about things one can directly program a computer to do. So for example, a computational language can intrinsically talk about things in the real world—like the planet Mars or New York City or a chocolate chip cookie. A programming language can intrinsically talk only about abstract data structures in a computer.

Inevitably, a computational language has to be vastly bigger and richer than a programming language. Because while a programming language just has to know about the operation of a computer, a computational language tries to know about everything—with as much knowledge and computational intelligence as possible about the world and about computation built into it.

To be fair, the Wolfram Language is the sole example that exists of a full-scale computational language. But one gets a sense of magnitude from it. While the core of a standard programming language typically has perhaps a few tens of primitive functions built in, the Wolfram Language has more than 5600—with many of those individually representing major pieces of computational intelligence. And in its effort to be able to talk about the real world, the Wolfram Language also has millions of entities of all sorts built into it. And, yes, the Wolfram Language has had more than three decades of energetic, continuous development put into it.

Given a programming language, one can of course start programming things. And indeed many standard programming languages have all sorts of libraries of functions that have been created for them. But the objective of these libraries is not really the same as the objective of a true computational language. Yes, they’re providing specific “functions to call”. But they’re not trying to create a way to represent or talk about a broad range of computational ideas. To do that requires a coherent computational language—of the kind I’ve been building in the Wolfram Language all these years.

A programming language is (needless to say) intended as something in which to write programs. And while it’s usually considered desirable for humans to be able—at least at some level—to read the programs, the ultimate point is to provide a way to tell a computer what to do. But computational language can also achieve something else. Because it can serve as an expressive medium for communicating computational ideas to humans as well as to computers.

Even when one’s dealing with abstract algorithms, it’s common with standard programming languages to want to talk in terms of some kind of “pseudocode” that lets one describe the algorithms without becoming enmeshed in the (often fiddly) details of actual implementation. But part of the idea of computational language is always to have a way to express computational ideas directly in the language: to have the high-level expressiveness and readability of pseudocode, while still having everything be precise, complete and immediately executable on a computer.

Looking at the examples above, one thing that’s immediately obvious is that having the computational language be symbolic is critical. In most standard programming languages, `x` on its own without a value doesn’t mean anything; it has to stand for some structure in the memory of the computer. But in a computational language, one’s got to be able to have things that are purely symbolic, and that represent, for example, entities in the real world—that one can operate on just like any other kind of data.

There’s a whole cascade of wonderful unifications that flow from representing everything as a symbolic expression, crucial in being able to coherently build up a full-scale computational language. And to make a computational language as readily absorbable by humans as possible, there are also all sorts of detailed issues of interface—like having hierarchically structured notebooks, allowing details of computational language to be iconized for display, and so on.

Particularly in this age of machine learning one might wonder why one would need a precisely defined computational language at all. Why not just use natural language for everything?

Wolfram|Alpha provides a good example (indeed, probably the most sophisticated one that exists today) of what can be done purely with natural language. And indeed for the kinds of short questions that Wolfram|Alpha normally handles, it proves that natural language can work quite well.

But what if one wants to build up something more complicated? Just like in the case of doing mathematics without notation, it quickly becomes impractical. And I could see this particularly clearly when I was writing an introductory book on the Wolfram Language—and trying to create exercises for it. The typical form of an exercise is: “Take this thing described in natural language, and implement it in Wolfram Language”. Early in the book, this worked OK. But as soon as things got more complicated, it became quite frustrating. Because I’d immediately know what I wanted to say in Wolfram Language, but it took a lot of effort to express it in natural language for the exercise, and often what I came up with was hard to read and reminiscent of legalese.

One could imagine that with enough back-and-forth, one might be able to explain things to a computer purely in natural language. But to get any kind of clear idea of what the computer has understood, one needs some more structured representation—which is precisely what computational language provides.

And it’s certainly no coincidence that the way Wolfram|Alpha works is first to translate whatever natural language input it’s given to precise Wolfram Language—and only then to compute answers from it.

In a sense, using computational language is what lets us leverage the last few centuries of exact science and systematic knowledge. Earlier in history, one imagined that one could reason about everything just using words and natural language. But three or four centuries ago—particularly with mathematical notation and other mathematical ideas—it became clear that one could go much further if one had a structured, formal way of talking about the world. And computational language now extends that—bringing a much wider range of things into the domain of formal computational thinking, and going still further beyond natural language.

Of course, one argument for trying to use natural language is that “everybody already knows it”. But the whole point is to be able to apply computational thinking—and to do that systematically, one needs a new way of expressing oneself, which is exactly what computational language provides.

Computational language is something quite different from natural language, but in its construction it still uses natural language and people’s understanding of it. Because in a sense the “words” in the computational language are based on words in natural language. So, for example, in the Wolfram Language, we have functions like `StringLength`, `TextCases` and `FeatureSpacePlot`.

Each of these functions has a precise computational definition. But to help people understand and remember what the functions do, we use (very carefully chosen) natural language words in their names. In a sense, we’re leveraging people’s understanding of natural language to be able to create a higher level of language. (By the way, with our “code captions” mechanism, we’re able to at least annotate everything in lots of natural languages beyond English.)

It’s a slightly different story when it comes to the zillions of real-world entities that a computational language has to deal with. For a function like `TextCases`, you both have to know what it’s called, and how to use it. But for an entity like New York City, you just have to somehow get hold of it—and then it’s going to work the same as any other entity. And a convenient way to get hold of it is just to ask for it, by whatever (natural language) name you know for it.

For example, in the Wolfram Language you can just use a “free-form input box”. Type `nyc` and it’ll get interpreted as the official New York City entity:

✕
\!\(\*NamespaceBox["LinguisticAssistant", DynamicModuleBox[{Typeset`query$$ = "nyc", Typeset`boxes$$ = TemplateBox[{"\"New York City\"", RowBox[{"Entity", "[", RowBox[{"\"City\"", ",", RowBox[{"{", RowBox[{"\"NewYork\"", ",", "\"NewYork\"", ",", "\"UnitedStates\""}], "}"}]}], "]"}], "\"Entity[\\\"City\\\", {\\\"NewYork\\\", \\\"NewYork\\\", \ \\\"UnitedStates\\\"}]\"", "\"city\""}, "Entity"], Typeset`allassumptions$$ = {{"type" -> "Clash", "word" -> "nyc", "template" -> "Assuming \"${word}\" is ${desc1}. Use as ${desc2} instead", "count" -> "2", "Values" -> {{"name" -> "City", "desc" -> "a city", "input" -> "*C.nyc-_*City-"}, {"name" -> "VisualArts", "desc" -> "a photograph", "input" -> "*C.nyc-_*VisualArts-"}}}}, Typeset`assumptions$$ = {}, Typeset`open$$ = {1, 2}, Typeset`querystate$$ = {"Online" -> True, "Allowed" -> True, "mparse.jsp" -> 0.274794`5.890552239367699, "Messages" -> {}}}, DynamicBox[ ToBoxes[AlphaIntegration`LinguisticAssistantBoxes["", 4, Automatic, Dynamic[Typeset`query$$], Dynamic[Typeset`boxes$$], Dynamic[Typeset`allassumptions$$], Dynamic[Typeset`assumptions$$], Dynamic[Typeset`open$$], Dynamic[Typeset`querystate$$]], StandardForm], ImageSizeCache -> {173., {7., 15.}}, TrackedSymbols :> {Typeset`query$$, Typeset`boxes$$, Typeset`allassumptions$$, Typeset`assumptions$$, Typeset`open$$, Typeset`querystate$$}], DynamicModuleValues :> {}, UndoTrackedVariables :> {Typeset`open$$}], BaseStyle -> {"Deploy"}, DeleteWithContents -> True, Editable -> False, SelectWithContents -> True]\) |

You can use this entity to do computations:

✕
GeoArea[\!\(\*NamespaceBox["LinguisticAssistant", DynamicModuleBox[{Typeset`query$$ = "nyc", Typeset`boxes$$ = TemplateBox[{"\"New York City\"", RowBox[{"Entity", "[", RowBox[{"\"City\"", ",", RowBox[{"{", RowBox[{"\"NewYork\"", ",", "\"NewYork\"", ",", "\"UnitedStates\""}], "}"}]}], "]"}], "\"Entity[\\\"City\\\", {\\\"NewYork\\\", \\\"NewYork\\\", \ \\\"UnitedStates\\\"}]\"", "\"city\""}, "Entity"], Typeset`allassumptions$$ = {{"type" -> "Clash", "word" -> "nyc", "template" -> "Assuming \"${word}\" is ${desc1}. Use as ${desc2} instead", "count" -> "2", "Values" -> {{"name" -> "City", "desc" -> "a city", "input" -> "*C.nyc-_*City-"}, {"name" -> "VisualArts", "desc" -> "a photograph", "input" -> "*C.nyc-_*VisualArts-"}}}}, Typeset`assumptions$$ = {}, Typeset`open$$ = {1, 2}, Typeset`querystate$$ = {"Online" -> True, "Allowed" -> True, "mparse.jsp" -> 0.274794`5.890552239367699, "Messages" -> {}}}, DynamicBox[ ToBoxes[AlphaIntegration`LinguisticAssistantBoxes["", 4, Automatic, Dynamic[Typeset`query$$], Dynamic[Typeset`boxes$$], Dynamic[Typeset`allassumptions$$], Dynamic[Typeset`assumptions$$], Dynamic[Typeset`open$$], Dynamic[Typeset`querystate$$]], StandardForm], ImageSizeCache -> {173., {7., 15.}}, TrackedSymbols :> {Typeset`query$$, Typeset`boxes$$, Typeset`allassumptions$$, Typeset`assumptions$$, Typeset`open$$, Typeset`querystate$$}], DynamicModuleValues :> {}, UndoTrackedVariables :> {Typeset`open$$}], BaseStyle -> {"Deploy"}, DeleteWithContents -> True, Editable -> False, SelectWithContents -> True]\)] |

Of course, this kind of free-form input can be ambiguous. Type `ny` and the first interpretation is New York state:

✕
\!\(\*NamespaceBox["LinguisticAssistant", DynamicModuleBox[{Typeset`query$$ = "ny", Typeset`boxes$$ = TemplateBox[{"\"New York, United States\"", RowBox[{"Entity", "[", RowBox[{"\"AdministrativeDivision\"", ",", RowBox[{"{", RowBox[{"\"NewYork\"", ",", "\"UnitedStates\""}], "}"}]}], "]"}], "\"Entity[\\\"AdministrativeDivision\\\", {\\\"NewYork\\\", \ \\\"UnitedStates\\\"}]\"", "\"administrative division\""}, "Entity"], Typeset`allassumptions$$ = {{"type" -> "Clash", "word" -> "ny", "template" -> "Assuming \"${word}\" is ${desc1}. Use as ${desc2} instead", "count" -> "2", "Values" -> {{"name" -> "USState", "desc" -> "a US state", "input" -> "*C.ny-_*USState-"}, {"name" -> "City", "desc" -> "a city", "input" -> "*C.ny-_*City-"}}}}, Typeset`assumptions$$ = {}, Typeset`open$$ = {1, 2}, Typeset`querystate$$ = {"Online" -> True, "Allowed" -> True, "mparse.jsp" -> 0.321865`5.9592187470275455, "Messages" -> {}}}, DynamicBox[ ToBoxes[AlphaIntegration`LinguisticAssistantBoxes["", 4, Automatic, Dynamic[Typeset`query$$], Dynamic[Typeset`boxes$$], Dynamic[Typeset`allassumptions$$], Dynamic[Typeset`assumptions$$], Dynamic[Typeset`open$$], Dynamic[Typeset`querystate$$]], StandardForm], ImageSizeCache -> {333., {7., 15.}}, TrackedSymbols :> {Typeset`query$$, Typeset`boxes$$, Typeset`allassumptions$$, Typeset`assumptions$$, Typeset`open$$, Typeset`querystate$$}], DynamicModuleValues :> {}, UndoTrackedVariables :> {Typeset`open$$}], BaseStyle -> {"Deploy"}, DeleteWithContents -> True, Editable -> False, SelectWithContents -> True]\) |

Press the little dots and you get to say you want New York City instead:

✕
\!\(\*NamespaceBox["LinguisticAssistant", DynamicModuleBox[{Typeset`query$$ = "nyc", Typeset`boxes$$ = TemplateBox[{"\"New York City\"", RowBox[{"Entity", "[", RowBox[{"\"City\"", ",", RowBox[{"{", RowBox[{"\"NewYork\"", ",", "\"NewYork\"", ",", "\"UnitedStates\""}], "}"}]}], "]"}], "\"Entity[\\\"City\\\", {\\\"NewYork\\\", \\\"NewYork\\\", \ \\\"UnitedStates\\\"}]\"", "\"city\""}, "Entity"], Typeset`allassumptions$$ = {{"type" -> "Clash", "word" -> "nyc", "template" -> "Assuming \"${word}\" is ${desc1}. Use as ${desc2} instead", "count" -> "2", "Values" -> {{"name" -> "City", "desc" -> "a city", "input" -> "*C.nyc-_*City-"}, {"name" -> "VisualArts", "desc" -> "a photograph", "input" -> "*C.nyc-_*VisualArts-"}}}}, Typeset`assumptions$$ = {}, Typeset`open$$ = {1, 2}, Typeset`querystate$$ = {"Online" -> True, "Allowed" -> True, "mparse.jsp" -> 0.274794`5.890552239367699, "Messages" -> {}}}, DynamicBox[ ToBoxes[AlphaIntegration`LinguisticAssistantBoxes["", 4, Automatic, Dynamic[Typeset`query$$], Dynamic[Typeset`boxes$$], Dynamic[Typeset`allassumptions$$], Dynamic[Typeset`assumptions$$], Dynamic[Typeset`open$$], Dynamic[Typeset`querystate$$]], StandardForm], ImageSizeCache -> {173., {7., 15.}}, TrackedSymbols :> {Typeset`query$$, Typeset`boxes$$, Typeset`allassumptions$$, Typeset`assumptions$$, Typeset`open$$, Typeset`querystate$$}], DynamicModuleValues :> {}, UndoTrackedVariables :> {Typeset`open$$}], BaseStyle -> {"Deploy"}, DeleteWithContents -> True, Editable -> False, SelectWithContents -> True]\) |

For convenience, the inputs here are natural language. But the outputs—sometimes after a bit of disambiguation—are precise computational language, ready to be used wherever one wants.

And in general, it’s very powerful to be able to use natural language to specify small chunks of computational language. To express large-scale computational thinking, one needs the formality and structure of computational language. But “small utterances” can be given in natural language—like in Wolfram|Alpha—then translated to precise computational language:

✕
\!\(\*NamespaceBox["LinguisticAssistant", DynamicModuleBox[{Typeset`query$$ = "population of nyc", Typeset`boxes$$ = RowBox[{TemplateBox[{"\"New York City\"", RowBox[{"Entity", "[", RowBox[{"\"City\"", ",", RowBox[{"{", RowBox[{"\"NewYork\"", ",", "\"NewYork\"", ",", "\"UnitedStates\""}], "}"}]}], "]"}], "\"Entity[\\\"City\\\", {\\\"NewYork\\\", \\\"NewYork\\\", \ \\\"UnitedStates\\\"}]\"", "\"city\""}, "Entity"], "[", TemplateBox[{"\"city population\"", RowBox[{"EntityProperty", "[", RowBox[{"\"City\"", ",", "\"Population\""}], "]"}], "\"EntityProperty[\\\"City\\\", \\\"Population\\\"]\""}, "EntityProperty"], "]"}], Typeset`allassumptions$$ = {}, Typeset`assumptions$$ = {}, Typeset`open$$ = {1, 2}, Typeset`querystate$$ = {"Online" -> True, "Allowed" -> True, "mparse.jsp" -> 0.701535`6.297594336611864, "Messages" -> {}}}, DynamicBox[ ToBoxes[AlphaIntegration`LinguisticAssistantBoxes["", 4, Automatic, Dynamic[Typeset`query$$], Dynamic[Typeset`boxes$$], Dynamic[Typeset`allassumptions$$], Dynamic[Typeset`assumptions$$], Dynamic[Typeset`open$$], Dynamic[Typeset`querystate$$]], StandardForm], ImageSizeCache -> {291., {11., 18.}}, TrackedSymbols :> {Typeset`query$$, Typeset`boxes$$, Typeset`allassumptions$$, Typeset`assumptions$$, Typeset`open$$, Typeset`querystate$$}], DynamicModuleValues :> {}, UndoTrackedVariables :> {Typeset`open$$}], BaseStyle -> {"Deploy"}, DeleteWithContents -> True, Editable -> False, SelectWithContents -> True]\) |

✕
EntityClass[ "City", {EntityProperty["City", "Population"] -> TakeLargest[5]}] // EntityList |

✕
Plot[Cos[x], {x, -6.6, 6.6}, PlotStyle -> Purple] |

I think by now there’s little doubt the introduction of the computational paradigm is the single most important intellectual development of the past century. And going forward, I think computational language is going to be crucial in being able to broadly make use of that paradigm—much as many centuries ago, mathematical notation was crucial to launching the widespread use of the mathematical paradigm.

How should one express and communicate the ideas of a “computational X” field? Blobs of low-level programming language code won’t do it. Instead, one needs something that can talk directly about things in the field—whether they are genes, animals, words, battles or whatever. And one also needs something that humans can readily read and understand. And this is precisely what computational language can provide.

Of course, computational language also has the giant bonus that computers can understand it, and that it can be used to specify actual computations to do. In other words, by being able to express something in computational language, you’re not only finding a good way to communicate it to humans, you’re also setting up something that can leverage the power of actual computation to automatically produce things.

And I suspect that in time it will become clear that the existence of computational language as a communication medium is what ultimately succeeded in launching a huge range of computational X fields. Because it’s what will allow the ideas in these fields to be put in a concrete form that people can think in terms of.

How will the computational language be presented? Often, I suspect, it will be part of what I call computational essays. A computational essay mixes natural language text with computational language—and with the outputs of actual computations described by the computational language. It’s a little like how for the past couple of centuries, technical papers have typically relied on mixing text and formulas.

But a computational essay is something much more powerful. For one thing, people can not only read the computational language in a computational essay, but they can also immediately reuse it elsewhere. In addition, when one writes a computational essay, it’s a computer-assisted activity, in which one shares the load with the computer. The human has to write the text and the computational language, but then the computer can automatically generate all kinds of results, infographics, etc. as described by the computational language.

In practice it’s important that computational essays can be presented in Wolfram Notebooks, in the cloud and on the desktop, and that these notebooks can contain all sorts of dynamic and computational elements.

One can expect to use computational essays for a wide range of things—whether papers, reports, exercises or whatever. And I suspect that computational essays, written with computational language, will become the primary form of communication for computational X fields.

I doubt we can yet foresee even a fraction of the places where computational language will be crucial. But one place that’s already clear is in defining computational contracts. In the past, contracts have basically always been written in natural language—or at least in the variant that is legalese. But computational language provides an alternative.

With the Wolfram Language as it is today, we can’t cover everything in every contract. But it’s already clear how we can use computational language to represent many kinds of things in the world that are the subject of contracts. And the point is that with computational language we can write a precise contract that both humans and machines can understand.

In time there’ll be computational contracts everywhere: for commerce, for defining goals, for AI ethics, and so on. And computational language is what will make them all possible.

When literacy in natural language began to become widespread perhaps 500 years ago, it led to sweeping changes in how the world could be organized, and in the development of civilization. In time I think it’s inevitable that there’ll also be widespread literacy in computational language. Certainly that will lead to much broader application of computational thinking (and, for example, the development of many “computational X” fields). And just as our world today is full of written natural language, so in the future we can expect that there will be computational language everywhere—that both defines a way for us humans to think in computational terms, and provides a bridge between human thinking and the computation that machines and AIs can do.

I’ve talked a lot about the general concept of computational language. But in the world today, there’s actually only one example that exists of a full-scale computational language: the Wolfram Language. At first, it might seem strange that one could say this so categorically. With all the technology out there in the world, how could something be that unique?

But it is. And I suppose this becomes a little less surprising when one realizes that we’ve been working on the Wolfram Language for well over thirty years—or more than half of the whole history of modern computing. And indeed, the span of time over which we’ve been able to consistently pursue the development of the Wolfram Language is now longer than for almost any other software system in history.

Did I foresee the emergence of the Wolfram Language as a full computational language? Not entirely. When I first started developing what’s now the Wolfram Language I wanted to make it as general as possible—and as flexible in representing computational ideas and processes.

At first, its most concrete applications were to mathematics, and to various kinds of modeling. But as time went on, I realized that more and more types of things could fit into the computational framework that we’d defined. And gradually this started to include things in the real world. Then, about a decade and a half ago, I realized that, yes, with the whole symbolic language we’d defined, we could just start systematically representing all those things like cities and chemicals in pretty much the same way as we’d represented abstract things before.

I’d always had the goal of putting as much knowledge as possible into the language, and of automating as much as possible. But from the beginning I made sure that the language was based on a small set of principles—and that as it grew it maintained a coherent and unified design.

Needless to say, this wasn’t easy. And indeed it’s been my daily activity now for more than 30 years (with, for example, 300+ hours of it livestreamed over the past year). It’s a difficult process, involving both deep understanding of every area the language covers, as well as a string of complicated judgement calls. But it’s the coherence of design that this achieves that has allowed the language to maintain its unity even as it has grown to encompass all sorts of knowledge about the real world, as well as all those other things that make it a full computational language.

Part of what’s made the Wolfram Language possible is the success of its principles and basic framework. But to actually develop it has also involved the creation of a huge tower of technology and content—and the invention of countless algorithms and meta-algorithms, as well as the acquisition and curation of immense amounts of data.

It’s been a strange mixture of intellectual scholarship and large-scale engineering—that we’ve been fortunate enough to be able to consistently pursue for decades. In many ways, this has been a personal mission of mine. And along the way, people have often asked me how to pigeonhole what we’re building. Is it a calculation system? Is it an encyclopedia-like collection of data? Is it a programming language?

Well, it’s all of those things. But they’re only part of the story. And as the Wolfram Language has developed, it’s become increasingly clear how far away it is from existing categories. And it’s only quite recently that I’ve finally come to understand what it is we’ve managed to build: the world’s only full computational language. Having understood this, it starts to be easier to see just how what we’ve been doing all these years fits into the arc of intellectual history, and what some of its implications might be going forward.

From a practical point of view, it’s great to be able to respond to that obvious basic question: “What is the Wolfram Language?” Because now we have a clear answer: “It’s a computational language!” And, yes, that’s very important!

]]>*This is an edited transcript of a recent talk** I gave at a blockchain conference, where I said I’d talk about “What will the world be like when computational intelligence and computational contracts are ubiquitous?”*

We live in an interesting time today—a time when we’re just beginning to see the implications of what we might call “the force of computation”. In the end, it’s something that’s going to affect almost everything. And what’s going to happen is really a deep story about the interplay between the human condition, the achievements of human civilization—and the fundamental nature of this thing we call computation.

So what is computation? Well, it’s what happens when you follow rules, or what we call programs. Now of course there are plenty of programs that we humans have written to do particular things. But what about programs in general—programs in the abstract? Well, there’s an infinite universe of possible programs out there. And many years ago I turned my analog of a telescope towards that computational universe. And this is what I saw:

✕
GraphicsGrid[ Partition[ Table[ArrayPlot[CellularAutomaton[n, {{1}, 0}, {30, All}], ImageSize -> 40], {n, 0, 255}], 16]] |

Each box represents a different simple program. And often they just do something simple. But look more carefully. There’s a big surprise. This is the first example I saw—rule 30:

✕
ArrayPlot[CellularAutomaton[30, {{1}, 0}, {300, All}], PixelConstrained -> 1] RulePlot[CellularAutomaton[30]] |

You start from one cell, and you just follow that simple program—but here’s what you get: all that complexity. At first it’s hard to believe that you can get so much from so little. But seeing this changed my whole worldview, and made me realize just how powerful the force of computation is.

Because that’s what’s making all that complexity. And that’s what lets nature—seemingly so effortlessly—make the complexity it does. It’s also what allows something like mathematics to have the richness it does. And it provides the raw material for everything it’s possible for us humans to do.

Now the fact is that we’re only just starting to tap the full force of computation. And actually, most of the things we do today—as well as the technology we build—are specifically set up to avoid it. Because we think we have to make sure that everything stays simple enough that we can always foresee what’s going to happen.

But to take advantage of all that power out there in the computational universe, we’ve got to go beyond that. So here’s the issue: there are things we humans want to do—and then there’s all that capability out there in the computational universe. So how do we bring them together?

Well, actually, I’ve spent a good part of my life trying to solve that—and I think the key is what I call computational language. And, yes, there’s only basically one full computational language that exists in the world today—and it’s the one I’ve spent the past three decades building—the Wolfram Language.

Traditional computer languages—“programming languages”—are designed to tell computers what to do, in essentially the native terms that computers use. But the idea of a computational language is instead to take the kind of things we humans think about, and then have a way to express them computationally. We need a computational language to be able to talk not just about data types and data structures in a computer, but also about real things that exist in our world, as well as the intellectual frameworks we use to discuss them.

And with a computational language, we have not only a way to help us formulate our computational thinking, but also a way to communicate to a computer on our terms.

I think the arrival of computational language is something really important. There’s some analog of it in the arrival of mathematical notation 400 or so years ago—that’s what allowed math to take off, and in many ways launched our modern technical world. There’s also some analog in the whole idea of written language—which launched so many things about the way our world is set up.

But, you know, if we look at history, probably the single strongest systematic trend is the advance of technology. That over time there’s more and more that we’ve been able to automate. And with computation that’s dramatically accelerating. And in the end, in some sense, we’ll be able to automate almost everything. But there’s still something that can’t be automated: the question of what we want to do.

It’s the pattern of technology today, and it’s going to increasingly be the pattern of technology in the future: we humans define what we want to do—we set up goals—and then technology, as efficiently as possible, tries to do what we want. Of course, a critical part of this is explaining what we want. And that’s where computational language is crucial: because it’s what allows us to translate our thinking to something that can be executed automatically by computation. In effect, it’s a bridge between our patterns of thinking, and the force of computation.

Let me say something practical about computational language for a moment. Back at the dawn of the computer industry, we were just dealing with raw computers programmed in machine code. But soon there started to be low-level programming languages, then we started to be able to take it for granted that our computers would have operating systems, then user interfaces, and so on.

Well, one of my goals is to make computational intelligence also something that’s ubiquitous. So that when you walk up to your computer you can take for granted that it will have the knowledge—the intelligence—of our civilization built into it. That it will immediately know facts about the world, and be able to use the achievements of science and other areas of human knowledge to work things out.

Obviously with Wolfram Language and Wolfram|Alpha and so on we’ve built a lot of this. And you can even often use human natural language to do things like ask questions. But if you really want to build up anything at all sophisticated, you need a more systematic way to express yourself, and that’s where computational language—and the Wolfram Language—is critical.

OK, well, here’s an important use case: computational contracts. In today’s world, we’re typically writing contracts in natural language, or actually in something a little more precise: legalese. But what if we could write our contracts in computational language? Then they could always be as precise as we want them to be. But there’s something else: they can be executed automatically, and autonomously. Oh, as well as being verifiable, and simulatable, and so on.

Computational contracts are something more general than typical blockchain smart contracts. Because by their nature they can talk about the real world. They don’t just involve the motion of cryptocurrency; they involve data and sensors and actuators. They involve turning questions of human judgement into machine learning classifiers. And in the end, I think they’ll basically be what run our world.

Right now, most of what the computers in the world do is to execute tasks we basically initiate. But increasingly our world is going to involve computers autonomously interacting with each other, according to computational contracts. Once something happens in the world—some computational fact is established—we’ll quickly see cascades of computational contracts executing. And there’ll be all sorts of complicated intrinsic randomness in the interactions of different computational acts.

In a sense, what we’ll have is a whole AI civilization. With its own activities, and history, and memories. And the computational contracts are in effect the laws of the AI civilization. We’ll probably want to have a kind of AI constitution, that defines how generally we want the AIs to act.

Not everyone or every country will want the same one. But we’ll often want to say things like “be nice to humans”. But how do we say that? Well, we’ll have to use a computational language. Will we end up with some tiny statement—some golden rule—that will just achieve everything we want? The complexity of human systems of laws doesn’t make that seem likely. And actually, with what we know about computation, we can see that it’s theoretically impossible.

Because, basically, it’s inevitable that there will be unintended consequences—corner cases, or bugs, or whatever. And there’ll be an infinite hierarchy of patches one needs to apply—a bit like what we see in human laws.

You know, I keep on talking about computers and AIs doing computation. But actually, computation is a more general thing. It’s what you get by following any set of rules. They could be rules for a computer program. But they could also be rules, say, for some technological system, or some system in nature.

Think about all those programs out in the computational universe. In detail, they’re all doing different things. But how do they compare? Is there some whole hierarchy of who’s more powerful than whom? Well, it turns out that the computational universe is a very egalitarian place—because of something I discovered called the Principle of Computational Equivalence.

Because what this principle says is that all programs whose behavior is not obviously simple are actually equivalent in the sophistication of the computations they do. It doesn’t matter if your rules are very simple or very complicated: there’s no difference in the sophistication of the computations that get done.

It’s been more than 80 years since the idea of universal computation was established: that it’s possible to have a fixed machine that can be programmed to do any possible computation. And obviously that’s been an important idea—because it’s what launched the software industry, and much of current technology.

But the Principle of Computational Equivalence says something more: it says that not only is something like universal computation possible, it’s ubiquitous. Out in the computational universe of possible programs many achieve it, even very simple ones, like rule 30. And, yes, in practice that means we can expect to make computers out of much simpler—say molecular—components than we might ever have imagined. And it means that all sorts of even rather simple software systems can be universal—and can’t be guaranteed secure.

But there’s a more fundamental consequence: the phenomenon of computational irreducibility. Being able to predict stuff is a big thing, for example in traditional science-oriented thinking. But if you’re going to predict what a computational system—say rule 30—is going to do, what it means is that somehow you have to be smarter than it is. But the Principle of Computational Equivalence says that’s not possible. Whether it’s a computer or a brain or anything else, it’s doing computations that have exactly the same sophistication.

So it can’t outrun the actual system itself. The behavior of the system is computationally irreducible: there’s no way to find out what it will do except in effect by explicitly running or watching it. You know, I came up with the idea of computational irreducibility in the early 1980s, and I’ve thought a lot about its applications in science, in understanding phenomena like free will, and so on. But I never would have guessed that it would find an application in proof-of-work for blockchains, and that measurable fractions of the world’s computers would be spending their time purposefully grinding computational irreducibility.

By the way, it’s computational irreducibility that means you’ll always have unintended consequences, and you won’t be able to have things like a simple and complete AI constitution. But it’s also computational irreducibility that in a sense means that history is significant: that there’s something irreducible achieved by the course of history.

You know, so far in history we’ve only really had one example of what we’re comfortable calling “intelligence”—and that’s human intelligence. But something the Principle of Computational Equivalence implies is that actually there are lots of things that are computationally just as sophisticated. There’s AI that we purposefully build. But then there are also things like the weather. Yes, we might say in some animistic way “the weather has a mind of its own”. But what the Principle of Computational Equivalence implies is that in some real sense it does: that the hydrodynamic processes in the atmosphere are just as sophisticated as anything going on in our brains.

And when we look out into the cosmos, there are endless examples of sophisticated computation—that we really can’t distinguish from “extraterrestrial intelligence”. The only difference is that—like with the weather—it’s just computation going on. There’s no alignment with human purposes. Of course, that’s a slippery business. Is that graffiti on the blockchain put there on purpose? Or is it just the result of some computational process?

That’s why computational language is important: it provides a bridge between raw computation and human thinking. If we look inside a typical modern neural net, it’s very hard to understand what it does. Same with the intermediate steps of an automated proof of a theorem. The issue is that there’s no “human story” that can be told about what’s going on there. It’s computation, alright. But—a bit like the weather—it’s not computation that’s connected to human experience.

It’s a bit of a complicated thing, though. Because when things get familiar, they do end up seeming human. We invent words for common phenomena in the weather, and then we can effectively use them to tell stories about what’s going on. I’ve spent much of my life as a computational language designer. And in a sense the essence of language design is to identify what common lumps of computational work there are, that one can make into primitives in the language.

And it’s sort of a circular thing. Once one’s developed a particular primitive—a particular abstraction—one then finds that one can start thinking in terms of it. And then the things one builds end up being based on it. It’s the same with human natural language. There was a time when the word “table” wasn’t there. So people had to start describing things with flat surfaces, and legs, and so on. But eventually this abstraction of a “table” appeared. And once it did, it started to get incorporated into the environment people built for themselves.

It’s a common story. In mathematics there are an infinite number of possible theorems. But the ones people study are ones that are reached by creating some general abstraction and then progressively building on it. When it comes to computation, there’s a lot that happens in the computational universe—just like there’s a lot that happens in the physical universe—that we don’t have a way to connect to.

It’s like the AIs are going off and leading their own existence, and we don’t know what’s going on. But that’s the importance of computational language, and computational contracts. They’re what let us connect the AIs with what we humans understand and care about.

Let’s talk a little about the more distant future. Given the Principle of Computational Equivalence I have to believe that our minds—our consciousness—can perfectly well be represented in purely digital form. So, OK, at some point the future of our civilization might be basically a trillion souls in a box. There’ll be a complicated mixing of the alien intelligence of AI with the future of human intelligence.

But here’s the terrible thing: looked at from the outside, those trillion souls that are our future will just be doing computations—and from the Principle of Computational Equivalence, those computations won’t be any more sophisticated than the computations that happen, say, with all these electrons running around inside a rock. The difference, though, is that the computations in the box are in a sense *our* computations; they’re computations that are connected to our characteristics and our purposes.

At some level, it seems like a bad outcome if the future of our civilization is a trillion disembodied souls basically playing videogames for the rest of eternity. But human purposes evolve. I mean, if you tried to explain to someone from a thousand years ago why today we might walk on a treadmill, we’d find it pretty difficult. And I think the good news is that at any time in history, what’s happening then can seem completely meaningful at that time.

The Principle of Computational Equivalence tells us that in a sense computation is ubiquitous. Right now the computation we define exists mostly in the computers we’ve built. But in time, I expect we won’t just *have* computers: everything will basically be *made of* computers. A bit like a generalization of how it works with biological life, every object and every material will be made of components that do computations we’ve somehow defined.

But the pressure again is on how we do that definition. Physics gives some basic rules. But we get to say more than that. And it’s computational language that makes what we say be meaningful to us humans.

In the much nearer term, there’s a very important transition: the point at which literacy in computational language becomes truly commonplace. It’s been great with the Wolfram Language that we can now give kids a way to actually do computational thinking for real. It’s great that we can now have computational essays where people get to express themselves in a mixture of natural language and computational language.

But what will be possible with this? In a sense, human language was what launched civilization. What will computational language do? We can rethink almost everything: democracy that works by having everyone write a computational essay about what they want, that’s then fed to a big central AI—which inevitably has all the standard problems of political philosophy. New ways to think about what it means to do science, or to know things. Ways to organize and understand the civilization of the AIs.

A big part of this is going to start with computational contracts and the idea of autonomous computation—a kind of strange merger of the world of natural law, human law, and computational law. Something anticipated three centuries ago by people like Leibniz—but finally becoming real today. Finally a world run with code.

]]>Today we’re releasing Version 12 of Wolfram Language (and Mathematica) on desktop platforms, and in the Wolfram Cloud. We released Version 11.0 in August 2016, 11.1 in March 2017, 11.2 in September 2017 and 11.3 in March 2018. It’s a big jump from Version 11.3 to Version 12.0. Altogether there are 278 completely new functions, in perhaps 103 areas, together with thousands of different updates across the system:

In an “integer release” like 12, our goal is to provide fully-filled-out new areas of functionality. But in every release we also want to deliver the latest results of our R&D efforts. In 12.0, perhaps half of our new functions can be thought of as finishing areas that were started in previous “.1” releases—while half begin new areas. I’ll discuss both types of functions in this piece, but I’ll be particularly emphasizing the specifics of what’s new in going from 11.3 to 12.0.

I must say that now that 12.0 is finished, I’m amazed at how much is in it, and how much we’ve added since 11.3. In my keynote at our Wolfram Technology Conference last October I summarized what we had up to that point—and even that took nearly 4 hours. Now there’s even more.

What we’ve been able to do is a testament both to the strength of our R&D effort, and to the effectiveness of the Wolfram Language as a development environment. Both these things have of course been building for three decades. But one thing that’s new with 12.0 is that we’ve been letting people watch our behind-the-scenes design process—livestreaming more than 300 hours of my internal design meetings. So in addition to everything else, I suspect this makes Version 12.0 the very first major software release in history that’s been open in this way.

OK, so what’s new in 12.0? There are some big and surprising things—notably in chemistry, geometry, numerical uncertainty and database integration. But overall, there are lots of things in lots of areas—and in fact even the basic summary of them in the Documentation Center is already 19 pages long:

Although nowadays the vast majority of what the Wolfram Language (and Mathematica) does isn’t what’s usually considered math, we still put immense R&D effort into pushing the frontiers of what can be done in math. And as a first example of what we’ve added in 12.0, here’s the rather colorful `ComplexPlot3D`:

✕
ComplexPlot3D[Gamma[z],{z,-4-4I,4+4I}] |

It’s always been possible to write Wolfram Language code to make plots in the complex plane. But only now have we solved the math and algorithm problems that are needed to automate the process of robustly plotting even quite pathological functions in the complex plane.

Years ago I remember painstakingly plotting the dilogarithm function, with its real and imaginary parts. Now `ReImPlot` just does it:

✕
ReImPlot[PolyLog[2, x], {x, -4, 4}] |

The visualization of complex functions is (pun aside) a complex story, with details making a big difference in what one notices about a function. And so one of the things we’ve done in 12.0 is to introduce carefully selected standardized ways (such as named color functions) to highlight different features:

✕
ComplexPlot[(z^2+1)/(z^2-1),{z,-2-2I,2+2I},ColorFunction->"CyclicLogAbsArg"] |

Measurements in the real world often have uncertainty that gets represented as values with ± errors. We’ve had add-on packages for handling “numbers with errors” for ages. But in Version 12.0 we’re building in computation with uncertainty, and we’re doing it right.

The key is the symbolic object `Around[ x, δ]`, which represents a value “around

✕
Around[7.1,.25] |

You can do arithmetic with `Around`, and there’s a whole calculus for how the uncertainties combine:

✕
Sqrt[Around[7.1,.25]]+Around[1,.1] |

If you plot `Around` numbers, they’ll be shown with error bars:

✕
ListPlot[Table[Around[n,RandomReal[Sqrt[n]]],{n,20}]] |

There are lots of options—like here’s one way to show uncertainty in both *x* and *y*:

✕
ListPlot[Table[Around[RandomReal[10],RandomReal[1]],20,2],IntervalMarkers->"Ellipses"] |

You can have `Around` quantities:

✕
1/Around[Quantity[3, "Metres"], Quantity[3.5, "Centimetres"]] |

And you can also have symbolic `Around` objects:

✕
Around[x,Subscript[δ, x]]+Around[y,Subscript[δ, y]] |

But what really is an `Around` object? It’s something where there are certain rules for combining uncertainties, that are based on uncorrelated normal distributions. But there’s no statement being made that `Around[ x, δ]` represents anything that actually in detail follows a normal distribution—any more than that

OK, so let’s say you make a bunch of measurements of some value. You can get an estimate of the value—together with its uncertainty—using `MeanAround` (and, yes, if the measurements themselves have uncertainties, these will be taken into account in weighting their contributions):

✕
MeanAround[{1.4,1.7,1.8,1.2,1.5,1.9,1.7,1.3,1.7,1.9,1.0,1.7}] |

Functions all over the system—notably in machine learning—are starting to have the option `ComputeUncertaintyTrue`, which makes them give `Around` objects rather than pure numbers.

`Around` might seem like a simple concept, but it’s full of subtleties—which is the main reason it’s taken until now for it to get into the system. Many of the subtleties revolve around correlations between uncertainties. The basic idea is that the uncertainty of every `Around` object is assumed to be independent. But sometimes one has values with correlated uncertainties—and so in addition to `Around`, there’s also `VectorAround`, which represents a vector of potentially correlated values with a specified covariance matrix.

There’s even more subtlety when one’s dealing with things like algebraic formulas. If one replaces `x` here with an `Around`, then, following the rules of `Around`, each instance is assumed to be uncorrelated:

✕
(Exp[x]+Exp[x/2])/.x->Around[0,.3] |

But probably one wants to assume here that even though the value of `x` may be uncertain, it’s going to be the same for each instance, and one can do this using the function `AroundReplace` (notice the result is different):

✕
AroundReplace[Exp[x]+Exp[x/2],x->Around[0,.3]] |

There’s lots of subtlety in how to display uncertain numbers. Like how many trailing 0s should you put in:

✕
Around[1,.0006] |

Or how much precision of the uncertainty should you include (there’s a conventional breakpoint when the trailing digits are 35):

✕
{Around[1.2345,.000312],Around[1.2345,.00037]} |

In rare cases where lots of digits are known (think, for example, some physical constants), one wants to go to a different way to specify uncertainty:

✕
Around[1.23456789,.000000001] |

And it goes on and on. But gradually `Around` is going to start showing up all over the system. By the way, there are lots of other ways to specify `Around` numbers. This is a number with 10% relative error:

✕
Around[2,Scaled[.1]] |

This is the best `Around` can do in representing an interval:

✕
Around[Interval[{2,3}]] |

For a distribution, `Around` computes variance:

✕
Around[NormalDistribution[2,1]] |

It can also take into account asymmetry by giving asymmetric uncertainties:

✕
Around[LogNormalDistribution[2,1]] |

In making math computational, it’s always a challenge to both be able to “get everything right”, and not to confuse or intimidate elementary users. Version 12.0 introduces several things to help. First, try solving an irreducible quintic equation:

✕
Solve[x^5 + 6 x + 1 == 0, x] |

In the past, this would have shown a bunch of explicit `Root` objects. But now the `Root` objects are formatted as boxes showing their approximate numerical values. Computations work exactly the same, but the display doesn’t immediately confront people with having to know about algebraic numbers.

When we say `Integrate`, we mean “find an integral”, in the sense of an antiderivative. But in elementary calculus, people want to see explicit constants of integration (as they always have in Wolfram|Alpha), so we added an option for that (and C[*n*] also has a nice, new output form):

✕
Integrate[x^3,x,GeneratedParameters->C] |

When we benchmark our symbolic integration capabilities we do really well. But there’s always more that can be done, particularly in terms of finding the simplest forms of integrals (and at a theoretical level this is an inevitable consequence of the undecidability of symbolic expression equivalence). In Version 12.0 we’ve continued to pick away at the frontier, adding cases like:

✕
\[Integral]Sqrt[ Sqrt[x] + Sqrt[2 x + 2 Sqrt[x] + 1] + 1] \[DifferentialD]x |

✕
\[Integral]x^2/(ProductLog[a/x] + 1) \[DifferentialD]x |

In Version 11.3 we introduced asymptotic analysis, being able to find asymptotic values of integrals and so on. Version 12.0 adds asymptotic sums, asymptotic recurrences and asymptotic solutions to equations:

✕
AsymptoticSum[1/Sqrt[k], {k, 1, n}, {n, \[Infinity], 5}] |

✕
AsymptoticSolve[x y^4 - (x + 1) y^2 + x == 1, y, {x, 0, 3}, Reals] |

One of the great things about making math computational is that it gives us new ways to explain math itself. And something we’ve been doing is to enhance our documentation so that it explains the math as well as the functions. For example, here’s the beginning of the documentation about `Limit`—with diagrams and examples of the core mathematical ideas:

Polygons have been part of the Wolfram Language since Version 1. But in Version 12.0 they’re getting generalized: now there’s a systematic way to specify holes in them. A classic geographic use case is the polygon for South Africa—with its hole for the country of Lesotho.

In Version 12.0, much like `Root`, `Polygon` gets a convenient new display form:

✕
RandomPolygon[20] |

You can compute with it just as before:

✕
Area[%] |

`RandomPolygon` is new too. You can ask, say, for 5 random convex polygons, each with 10 vertices, in 3D:

✕
Graphics3D[RandomPolygon[3->{"Convex",10},5]] |

There are lots of new operations on polygons. Like `PolygonDecomposition`, which can, for example, decompose a polygon into convex parts:

✕
RandomPolygon[8] |

✕
PolygonDecomposition[%, "Convex"] |

Polygons with holes introduce a need for other kinds of operations too, like `OuterPolygon`, `SimplePolygonQ`, and `CanonicalizePolygon`.

Polygons are pretty straightforward to specify: you just give their vertices in order (and if they have holes, you also give the vertices for the holes). Polyhedra are a bit more complicated: in addition to giving the vertices, you have to say how these vertices form faces. But in Version 12.0, `Polyhedron` lets you do this in considerable generality, including voids (the 3D analog of holes), etc.

But first, recognizing their 2000+ years of history, Version 12.0 introduces functions for the five Platonic solids:

✕
Graphics3D[Dodecahedron[]] |

And given the Platonic solids, one can immediately start computing with them:

✕
Volume[Dodecahedron[]] |

Here’s the solid angle subtended at vertex 1 (since it’s Platonic, all the vertices give the same angle):

✕
PolyhedronAngle[Dodecahedron[],1] |

Here’s an operation done on the polyhedron:

✕
Graphics3D[BeveledPolyhedron[Dodecahedron[],1]] |

✕
Volume[DualPolyhedron[BeveledPolyhedron[Dodecahedron[],1]]] |

Beyond the Platonic solids, Version 12 also builds in all the “uniform polyhedra” (*n* edges and *m* faces meet at each vertex)—and you can also get symbolic `Polyhedron` versions of named polyhedra from `PolyhedronData`:

✕
Graphics3D[AugmentedPolyhedron[PolyhedronData["Spikey","Polyhedron"],2]] |

You can make any polyhedron (including a “random” one, with `RandomPolyhedron`), then do whatever computations you want on it:

✕
RegionUnion[Dodecahedron[{0,0,0}],Dodecahedron[{1,1,1}]] |

✕
SurfaceArea[%] |

Mathematica and the Wolfram Language are very powerful at doing both explicit computational geometry and geometry represented in terms of algebra. But what about geometry the way it’s done in Euclid’s *Elements*—in which one makes geometric assertions and then sees what their consequences are?

Well, in Version 12, with the whole tower of technology we’ve built, we’re finally able to deliver a new style of mathematical computation—that in effect automates what Euclid was doing 2000+ years ago. A key idea is to introduce symbolic “geometric scenes” that have symbols representing constructs such as points, and then to define geometric objects and relations in terms of them.

For example, here’s a geometric scene representing a triangle *a*, *b*, *c*, and a circle through *a*, *b* and *c*, with center *o*, with the constraint that *o* is at the midpoint of the line from *a* to *c*:

✕
GeometricScene[{a,b,c,o},{Triangle[{a,b,c}],CircleThrough[{a,b,c},o],o==Midpoint[{a,c}]}] |

On its own, this is just a symbolic thing. But we can do operations on it. For example, we can ask for a random instance of it, in which *a*, *b*, *c* and *o* are made specific:

✕
RandomInstance[GeometricScene[{a,b,c,o},{Triangle[{a,b,c}],CircleThrough[{a,b,c},o],o==Midpoint[{a,c}]}]] |

You can generate as many random instances as you want. We try to make the instances as generic as possible, with no coincidences that aren’t forced by the constraints:

✕
RandomInstance[GeometricScene[{a,b,c,o},{Triangle[{a,b,c}],CircleThrough[{a,b,c},o],o==Midpoint[{a,c}]}],3] |

OK, but now let’s “play Euclid”, and find geometric conjectures that are consistent with our setup:

✕
FindGeometricConjectures[GeometricScene[{a,b,c,o},{Triangle[{a,b,c}],CircleThrough[{a,b,c},o],o==Midpoint[{a,c}]}]] |

For a given geometric scene, there may be many possible conjectures. We try to pick out the interesting ones. In this case we come up with two—and what’s illustrated is the first one: that the line *ba* is perpendicular to the line *cb*. As it happens, this result actually appears in Euclid (it’s in Book 3, as part of Proposition 31)— though it’s usually called Thales’s theorem.

In 12.0, we now have a whole symbolic language for representing typical things that appear in Euclid-style geometry. Here’s a more complex situation—corresponding to what’s called Napoleon’s theorem:

✕
RandomInstance[ GeometricScene[{"C", "B", "A", "C'", "B'", "A'", "Oc", "Ob", "Oa"}, {Triangle[{"C", "B", "A"}], TC == Triangle[{"A", "B", "C'"}], TB == Triangle[{"C", "A", "B'"}], TA == Triangle[{"B", "C", "A'"}], GeometricAssertion[{TC, TB, TA}, "Regular"], "Oc" == TriangleCenter[TC, "Centroid"], "Ob" == TriangleCenter[TB, "Centroid"], "Oa" == TriangleCenter[TA, "Centroid"], Triangle[{"Oc", "Ob", "Oa"}]}]] |

In 12.0 there are lots of new and useful geometric functions that work on explicit coordinates:

✕
CircleThrough[{{0,0},{2,0},{0,3}}] |

✕
TriangleMeasurement[Triangle[{{0,0},{1,2},{3,4}}],"Inradius"] |

For triangles there are 12 types of “centers” supported, and, yes, there can be symbolic coordinates:

✕
TriangleCenter[Triangle[{{0,0},{1,2},{3,y}}],"NinePointCenter"] |

And to support setting up geometric statements we also need “geometric assertions”. In 12.0 there are 29 different kinds—such as `"Parallel"`, `"Congruent"`, `"Tangent"`, `"Convex"`, etc. Here are three circles asserted to be pairwise tangent:

✕
RandomInstance[GeometricScene[{a,b,c},{GeometricAssertion[{Circle[a],Circle[b],Circle[c]},"PairwiseTangent"]}]] |

Version 11.3 introduced `FindEquationalProof` for generating symbolic representations of proofs. But what axioms should be used for these proofs? Version 12.0 introduces `AxiomaticTheory`, which gives axioms for various common axiomatic theories.

Here’s my personal favorite axiom system:

✕
AxiomaticTheory["WolframAxioms"] |

What does this mean? In a sense it’s a more symbolic symbolic expression than we’re used to. In something like 1 + `x` we don’t say what the value of `x` is, but we imagine that it can have a value. In the expression above, a, b and c are pure “formal symbols” that serve an essentially structural role, and can’t ever be thought of as having concrete values.

What about the · (center dot)? In 1 + `x` we know what + means. But the · is intended to be a purely abstract operator. The point of the axiom is in effect to define a constraint on what · can represent. In this particular case, it turns out that the axiom is an axiom for Boolean algebra, so that · can represent `Nand` and `Nor`. But we can derive consequences of the axiom completely formally, for example with `FindEquationalProof`:

✕
FindEquationalProof[p·q==q·p,AxiomaticTheory["WolframAxioms"]] |

There’s quite a bit of subtlety in all of this. In the example above, it’s useful to have · as the operator, not least because it displays nicely. But there’s no built-in meaning to it, and `AxiomaticTheory` lets you give something else (here `f`) as the operator:

✕
AxiomaticTheory[{"WolframAxioms",<|"Nand"->f|>}] |

What’s the “`Nand`” doing there? It’s a name for the operator (but it shouldn’t be interpreted as anything to do with the value of the operator). In the axioms for group theory, for example, several operators appear:

✕
AxiomaticTheory["GroupAxioms"] |

This gives the default representations of the various operators here:

✕
AxiomaticTheory["GroupAxioms","Operators"] |

`AxiomaticTheory` knows about notable theorems for particular axiomatic systems:

✕
AxiomaticTheory["GroupAxioms","NotableTheorems"] |

The basic idea of formal symbols was introduced in Version 7, for doing things like representing dummy variables in generated constructs like these:

✕
PDF[NormalDistribution[0,1]] |

✕
Sum[2^n n!, n] |

✕
Entity["Surface", "Torus"][EntityProperty["Surface", "AlgebraicEquation"]] |

You can enter a formal symbol using `\[FormalA]` or Esc.aEsc, etc. But back in Version 7, `\[FormalA]` was rendered as a. And that meant the expression above looked like:

✕
Function[{\[FormalA], \[FormalC]}, Function[{\[FormalX], \[FormalY], \[FormalZ]}, \[FormalA]^4 - 2 \[FormalA]^2 \[FormalC]^2 + \[FormalC]^4 - 2 \[FormalA]^2 \[FormalX]^2 - 2 \[FormalC]^2 \[FormalX]^2 + \[FormalX]^4 - 2 \[FormalA]^2 \[FormalY]^2 - 2 \[FormalC]^2 \[FormalY]^2 + 2 \[FormalX]^2 \[FormalY]^2 + \[FormalY]^4 - 2 \[FormalA]^2 \[FormalZ]^2 + 2 \[FormalC]^2 \[FormalZ]^2 + 2 \[FormalX]^2 \[FormalZ]^2 + 2 \[FormalY]^2 \[FormalZ]^2 + \[FormalZ]^4]] |

I always thought this looked incredibly complicated. And for Version 12 we wanted to simplify it. We tried many possibilities, but eventually settled on single gray underdots—which I think look much better.

In `AxiomaticTheory`, both the variables and the operators are “purely symbolic”. But one thing that’s definite is the arity of each operator, which one can ask `AxiomaticTheory`:

✕
AxiomaticTheory["BooleanAxioms"] |

✕
AxiomaticTheory["BooleanAxioms","OperatorArities"] |

Conveniently, the representation of operators and arities can immediately be fed into `Groupings`, to get possible expressions involving particular variables:

✕
Groupings[{a,b},%] |

Axiomatic theories represent a classic historical area for mathematics. Another classical historical area—much more on the applied side—is the *n*-body problem. Version 12.0 introduces `NBodySimulation`, which gives simulations of the *n*-body problem. Here’s a three-body problem (think Earth-Moon-Sun) with certain initial conditions (and inverse-square force law):

✕
NBodySimulation["InverseSquare",{<|"Mass"->1,"Position"->{0,0},"Velocity"->{0,.5}|>, <|"Mass"->1,"Position"->{1,1},"Velocity"->{0,-.5}|>, <|"Mass"->1,"Position"->{0,1},"Velocity"->{0,0}|>},4] |

You can ask about various aspects of the solution; this plots the positions as a function of time:

✕
ParametricPlot[Evaluate[%[All, "Position", t]], {t, 0, 4}] |

Underneath, this is just solving differential equations, but—a bit like `SystemModel`—`NBodySimulation` provides a convenient way to set up the equations and handle their solutions. And, yes, standard force laws are built in, but you can define your own.

We’ve been polishing the core of the Wolfram Language for more than 30 years now, and in each successive version we end up introducing some new extensions and conveniences.

We’ve had the function `Information` ever since Version 1.0, but in 12.0 we’ve greatly extended it. It used to just give information about symbols (although that’s been modernized as well):

✕
Information[Sin] |

But now it also gives information about lots of kinds of objects. Here’s information on a classifier:

✕
Information[Classify["NotablePerson"]] |

Here’s information about a cloud object:

✕
Information[CloudPut[100!]] |

Hover over the labels in the “information box” and you can find out the names of the corresponding properties:

✕
Information[CloudPut[100!],"FileHashMD5"] |

For entities, `Information` gives a summary of known property values:

✕
Information[Entity["Element", "Tungsten"]] |

Over the past few versions, we’ve introduced a lot of new summary display forms. In Version 11.3 we introduced `Iconize`, which is essentially a way of creating a summary display form for anything. `Iconize` has proved to be even more useful than we originally anticipated. It’s great for hiding unnecessary complexity both in notebooks and in pieces of Wolfram Language code. In 12.0 we’ve redesigned how `Iconize` displays, particularly to make it “read nicely” inside expressions and code.

You can explicitly iconize something:

✕
{a,b,Iconize[Range[10]]} |

Press the + and you’ll see some details:

Press and you’ll get the original expression again:

If you have lots of data you want to reference in a computation, you can always store it in a file, or in the cloud (or even in a data repository). It’s usually more convenient, though, to just put it in your notebook, so you have everything in the same place. One way to avoid the data “taking over your notebook” is to put in closed cells. But `Iconize` provides a much more flexible and elegant way to do this.

When you’re writing code, it’s often convenient to “iconize in place”. The right-click menu now lets you do that:

✕
Plot[Sin[x], {x, 0, 10}, PlotStyle -> Red, Filling -> Axis, FillingStyle -> LightYellow] |

Talking of display, here’s something small but convenient that we added in 12.0:

✕
PercentForm[0.3] |

And here are a couple of other “number conveniences” that we added:

✕
NumeratorDenominator[11/4] |

✕
MixedFractionParts[11/4] |

Functional programming has always been a central part of the Wolfram Language. But we’re continually looking to extend it, and to introduce new, generally useful primitives. An example in Version 12.0 is `SubsetMap`:

✕
SubsetMap[Reverse, {a, b, c, xxx, yyy, zzz}, {2, 5}] |

✕
SubsetMap[Reverse@*Map[f], {a, b, c, xxx, yyy, zzz}, {2, 5}] |

Functions are normally things that can take several inputs, but always give a single piece of output. In areas like quantum computing, however, one’s interested instead in having inputs and outputs. `SubsetMap` effectively implements functions, picking up inputs from specified positions in a list, applying some operation to them, then putting back the results at the same positions.

I started formulating what’s now `SubsetMap` about a year ago. And I quickly realized that actually I could really have used this function in all sorts of places over the years. But what should this particular “lump of computational work” be called? My initial working name was `ArrayReplaceFunction` (which I shortened to `ARF` in my notes). In a sequence of (livestreamed) meetings we went back and forth. There were ideas like `ApplyAt` (but it’s not really `Apply`) and `MutateAt` (but it’s not doing mutation in the lvalue sense), as well as `RewriteAt`, `ReplaceAt`, `MultipartApply` and `ConstructInPlace`. There were ideas about curried “function decorator” forms, like `PartAppliedFunction`, `PartwiseFunction`, `AppliedOnto`, `AppliedAcross` and `MultipartCurry`.

But somehow when we explained the function we kept on coming back to talking about how it was operating on a subset of a list, and how it was really like `Map`, except that it was operating on multiple elements at a time. So finally we settled on the name `SubsetMap`. And—in yet another reinforcement of the importance of language design—it’s remarkable how, once one has a name for something like this, one immediately finds oneself able to reason about it, and see where it can be used.

For many years we’ve worked hard to make the Wolfram Language the highest-level and most automated system for doing state-of-the-art machine learning. Early on, we introduced the “superfunctions” `Classify` and `Predict` that do classification and prediction tasks in a completely automated way, automatically picking the best approach for the particular input given. Along the way, we’ve introduced other superfunctions—like `SequencePredict`, `ActiveClassification` and `FeatureExtract`.

In Version 12.0 we’ve got several important new machine learning superfunctions. There’s `FindAnomalies`, which finds “anomalous elements” in data:

✕
FindAnomalies[{1.2, 2.5, 3.2, 107.6, 4.6, 5, 5.1, 204.2}] |

Along with this, there’s `DeleteAnomalies`, which deletes elements it considers anomalous:

✕
DeleteAnomalies[{1.2, 2.5, 3.2, 107.6, 4.6, 5, 5.1, 204.2}] |

There’s also `SynthesizeMissingValues`, which tries to generate plausible values for missing pieces of data:

✕
SynthesizeMissingValues[{{1.1,1.4},{2.3,3.1},{3,4},{Missing[],5.4},{8.7,7.5}}] |

How do these functions work? They’re all based on a new function called `LearnDistribution`, which tries to learn the underlying distribution of data, given a certain set of examples. If the examples were just numbers, this would essentially be a standard statistics problem, for which we could use something like `EstimatedDistribution`. But the point about `LearnDistribution` is that it works with data of any kind, not just numbers. Here it is learning an underlying distribution for a collection of colors:

✕
dist = LearnDistribution[{RGBColor[0.5172966964096541, 0.4435322033449375, 1.], RGBColor[0.3984626930847484, 0.5592892024442906, 1.], RGBColor[0.6149389612362844, 0.5648721294502163, 1.], RGBColor[0.4129156497559272, 0.9146065592632544, 1.], RGBColor[0.7907065846445507, 0.41054133291260947`, 1.], RGBColor[0.4878854162550912, 0.9281119680196579, 1.], RGBColor[0.9884362181280959, 0.49025178842859785`, 1.], RGBColor[0.633242503827218, 0.9880985331612835, 1.], RGBColor[0.9215182482568276, 0.8103084921468551, 1.], RGBColor[0.667469513641223, 0.46420827644204676`, 1.]}] |

Once we have this “learned distribution”, we can do all sorts of things with it. For example, this generates 20 random samples from it:

✕
RandomVariate[dist,20] |

But now think about `FindAnomalies`. What it has to do is to find out which data points are anomalous relative to what’s expected. Or, in other words, given the underlying distribution of the data, it finds what data points are outliers, in the sense that they should occur only with very low probability according to the distribution.

And just like for an ordinary numerical distribution, we can compute the PDF for a particular piece of data. Purple is pretty likely given the distribution of colors we’ve learned from our examples:

✕
PDF[dist, RGBColor[ 0.6323870562875563, 0.3525878887878987, 1.0002083564175581`]] |

But red is really really unlikely:

✕
PDF[dist, RGBColor[1, 0, 0]] |

For ordinary numerical distributions, there are concepts like CDF that tell us cumulative probabilities, say that we’ll get results that are “further out” than a particular value. For spaces of arbitrary things, there isn’t really a notion of “further out”. But we’ve come up with a function we call `RarerProbability`, that tells us what the total probability is of generating an example with a smaller PDF than something we give:

✕
RarerProbability[dist, RGBColor[ 0.6323870562875563, 0.3525878887878987, 1.0002083564175581`]] |

✕
RarerProbability[dist, RGBColor[1, 0, 0]] |

Now we’ve got a way to describe anomalies: they’re just data points that have a very small rarer probability. And in fact `FindAnomalies` has an option `AcceptanceThreshold` (with default value 0.001) that specifies what should count as “very small”.

OK, but let’s see this work on something more complicated than colors. Let’s train an anomaly detector by looking at 1000 examples of handwritten digits:

✕
AnomalyDetection[RandomSample[ResourceData["MNIST"][[All,1]],1000]] |

Now `FindAnomalies` can tell us which examples are anomalous:

✕
FindAnomalies[AnomalyDetection[RandomSample[ResourceData["MNIST"][[All,1]],1000]], {\!\(\* GraphicsBox[ TagBox[RasterBox[CompressedData[" 1:eJxTTMoPSmNiYGAo5gASQYnljkVFiZXBAkBOaF5xZnpeaopnXklqemqRRRJI mQwU/x+84O9URsb6P1ilPk1jAoLzWOUymJiEcchNY2Srm80kcAObHC9z1/8w Jm9sUh0sWf+/2DItxyJ1T5Cp9f8tJqbDWOTmMgHlinDK8UpyMVn+xCL3K4iJ Eei7TdicAgT2jIyFOKT+5zGJ38YhtYiRtR6H1CtuRkNcJlozMa/BIfVYiMkA h9QjAyatF9gkrqo2GjDpPMeq6RzQ0zrPsBv4NI4p+AcuN1ITAABxtMfa "], {{0, 28}, {28, 0}}, {0, 255}, ColorFunction->GrayLevel], BoxForm`ImageTag[ "Byte", ColorSpace -> Automatic, Interleaving -> None], Selectable->False], DefaultBaseStyle->"ImageGraphics", ImageSizeRaw->{28, 28}, PlotRange->{{0, 28}, {0, 28}}]\), \!\(\* GraphicsBox[ TagBox[RasterBox[CompressedData[" 1:eJxTTMoPSmNiYGAo5gASQYnljkVFiZXBAkBOaF5xZnpeaopnXklqemqRRRJI mQwU/x/kgJGJcTUOqV4mFqY12KWKmBiZZI9jlwPqYsEu9ciKgYnRGrsuK6Au 68e4dDEw4dbFVIpdFyNeu7D77NEqoC6mXhLt+n8Mt79C5XGGYhhuf4F14bAL t7+OyeMKw///LYH+wi7z//9jayYWXHLUBgCB+cHS "], {{0, 28}, {28, 0}}, {0, 255}, ColorFunction->GrayLevel], BoxForm`ImageTag[ "Byte", ColorSpace -> Automatic, Interleaving -> None], Selectable->False], DefaultBaseStyle->"ImageGraphics", ImageSizeRaw->{28, 28}, PlotRange->{{0, 28}, {0, 28}}]\), \!\(\* GraphicsBox[ TagBox[RasterBox[CompressedData[" 1:eJxTTMoPSmNiYGAo5gASQYnljkVFiZXBAkBOaF5xZnpeaopnXklqemqRRRJI mQwU/x/M4I7MI1SBfL2vMOYpxsuocqGMd2DMLehyzoy9MKYTulwWYwuMKY0p dxanXCJCQJrtBqqcOWMXlPVLUhdVCmim76qdm+fNu76wktHr27dvyHLtjChA GFnuZbkTI6NiQIB/ABvDhOXn0Ez9+/37LxAtJPDsPy4gZIZT6gZnC065HYyn cMr1IQIWAyQy+q/ELSd7FbfcBNxmir/DKUcVAADomc0b "], {{0, 28}, {28, 0}}, { 0, 255}, ColorFunction->GrayLevel], BoxForm`ImageTag[ "Byte", ColorSpace -> Automatic, Interleaving -> None], Selectable->False], DefaultBaseStyle->"ImageGraphics", ImageSizeRaw->{28, 28}, PlotRange->{{0, 28}, {0, 28}}]\), \!\(\* GraphicsBox[ TagBox[RasterBox[CompressedData[" 1:eJxTTMoPSmNiYGAo5gASQYnljkVFiZXBAkBOaF5xZnpeaopnXklqemqRRRJI mQwUDwZwxxCnVOZfnHJ8T75rYAiKC4Cp2n+rMKRcXm8E099+GaNLsW/7OQ9E 2/9ZhqFtwT8HEMV07J8RulT7v1WMINru3xsBNKmw339cQDTroX/FaFLSD/9N BzOU/n1gR5Mz+vdeBESz7P2XwsAujSIn+/zfxZychqO9//7dOHoRzX8xf/5B wN9fi/250ExVCwWC4n8//TE8BwW6/97ikmJI+HcLl5Tc43+TcUhxrP33uxmH nO+/P6W4jDz4bxNOl9AFAAAYpls0 "], {{0, 28}, {28, 0}}, {0, 255}, ColorFunction->GrayLevel], BoxForm`ImageTag[ "Byte", ColorSpace -> Automatic, Interleaving -> None], Selectable->False], DefaultBaseStyle->"ImageGraphics", ImageSizeRaw->{28, 28}, PlotRange->{{0, 28}, {0, 28}}]\), \!\(\* GraphicsBox[ TagBox[RasterBox[CompressedData[" 1:eJxTTMoPSmNiYGAo5gASQYnljkVFiZXBAkBOaF5xZnpeaopnXklqemqRRRJI mQwU/x8UgKEep5QDbrn9DAz7SdC2vx6uDYtyGO2AKQU1CtO2/bAAxLStHqYa 05FAKTBwwLRtPwMSwHQHg0M9RDu6bRAZCAPd/fX1cLPRtSGZjaENydr9uOTw pR88cvuxuBJJDqd19AAAMwi/NQ== "], {{0, 28}, {28, 0}}, {0, 255}, ColorFunction->GrayLevel], BoxForm`ImageTag[ "Byte", ColorSpace -> Automatic, Interleaving -> None], Selectable->False], DefaultBaseStyle->"ImageGraphics", ImageSizeRaw->{28, 28}, PlotRange->{{0, 28}, {0, 28}}]\), \!\(\* GraphicsBox[ TagBox[RasterBox[CompressedData[" 1:eJxTTMoPSmNiYGAo5gASQYnljkVFiZXBAkBOaF5xZnpeaopnXklqemqRRRJI mQwU/x+M4FkLV9+VK1fmZ2czqn5GlbotwwwETBDiOKrcPCYkuW1oZvZJOMWu BgJrZiaJ92hyPx6DqSkCzMInsTrokAwTk/AybDLH6oH2WWPR9emYPCczE1fj DwyZ9/tVwU6Uj9//BU3qoBIz3A+qaPbVMzExMjHJNU8p0hFgYij9jSy3Sl4t 48CBVyDm1UIm5lcoGj8ignAquhwCXHHFDBeYq3CFy9srSUxMTJjhcvbYxn51 kB+CMKSmcHGygPwnf/wzhpwbSIts8GrMIAO6gUktp+05DrdTEQAAo1CVcQ== "], {{0, 28}, {28, 0}}, {0, 255}, ColorFunction->GrayLevel], BoxForm`ImageTag[ "Byte", ColorSpace -> Automatic, Interleaving -> None], Selectable->False], DefaultBaseStyle->"ImageGraphics", ImageSizeRaw->{28, 28}, PlotRange->{{0, 28}, {0, 28}}]\), \!\(\* GraphicsBox[ TagBox[RasterBox[CompressedData[" 1:eJxTTMoPSmNiYGAo5gASQYnljkVFiZXBAkBOaF5xZnpeaopnXklqemqRRRJI mQwU/x/s4PcnHBKvNzqZCNX8wRD/8nmfPx8jEAjFo0udtVcAinNouWpp5aPL WTIysoauvIvNpq0cIhpJ2B1xgpvR7zsOKWFGRhxufyLEyLj5H1apz9ZAF0rk fsP01/8f9YwQEP0VTeZGqTojo+Xmfd0yjIy6P1HlUhk52yc+BrG6uTnPosol MDKKN4K93MDPuA1V7m0qMBA5tUr0tRgZ1dAt/L/SGOIUBqU3mA79sn9KhrOz c+0HrD4c3AAAH4+4UQ== "], {{0, 28}, {28, 0}}, {0, 255}, ColorFunction->GrayLevel], BoxForm`ImageTag[ "Byte", ColorSpace -> Automatic, Interleaving -> None], Selectable->False], DefaultBaseStyle->"ImageGraphics", ImageSizeRaw->{28, 28}, PlotRange->{{0, 28}, {0, 28}}]\), \!\(\* GraphicsBox[ TagBox[RasterBox[CompressedData[" 1:eJxTTMoPSmNiYGAo5gASQYnljkVFiZXBAkBOaF5xZnpeaopnXklqemqRRRJI mQwU/x+UoCeKkZGBkZGx4hmmHDsTFBg/wi3H1I0h186hbwkErExM2piGbnsP JN7xYpUDgr9vzUAWYkpcqK3NB9u3BUMqghXqlKq/6FKdMFfqY/qvFu4Fz1fo clOYmTSNjAyx27ei/Or//3+WcaHJ/UZi8qHKnbdtug6TckEzcx4Tk+xVMOuz J1DKFsmY/3v5gZLX/v/fPUkeKCV7AsUZU4FCchYWPCBHStehOnG/EsxvzNpn 0N3/ygEiJbcIw2v//7/v7nYUKOq+hkWKugAABiF8Xw== "], {{0, 28}, {28, 0}}, { 0, 255}, ColorFunction->GrayLevel], BoxForm`ImageTag[ "Byte", ColorSpace -> Automatic, Interleaving -> None], Selectable->False], DefaultBaseStyle->"ImageGraphics", ImageSizeRaw->{28, 28}, PlotRange->{{0, 28}, {0, 28}}]\), \!\(\* GraphicsBox[ TagBox[RasterBox[CompressedData[" 1:eJxTTMoPSmNiYGAo5gASQYnljkVFiZXBAkBOaF5xZnpeaopnXklqemqRRRJI mQwU/x9GwAHim/376+sxpRgYHOoZwABdjgEJYJOrd6iv378fS1DtR6jC7Sg8 cvV45erxGEl1OWzeI8Ip+LU5kGMk0JX7ybHOgTwj0QEApknS3g== "], {{0, 28}, { 28, 0}}, {0, 255}, ColorFunction->GrayLevel], BoxForm`ImageTag[ "Byte", ColorSpace -> Automatic, Interleaving -> None], Selectable->False], DefaultBaseStyle->"ImageGraphics", ImageSizeRaw->{28, 28}, PlotRange->{{0, 28}, {0, 28}}]\), \!\(\* GraphicsBox[ TagBox[RasterBox[CompressedData[" 1:eJxTTMoPSmNiYGAo5gASQYnljkVFiZXBAkBOaF5xZnpeaopnXklqemqRRRJI mQwUD16Qe0EEp9yBfw045Vb924hTbtm/YJxyH/964ZY7j1Mq4F8/Trl6PHKb yJbrwiNngEtK6CduOZF/N7hwy53DaZ3Ifzxy/1bgkcvHYyZuOd5DrjjlqAUA H0Iyqg== "], {{0, 28}, {28, 0}}, {0, 255}, ColorFunction->GrayLevel], BoxForm`ImageTag[ "Byte", ColorSpace -> Automatic, Interleaving -> None], Selectable->False], DefaultBaseStyle->"ImageGraphics", ImageSizeRaw->{28, 28}, PlotRange->{{0, 28}, {0, 28}}]\), \!\(\* GraphicsBox[ TagBox[RasterBox[CompressedData[" 1:eJxTTMoPSmNiYGAo5gASQYnljkVFiZXBAkBOaF5xZnpeaopnXklqemqRRRJI mQwU/x+s4FJKpNVW7FLzeBgZGdnPYJPaz83IKcXIGIVF6q8ro+zlN6u5NBu/ YMidY2RfBaS2MjLOQpf67MiYDaL/KDLyP0WT62OUfQBmTGJkbECTC2PMh9qr xMh4HkXqLovsTyjzDi/jORS5HsZkOFsMTS6csRfGvMfDegVZ6pU41w0Y25C7 HEXbOkZxKOtvC8tGVFduhMn97GZMQPNBCUyunpHxCppcG0Tu6yZWsdP/0OSe mXAD3X1Jg1Hi/H8MUMgo1mUkyqq+HlPq/3JmYLzyVmCRAYLZVTbBP7FLURMA AEeuuRo= "], {{0, 28}, {28, 0}}, {0, 255}, ColorFunction->GrayLevel], BoxForm`ImageTag[ "Byte", ColorSpace -> Automatic, Interleaving -> None], Selectable->False], DefaultBaseStyle->"ImageGraphics", ImageSizeRaw->{28, 28}, PlotRange->{{0, 28}, {0, 28}}]\), \!\(\* GraphicsBox[ TagBox[RasterBox[CompressedData[" 1:eJxTTMoPSmNiYGAo5gASQYnljkVFiZXBAkBOaF5xZnpeaopnXklqemqRRRJI mQwU/x9gcJ9hDy6pX9GMc3FI/bjAyPgWh9wrZUbeH7hsY2QMwmXdHUamaTik PlgzsuHStpORMQKXnCuj0C8cUqdZGZVxaZvFyIjLJf/dGKU+4TKSjTERl7bt eIz0YpR9h0PqPDNuI2czyj/GIfVRl9EVl7Y5jIwzccntl5X+jEuOTgAACjPm MQ== "], {{0, 28}, {28, 0}}, {0, 255}, ColorFunction->GrayLevel], BoxForm`ImageTag[ "Byte", ColorSpace -> Automatic, Interleaving -> None], Selectable->False], DefaultBaseStyle->"ImageGraphics", ImageSizeRaw->{28, 28}, PlotRange->{{0, 28}, {0, 28}}]\)}] |

We first introduced our symbolic framework for constructing, exploring and using neural networks back in 2016, as part of Version 11. And in every version since then we’ve added all sorts of state-of-the-art features. In June 2018 we introduced our Neural Net Repository to make it easy to access the latest neural net models from the Wolfram Language—and already there are nearly 100 curated models of many different types in the repository, with new ones being added all the time.

So if you need the latest BERT “transformer” neural network (that was added today!), you can get it from `NetModel`:

✕
NetModel["BERT Trained on BookCorpus and English Wikipedia Data"] |

You can open this up and see the network that’s involved (and, yes, we’ve updated the display of net graphs for Version 12.0):

And you can immediately use the network, here to produce some kind of “meaning features” array:

✕
NetModel["BERT Trained on BookCorpus and English Wikipedia Data"][ "What a wonderful network!"] // MatrixPlot |

In Version 12.0 we’ve introduced several new layer types—notably `AttentionLayer`, which lets one set up the latest “transformer” architectures—and we’ve enhanced our “neural net functional programming” capabilities, with things like `NetMapThreadOperator`, and multiple-sequence `NetFoldOperator`. In addition to these “inside-the-net” enhancements, Version 12.0 adds all sorts of new `NetEncoder` and `NetDecoder` cases, such as BPE tokenization for text in hundreds of languages, and the ability to include custom functions for getting data into and out of neural nets.

But some of the most important enhancements in Version 12.0 are more infrastructural. `NetTrain` now supports multi-GPU training, as well as dealing with mixed-precision arithmetic, and flexible early-stopping criteria. We’re continuing to use the popular MXNet low-level neural net framework (to which we’ve been major contributors)—so we can take advantage of the latest hardware optimizations. There are new options for seeing what’s happening during training, and there’s also `NetMeasurements` that allows you to make 33 different types of measurements on the performance of a network:

✕
NetMeasurements[NetModel["LeNet Trained on MNIST Data"], {\!\(\* GraphicsBox[ TagBox[RasterBox[CompressedData[" 1:eJxTTMoPSmNiYGAo5gASQYnljkVFiZXBAkBOaF5xZnpeaopnXklqemqRRRJI mQwU/x9YUI/HAQ4M+3HKMTDU4zYSt5wDA24z8QUGHjmgdQ54tOFySj0eIx3w +ICAkftxa8NpHR4jCXicrECpxxPO+3G7hE4AAARG3ZY= "], {{0, 28}, {28, 0}}, { 0, 255}, ColorFunction->GrayLevel], BoxForm`ImageTag[ "Byte", ColorSpace -> Automatic, Interleaving -> None], Selectable->False], DefaultBaseStyle->"ImageGraphics", ImageSizeRaw->{28, 28}, PlotRange->{{0, 28}, {0, 28}}]\) -> 1, \!\(\* GraphicsBox[ TagBox[RasterBox[CompressedData[" 1:eJxTTMoPSmNiYGAo5gASQYnljkVFiZXBAkBOaF5xZnpeaopnXklqemqRRRJI mQwU/x964N8LDwZGxtQ72OROMvJOKA9glLmJKXWRVWTn//8fuhkljqBLfZZn fQyiTzExWl5Hk/Nn1AHTmxgZGd2/ocopMn4E0z9NGbnT/6BIvRMzggg8VmDq RjPyHOMsEPV7tRyjH7pTVjOeA8pcjWJk1DiIIcem2NygD3QHH4bU//9NYoyi kQv4GDsxpYCuefz2nQJj3V9scv///wpk9MYh9W8mo/wH7FL/rzDynsAh9Vqa uR2H1BdFpnxcUoaMoTik/ocxOv3BIfVcEBRmVAIAcZ7Grw== "], {{0, 28}, {28, 0}}, {0, 255}, ColorFunction->GrayLevel], BoxForm`ImageTag[ "Byte", ColorSpace -> Automatic, Interleaving -> None], Selectable->False], DefaultBaseStyle->"ImageGraphics", ImageSizeRaw->{28, 28}, PlotRange->{{0, 28}, {0, 28}}]\) -> 9, \!\(\* GraphicsBox[ TagBox[RasterBox[CompressedData[" 1:eJxTTMoPSmNiYGAo5gASQYnljkVFiZXBAkBOaF5xZnpeaopnXklqemqRRRJI mQwU/x8Q8C2ckTEiPz//DRapaCYmKUkmJqZ7mHJ3mZjMUlOnpqa+xpR7r2X2 Fad9sfm43dKDR86Pq6F1dV9RpqpKa+v7b2hyTBCgIQIkxLuuIMtt4Wdikm3e u/fbLP9VtcpMnA+QJZ9c3fEKyvxzxYtJ9ChO6ycz7sUp99vd6gVOyRQFLCEE AV9YRR/hkrvNVIrEu1O2bNkFOC+eaSmS3De3UBkeccvWw58/v2qNZ/a5i2pQ FyswTBjAwSNzA92Ww6vElBlBUrKXsbjh+Rv+3nv37r3CIkUPAAABtrX9 "], {{0, 28}, {28, 0}}, {0, 255}, ColorFunction->GrayLevel], BoxForm`ImageTag[ "Byte", ColorSpace -> Automatic, Interleaving -> None], Selectable->False], DefaultBaseStyle->"ImageGraphics", ImageSizeRaw->{28, 28}, PlotRange->{{0, 28}, {0, 28}}]\) -> 5, \!\(\* GraphicsBox[ TagBox[RasterBox[CompressedData[" 1:eJxTTMoPSmNiYGAo5gASQYnljkVFiZXBAkBOaF5xZnpeaopnXklqemqRRRJI mQwU/6cx+OTNyMjIkIdN6n0UEwjwP8UiF8gEAcYvMeUEoHJMN7HK8WmKAeVS MeVShXvW/z8uxMTkgCn36xOIlMcqBwZLuHDLNQPt68cutYsXuzuB4Ls7UIr3 LrrwgubmSf/TgVJcO9BkrjVwMjGxybMC5WaiSd1XhYUJk+FjNLlOuBSTxg1U qZVcCDkmlYMHD9ZvhsvNYkIHFhhyVnlKGHLrQT5myrz08v/9Nk0gi8XiAMLC KUCB8J9g5uM5c+bMxxowAwoAzGhtzQ== "], {{0, 28}, {28, 0}}, {0, 255}, ColorFunction->GrayLevel], BoxForm`ImageTag[ "Byte", ColorSpace -> Automatic, Interleaving -> None], Selectable->False], DefaultBaseStyle->"ImageGraphics", ImageSizeRaw->{28, 28}, PlotRange->{{0, 28}, {0, 28}}]\) -> 2, \!\(\* GraphicsBox[ TagBox[RasterBox[CompressedData[" 1:eJxTTMoPSmNiYGAo5gASQYnljkVFiZXBAkBOaF5xZnpeaopnXklqemqRRRJI mQwU/x8u4FBT01YEb11TJQPLIRiviYmJxaoTAorYWZiYmDj+wOR+bmNnQgGO 25FMfVuS5YqQ4tqHZum3Z2DgzsQk+QK7sxZyM9luwOFkDyamJTiklvExeb/H LnWKn4n/MHapN15M/CtwmBjGxDQdh9RqASad19ilDvMz8S3CLvXBl4kpHIeJ AcBgfIVdagsfE9Np7FIHeJiYrHBom8bEZITDjSC5KBxS/88ElbzBJYcNAAB0 /LWr "], {{0, 28}, {28, 0}}, {0, 255}, ColorFunction->GrayLevel], BoxForm`ImageTag[ "Byte", ColorSpace -> Automatic, Interleaving -> None], Selectable->False], DefaultBaseStyle->"ImageGraphics", ImageSizeRaw->{28, 28}, PlotRange->{{0, 28}, {0, 28}}]\) -> 7}, "Perplexity"] |

Neural nets aren’t the only—or even always the best—way to do machine learning. But one thing that’s new in Version 12.0 is that we’re now able to use self-normalizing networks automatically in `Classify` and `Predict`, so they can easily take advantage of neural nets when it makes sense.

We introduced `ImageIdentify`, for identifying what an image is of, back in Version 10.1. In Version 12.0 we’ve managed to generalize this, to figure out not only what an image is of, but also what’s in an image. So, for example, `ImageCases` will show us cases of known kinds of objects in an image:

✕
ImageCases[CloudGet["https://wolfr.am/CMoUVVTH"]] |

For more details, `ImageContents` gives a dataset about what’s in an image:

✕
ImageContents[CloudGet["https://wolfr.am/CMoUVVTH"]] |

You can tell `ImageCases` to look for a particular kind of thing:

✕
ImageCases[CloudGet["https://wolfr.am/CMoUVVTH"], "zebra"] |

And you can also just test to see whether an image contains a particular kind of thing:

✕
ImageContainsQ[CloudGet["https://wolfr.am/CMoUVVTH"], "zebra"] |

In a sense, `ImageCases` is like a generalized version of `FindFaces`, for finding human faces in an image. Something new in Version 12.0 is that `FindFaces` and `FacialFeatures` have become more efficient and robust—with `FindFaces` now based on neural networks rather than classical image processing, and the network for `FacialFeatures` now being 10 MB rather than 500 MB:

✕
FacialFeatures[CloudGet["https://wolfr.am/CO20sk12"]] // Dataset |

Functions like `ImageCases` represent “new-style” image processing, of a type that didn’t seem conceivable only a few years ago. But while such functions let one do all sorts of new things, there’s still lots of value in more classical techniques. We’ve had fairly complete classical image processing in the Wolfram Language for a long time, but we continue to make incremental enhancements.

An example in Version 12.0 is the `ImagePyramid` framework, for doing multiscale image processing:

✕
ImagePyramid[CloudGet["https://wolfr.am/CTWBK9Em"]][All] |

There are several new functions in Version 12.0 concerned with color computation. A key idea is `ColorsNear`, which represents a neighborhood in perceptual color space, here around the color `Pink`:

✕
ChromaticityPlot3D[ColorsNear[Pink,.2]] |

The notion of color neighborhoods can be used, for example, in the new `ImageRecolor` function:

✕
ImageRecolor[CloudGet["https://wolfr.am/CT2rFF6e"], ColorsNear[RGBColor[ Rational[1186, 1275], Rational[871, 1275], Rational[1016, 1275]], .02] -> Orange] |

As I sit at my computer writing this, I’ll say something to my computer, and capture it:

Play Audio

Here’s a spectrogram of the audio I captured:

✕
Spectrogram[%] |

So far we could do this in Version 11.3 (though `Spectrogram` got 10 times faster in 12.0). But now here’s something new:

✕
SpeechRecognize[%%] |

We’re doing speech-to-text! We’re using state-of-the-art neural net technology, but I’m amazed at how well it works. It’s pretty streamlined, and we’re perfectly well able to handle even very long pieces of audio, say stored in files. And on a typical computer the transcription will run at about actual real-time speed, so that an hour of speech will take about an hour to transcribe.

Right now we consider `SpeechRecognize` experimental, and we’ll be continuing to enhance it. But it’s interesting to see another major computational task just become a single function in the Wolfram Language.

In Version 12.0, there are other enhancements too. `SpeechSynthesize` supports new languages and new voices (as listed by `VoiceStyleData[]`).

There’s now `WebAudioSearch`—analogous to `WebImageSearch`—that lets you search for audio on the web:

✕
WebAudioSearch["rooster"] |

You can retrieve actual `Audio` objects:

✕
WebAudioSearch["rooster","Samples",MaxItems->3] |

Then you can make spectrograms or other measurements:

✕
Spectrogram /@% |

And then—new in Version 12.0—you can use `AudioIdentify` to try to identify the category of sound (is that a talking rooster?):

✕
AudioIdentify/@%% |

We still consider `AudioIdentify` experimental. It’s an interesting start, but it definitely doesn’t, for example, work as well as `ImageIdentify`.

A more successful audio function is `PitchRecognize`, which tries to recognize the dominant frequency in an audio signal (it uses both “classical” and neural net methods). It can’t yet deal with “chords”, but it works pretty much perfectly for “single notes”.

When one deals with audio, one often wants not just to identify what’s in the audio, but to annotate it. Version 12.0 introduces the beginning of a large-scale audio framework. Right now `AudioAnnotate` can mark where there’s silence, or where there’s something loud. In the future, we’ll be adding speaker identification and word boundaries, and lots else. And to go along with these, we also have functions like `AudioAnnotationLookup`, for picking out parts of an audio object that have been annotated in particular ways.

Underneath all this high-level audio functionality there’s a whole infrastructure of low-level audio processing. Version 12.0 greatly enhances `AudioBlockMap` (for applying filters to audio signals), as well as introduces functions like `ShortTimeFourier`.

A spectrogram can be viewed a bit like a continuous analog of a musical score, in which pitches are plotted as a function of time. In Version 12.0 there’s now `InverseSpectrogram`—that goes from an array of spectrogram data to audio. Ever since Version 2 in 1991, we’ve had `Play` to generate sound from a function (like `Sin[100 t]`). Now with `InverseSpectrogram` we have a way to go from a “frequency-time bitmap” to a sound. (And, yes, there are tricky issues about best guesses for phases when one only has magnitude information.)

Starting with Wolfram|Alpha, we’ve had exceptionally strong natural language understanding (NLU) capabilities for a long time. And this means that given a piece of natural language, we’re good at understanding it as Wolfram Language—that we can then go and compute from:

✕
EntityValue[ EntityClass[ "Country", {EntityProperty["Country", "EntityClasses"] -> EntityClass["Country", "Europe"], EntityProperty["Country", "Population"] -> TakeLargest[5]}], EntityProperty["Country", "Flag"]] |

But what about natural language processing (NLP)—where we’re taking potentially long passages of natural language, and not trying to completely understand them, but instead just find or process particular features of them? Functions like `TextSentences`, `TextStructure`, `TextCases` and `WordCounts` have given us basic capabilities in this area for a while. But in Version 12.0—by making use of the latest machine learning, as well as our longstanding NLU and knowledgebase capabilities—we’ve now jumped to having very strong NLP capabilities.

The centerpiece is the dramatically enhanced version of `TextCases`. The basic goal of `TextCases` is to find cases of different types of content in a piece of text. An example of this is the classic NLP task of “entity recognition”—with `TextCases` here finding what country names appear in the Wikipedia article about ocelots:

✕
TextCases[WikipediaData["ocelots"],"Country"->"Interpretation"] |

We could also ask what islands are mentioned, but now we won’t ask for a Wolfram Language interpretation:

✕
TextCases[WikipediaData["ocelots"],"Island"] |

`TextCases` isn’t perfect, but it does pretty well:

✕
TextCases[WikipediaData["ocelots"],"Date"] |

It supports a whole lot of different content types too:

You can ask it to find pronouns, or reduced relative clauses, or quantities, or email addresses, or occurrences of any of 150 kinds of entities (like companies or plants or movies). You can also ask it to pick out pieces of text that are in particular human or computer languages, or that are about particular topics (like travel or health), or that have positive or negative sentiment. And you can use constructs like `Containing` to ask for combinations of these things (like noun phrases that contain the name of a river):

✕
TextCases[WikipediaData["ocelots"],Containing["NounPhrase","River"]] |

`TextContents` lets you see, for example, details of all the entities that were detected in a particular piece of text:

✕
TextContents[TextSentences[WikipediaData["ocelots"], 1]] |

And, yes, one can in principle use these capabilities through `FindTextualAnswer` to try to answer questions from text—but in a case like this, the results can be pretty wacky:

✕
FindTextualAnswer[WikipediaData["ocelots"],"weight of an ocelot",5] |

Of course, you can get a real answer from our actual built-in curated knowledgebase:

✕
Entity["Species", "Species:LeopardusPardalis"][ EntityProperty["Species", "Weight"]] |

By the way, in Version 12.0 we’ve added a variety of little “natural language convenience functions”, like `Synonyms` and `Antonyms`:

✕
Synonyms["magnificent"] |

One of the “surprise” new areas in Version 12.0 is computational chemistry. We’ve had data on explicit known chemicals in our knowledgebase for a long time. But in Version 12.0 we can compute with molecules that are specified simply as pure symbolic objects. Here’s how we can specify what turns out to be a water molecule:

✕
Molecule[{Atom["H"],Atom["H"],Atom["O"]},{Bond[{1,3}],Bond[{2,3}]}] |

And here’s how we can make a 3D rendering:

✕
MoleculePlot3D[%] |

We can deal with “known chemicals”:

✕
Molecule[Entity["Chemical", "Caffeine"]] |

We can use arbitrary IUPAC names:

✕
MoleculePlot3D[Molecule["2,4,6-trimethoxybenzaldehyde"]] |

Or we “make up” chemicals, for example specifying them by their SMILES strings:

✕
MoleculePlot3D[Molecule["O1CNNONC(N(OOC)OO)CCNONOCONCCONNCOC1"]] |

But we’re not just generating pictures here. We can also compute things from the structure—like symmetries:

✕
Molecule["C1=CC=CC=C1"]["PointGroup"] |

Given a molecule, we can do things like highlight carbon-oxygen bonds:

✕
MoleculePlot[ Molecule["C=C1[C@H](O)C2O[C@@]3(CC[C@H](/C=C/[C@@H](C)[C@@H]4CC(C)=C[\ C@@]5(O[C@H](C[C@@](C)(O)C(=O)O)CC[C@H]5O)O4)O3)CC[C@H]2O[C@H]1[C@@H](\ O)C[C@H](C)C1O[C@@]2(CCCCO2)CC[C@H]1C"], Bond[{"C", "O"}]] |

Or highlight structures, say specified by SMARTS strings (here any 5-member ring):

✕
MoleculePlot[Molecule["C=C1[C@H](O)C2O[C@@]3(CC[C@H](/C=C/[C@@H](C)[C@@H]4CC(C)=C[C@@]5(O[C@H](C[C@@](C)(O)C(=O)O)CC[C@H]5O)O4)O3)CC[C@H]2O[C@H]1[C@@H](O)C[C@H](C)C1O[C@@]2(CCCCO2)CC[C@H]1C"], MoleculePattern["[r5]"]] |

You can also do searches for “molecule patterns”; the results come out in terms of atom numbers:

✕
FindMoleculeSubstructure[Molecule["C=C1[C@H](O)C2O[C@@]3(CC[C@H](/C=C/[C@@H](C)[C@@H]4CC(C)=C[C@@]5(O[C@H](C[C@@](C)(O)C(=O)O)CC[C@H]5O)O4)O3)CC[C@H]2O[C@H]1[C@@H](O)C[C@H](C)C1O[C@@]2(CCCCO2)CC[C@H]1C"], MoleculePattern["[r5]"], All] |

The computational chemistry capabilities we’ve added in Version 12.0 are pretty general and pretty powerful (with the caveat that so far they only deal with organic molecules). At the lowest level they view molecules as labeled graphs with edges corresponding to bonds. But they also know about physics, and correctly account for atomic valences and bond configurations. Needless to say, there are lots of details (about stereochemistry, symmetry, aromaticity, isotopes, etc.). But the end result is that molecular structure and molecular computation have now successfully been added to the list of areas that are integrated into the Wolfram Language.

The Wolfram Language already has strong capabilities for geographic computing, but Version 12.0 adds more functions, and enhances some of those that were already there.

For example, there’s now `RandomGeoPosition`, which generates a random lat-long location. One might think this would be trivial, but of course one has to worry about coordinate transformations—and what makes it much more nontrivial is that one can tell it to pick points only inside a certain region, here the country of France:

✕
GeoListPlot[RandomGeoPosition[Entity["Country", "France"],100]] |

A theme of new geographic capabilities in Version 12.0 is handling not just geographic points and regions, but also geographic vectors. Here’s the current wind vector, for example, at the position of the Eiffel Tower, represented as a `GeoVector`, with speed and direction (there’s also `GeoVectorENU`, which gives east, north and up components, as well as `GeoGridVector` and `GeoVectorXYZ`):

✕
WindVectorData[Entity["Building", "EiffelTower::5h9w8"],Now,"DownwindGeoVector"] |

Functions like `GeoGraphics` let you visualize discrete geo vectors. `GeoStreamPlot` is the geo analog of `StreamPlot` (or `ListStreamPlot`)—and shows streamlines formed from geo vectors (here from `WindDirectionData`):

✕
GeoStreamPlot[CloudGet["https://wolfr.am/CTZnxuQI"]] |

Geodesy is a mathematically sophisticated area, and we pride ourselves on doing it well in the Wolfram Language. In Version 12.0, we’ve added a few new functions to fill in some details. For example, we now have functions like `GeoGridUnitDistance` and `GeoGridUnitArea` which give the distortion (basically, eigenvalues of the Jacobian) associated with different geo projections at every position on Earth (or Moon, Mars, etc.).

One direction of visualization that we’ve been steadily developing is what one might call “meta-graphics”: the labeling and annotation of graphical things. We introduced `Callout` in Version 11.0; in Version 12.0 it’s been extended to things like 3D graphics:

✕
Plot3D[Callout[Exp[-(x^2+y^2)],"maximum",{0,0}],{x,-2,2},{y,-2,2}] |

It’s pretty good at figuring out where to label things, even when they get a bit complex:

✕
PolarPlot[Evaluate[Table[Callout[Sin[n θ],n],{n,4}]],{θ,0,π}] |

There are lots of details that matter in making graphics really look good. Something that’s been enhanced in Version 12.0 is ensuring that columns of graphics line up on their frames, regardless of the length of their tick labels. We’ve also added `LabelVisibility`, which allows you to specify the relative priorities with which different labels should be made visible.

Another new feature of Version 12.0 is multipanel plot layout, where different datasets are shown in different panels, but the panels share axes whenever they can:

✕
ListPlot[Table[RandomReal[10,50],6],PlotLayout->{"Column",3}] |

Our curated knowledgebase—that for example powers Wolfram|Alpha—is vast and continually growing. And with every version of the Wolfram Language we’re progressively tightening its integration into the core of the language.

In Version 12.0 one thing we’re doing is to expose hundreds of types of entities directly in the language:

Before Version 12.0, the Wolfram|Alpha Example pages served as a proxy for documenting many types of entities. But now there’s Wolfram Language documentation for all of them:

There are still functions like `SatelliteData`, `WeatherData` and `FinancialData` that handle entity types that routinely need complex selection or computation. But in Version 12.0, every entity type can be accessed in the same way, with natural language (“control + =”) input, and “yellow-boxed” entities and properties:

✕
Entity["Element", "Tungsten"][ EntityProperty["Element", "MeltingPoint"]] |

By the way, one can also use entities implicitly, like here asking for the 5 elements with the highest known melting points:

✕
Entity["Element", "MeltingPoint" -> TakeLargest[5]] // EntityList |

And one can use `Dated` to get a time series of values:

✕
Entity["University", "HarvardUniversity::cmp42"][ Dated[EntityProperty["University", "EstTotalUndergrad"], All]] |

We’ve made it really convenient to work with data that’s built into the Wolfram Knowledgebase. You have entities, and it’s very easy to ask about properties and so on:

✕
Entity["City", {"NewYork", "NewYork", "UnitedStates"}]["Population"] |

But what if you have your own data? Can you set it up so you can use it as easily as this? A major new feature of Version 11 was the addition of `EntityStore`, in which one can define one’s own entity types, then specify entities, properties and values.

The Wolfram Data Repository contains a bunch of examples of entity stores. Here’s one:

✕
ResourceData["Entity Store of Books in Stephen Wolfram's Library"] |

It describes a single entity type: an `"SWLibraryBook"`. To be able to use entities of this type just like built-in entities, we “register” the entity store:

✕
EntityRegister[%] |

Now we can do things like ask for 10 random entities of type `"SWLibraryBook"`:

✕
RandomEntity["SWLibraryBook",10] |

Each entity in the entity store has a variety of properties. Here’s a dataset of the values of properties for one particular entity:

✕
Entity["SWLibraryBook", "OL4258186M::mudwv"]["Dataset"] |

OK, but with this setup we’re basically reading the whole contents of an entity store into memory. This makes it very efficient to do whatever Wolfram Language operations one wants on it. But it’s not a good scalable solution for large amounts of data—for example, data that is too big to fit in memory.

But what’s a typical source of large data? Very often it’s a database, and usually a relational one that can be accessed using SQL. We’ve had our DatabaseLink package for low-level read-write access to SQL databases for well over a decade. But in Version 12.0 we’re adding some major built-in features that allow external relational databases to be handled in the Wolfram Language just like entity stores, or built-in parts of the Wolfram Knowledgebase.

Let’s start off with a toy example. Here’s a symbolic representation of a small relational database that happens to be stored in a file:

✕
RelationalDatabase[FindFile["ExampleData/ecommerce-database.sqlite"]] |

Immediately we get a box that summarizes what’s in the database, and tells us that this database has 8 tables. If we open up the box, we can start inspecting the structure of those tables:

We can then set this relational database up as an entity store in the Wolfram Language. It looks very much the same as the library book entity store above, but now the actual data isn’t pulled into memory; instead it’s still in the external relational database, and we’re just defining a (“ORM-like”) mapping to entities in the Wolfram Language:

✕
EntityStore[%] |

Now we can register this entity store, which sets up a bunch of entity types that (at least by default) are named after the names of the tables in the database:

✕
EntityRegister[%] |

And now we can do “entity computations” on these, just like we would on built-in entities in the Wolfram Knowledgebase. Each entity here corresponds to a row in the “employees” table in the database:

✕
EntityList["employees"] |

For a given entity type, we can ask what properties it has. These “properties” correspond to columns in the table in the underlying database:

✕
EntityProperties["employees"] |

Now we can ask for the value of a particular property of a particular entity:

✕
Entity["employees", 1076][EntityProperty["employees", "lastName"]] |

We can also pick out entities by giving criteria; here we’re asking for “payments” entities with the 4 largest values of the “amount” property:

✕
EntityList[EntityClass["payments","amount"->TakeLargest[4]]] |

We can equally ask for the values of these largest amounts:

✕
EntityValue[EntityClass["payments","amount"->TakeLargest[4]],"amount"] |

OK, but here’s where it gets more interesting: so far we’ve been looking at a little file-backed database. But we can do exactly the same thing with a giant database hosted on an external server.

As an example, let’s connect to the terabyte-sized OpenStreetMap PostgreSQL database that contains what is basically the street map of the world:

As before, let’s register the tables in this database as entity types. Like most in-the-wild databases there are little glitches in the structure, which are worked around, but generate warnings:

✕
EntityRegister[EntityStore[%]] |

But now we can ask questions about the database—like how many geo points or “nodes” there are in all the streets of the world (and, yes, it’s a big number, which is why the database is big):

✕
EntityValue["planet_osm_nodes", "EntityCount"] |

Here we’re asking for the names of the objects with the 10 largest (projected) areas in the (101 GB) planet_osm_polygon table (and, yes, it takes under a second):

✕
EntityValue[ EntityClass["planet_osm_polygon", "way_area" -> TakeLargest[10]], "name"] // Timing |

So how does all this work? Basically what’s happening is that our Wolfram Language representation is getting compiled into low-level SQL queries that are then sent to be executed directly on the database server.

Sometimes you’ll ask for results that are just final values (like, say, the “amounts” above). But in other cases you’ll want something intermediate—like a collection of entities that have been selected in a particular way. And of course this collection could have a billion entries. So a very important feature of what we’re introducing in Version 12.0 is that we can represent and manipulate such things purely symbolically, resolving them to something specific only at the end.

Going back to our toy database, here’s an example of how we’d specify a class of entities obtained by aggregating the total `creditLimit` for all `customers` with a given value of `country`:

✕
AggregatedEntityClass["customers", "creditLimit" -> Total, "country"] |

At first, this is just something symbolic. But if we ask for specific values, then actual database queries get done, and we get specific results:

✕
EntityValue[%, {"country", "creditLimit"}] |

There’s a family of new functions for setting up different kinds of queries. And the functions actually work not only for relational databases, but also for entity stores, and for the built-in Wolfram Knowledgebase. So, for example, we can ask for the average atomic mass for a given period in the periodic table of elements:

✕
AggregatedEntityClass["Element", "AtomicMass" -> Mean, "Period"]["AtomicMass"] |

An important new construct is `EntityFunction`. `EntityFunction` is like `Function`, except that its variables represent entities (or classes of entities) and it describes operations that can be performed directly on external databases. Here’s an example with built-in data, in which we’re defining a “filtered” entity class in which the filtering criterion is a function which tests population values. The `FilteredEntityClass` itself is just represented symbolically, but `EntityList` actually performs the query, and resolves an explicit list of (here, unsorted) entities:

✕
FilteredEntityClass["Country", EntityFunction[c, c["Population"] > Quantity[10^8"People"]]] |

✕
EntityList[%] |

In addition to `EntityFunction`, `AggregatedEntityClass` and `SortedEntityClass`, Version 12.0 includes `SampledEntityClass` (to get a few entities from a class), `ExtendedEntityClass` (to add computed properties) and `CombinedEntityClass` (to combine properties from different classes). With these primitives, one can build up all the standard operations of “relational algebra”.

In standard database programming, one typically ends up with a whole jungle of “joins” and “foreign keys” and so on. Our Wolfram Language representation lets you operate at a higher level—where basically joins become function composition and foreign keys are just different entity types. (If you want to do explicit joins, though, you can—for example using `CombinedEntityClass`.)

What’s going on under the hood is that all those Wolfram Language constructs are getting compiled into SQL, or, more accurately, the specific dialect of SQL that’s suitable for the particular database you’re using (we currently support SQLite, MySQL, PostgreSQL and MS-SQL, with support for OracleSQL coming soon). When we do the compilation, we’re automatically checking types, to make sure you get a meaningful query. Even fairly simple Wolfram Language specifications can end up turning into many lines of SQL. For example,

✕
EntityFunction[c, c["employees"]["firstName"] <> " " <> c["employees"]["lastName"] <> " is the rep for " <> c["customerName"] <> ". Their manager is " <> c["employees"]["employees-reportsTo"]["firstName"] <> " " <> c["employees"]["employees-reportsTo"]["lastName"] <> "."][ Entity["customers", 103]] |

would produce the following intermediate SQL (here for querying the SQLite database):

The database integration system we have in Version 12.0 is pretty sophisticated—and we’ve been working on it for quite a few years. It’s an important step forward in allowing the Wolfram Language to directly handle a new level of “bigness” in big data—and to let the Wolfram Language directly do data science on terabyte-sized datasets and beyond. Like finding which street-like entities in the world have “Wolfram” in their name:

✕
FilteredEntityClass["planet_osm_line", EntityFunction[s, StringContainsQ[s["name"], "Wolfram"]]]["name"] |

What is the best way to represent knowledge about the world? It’s an issue that’s been debated by philosophers (and others) since antiquity. Sometimes people said logic was the key. Sometimes mathematics. Sometimes relational databases. But now we at least know one solid foundation (or at least, I’m pretty sure we do): everything can be represented by computation. This is a powerful idea—and in a sense that’s what makes everything we do with Wolfram Language possible.

But are there subsets of general computation that are useful for representing at least certain kinds of knowledge? One that we use extensively in the Wolfram Knowledgebase is the notion of entities (“New York City”), properties (“population”) and their values (“8.6 million people”). Of course such triples don’t represent all knowledge in the world (“what will the position of Mars be tomorrow?”). But they’re a decent start when it comes to certain kinds of “static” knowledge about distinct things.

So how can one formalize this kind of knowledge representation? One answer is through graph databases. And in Version 12.0—in alignment with many “semantic web” projects—we’re supporting graph databases using RDF, and queries against them using SPARQL. In RDF the central object is an IRI (“Internationalized Resource Identifier”), that can represent an entity or a property. A “triplestore” then consists of a collection of triples (“subject”, “predicate”, “object”), with each element in each triple being an IRI (or a literal, such as a number). The whole object can then be thought of as a graph database or graph store, or, mathematically, a hypergraph. (It’s a hypergraph because the predicate “edges” can also be vertices elsewhere.)

You can build your own `RDFStore` much like you build an `EntityStore`—and in fact you can query any Wolfram Language `EntityStore` using SPARQL just like you query an `RDFStore`. And since the entity-property part of the Wolfram Knowledgebase can be treated as an entity store, you can also query this. So here, finally, is an example. The country-city list `Entity["Country"], Entity["City"]}` in effect represents an RDF store. Then `SPARQLSelect` is an operator acting on this store. What it does is to try to find a triple that matches what you’re asking for, with a particular value for the “SPARQL variable” `x`:

✕
Needs["GraphStore`"] |

✕
SPARQLSelect[RDFTriple[Entity["Country", "USA"], EntityProperty["Country", "CapitalCity"], SPARQLVariable["x"]]][{Entity["Country"], Entity["City"]}] |

Of course, there’s also a much simpler way to do this in the Wolfram Language:

✕
Entity["Country", "USA"][EntityProperty["Country", "CapitalCity"]] |

But with SPARQL you can do much more exotic things—like ask what properties relate the US to Mexico:

✕
SPARQLSelect[RDFTriple[Entity["Country", "USA"],SPARQLVariable["x"],Entity["Country", "Mexico"]]][{Entity["Country"]}] |

Or whether there is a path based on the bordering country relation from Portugal to Germany:

✕
SPARQLAsk[ SPARQLPropertyPath[ Entity["Country", "Portugal"], {EntityProperty["Country", "BorderingCountries"] ..}, Entity["Country", "Germany"]]][Entity["Country"]] |

In principle you can just write a SPARQL query as a string (a bit like you can write an SQL string). But what we’ve done in Version 12.0 is introduce a symbolic representation of SPARQL that allows computation on the representation itself, making it easy, for example, to automatically generate complex SPARQL queries. (And it’s particularly important to do this because, on their own, practical SPARQL queries have a habit of getting extremely long and ponderous.)

OK, but are there RDF stores out in the wild? It’s been a long-running hope that a large part of the web will somehow eventually be tagged enough to “become semantic” and in effect be a giant RDF store. It’d be great if this happened, but so far it definitely hasn’t. Still, there are a few public RDF stores out there, and also some RDF stores within organizations, and with our new capabilities in Version 12.0 we’re in a unique position to do interesting things with them.

An incredibly common form of problem in industrial applications of mathematics is: “What configuration minimizes cost (or maximizes payoff) if certain constraints have to be satisfied?” More than half a century ago, the so-called simplex algorithm was invented for solving linear versions of this kind of problem, in which both the objective function (cost, payoff) and the constraints are linear functions of the variables in the problem. By the 1980s much more efficient (“interior point”) methods had been invented—and we’ve had these for doing “linear programming” in the Wolfram Language for a long time.

But what about nonlinear problems? Well, in the general case, one can use functions like `NMinimize`. And they do a state-of-the-art job. But it’s a hard problem. However, some years ago, it became clear that even among nonlinear optimization problems, there’s a class of so-called convex optimization problems that can actually be solved almost as efficiently as linear ones. (“Convex” means that both the objective and the constraints involve only convex functions—so that nothing can “wiggle” as one approaches an extremum, and there can’t be any local minima that aren’t global minima.)

In Version 12.0, we’ve now got strong implementations for all the various standard classes of convex optimization. Here’s a simple case, involving minimizing a quadratic form with a couple of linear constraints:

✕
QuadraticOptimization[2x^2+20y^2+6x y+5x,{-x+y>=2,y>=0},{x,y}] |

`NMinimize` could already do this particular problem in Version 11.3:

✕
NMinimize[{2x^2+20y^2+6x y+5x,{-x+y>=2,y>=0}},{x,y}] |

But if one had more variables, the old `NMinimize` would quickly bog down. In Version 12.0, however, `QuadraticOptimization` will continue to work just fine, up to more than 100,000 variables with more than 100,000 constraints (so long as they’re fairly sparse).

In Version 12.0 we’ve got “raw convex optimization” functions like `SemidefiniteOptimization` (that handles linear matrix inequalities) and `ConicOptimization` (that handles linear vector inequalities). But functions like `NMinimize` and `FindMinimum` will also automatically recognize when a problem can be solved efficiently by being transformed to a convex optimization form.

How does one set up convex optimization problems? Larger ones involve constraints on whole vectors or matrices of variables. And in Version 12.0 we now have functions like `VectorGreaterEqual` (input as ≥) that can immediately represent these.

Partial differential equations are hard, and we’ve been working on more and more sophisticated and general ways to handle them for 30 years. We first introduced `NDSolve` (for ODEs) in Version 2, back in 1991. We had our first (1+1-dimensional) numerical PDEs by the mid-1990s. In 2003 we introduced our powerful, modular framework for handling numerical differential equations. But in terms of PDEs we were still basically only dealing with simple, rectangular regions. To go beyond that required building our whole computational geometry system, which we introduced in Version 10. And with this, we released our first finite element PDE solvers. In Version 11, we then generalized to eigen problems.

Now, in Version 12, we’re introducing another major generalization: nonlinear finite element analysis. Finite element analysis involves decomposing regions into little discrete triangles, tetrahedra, etc.—on which the original PDE can be approximated by a large number of coupled equations. When the original PDE is linear, these equations will also be linear—and that’s the typical case people consider when they talk about “finite element analysis”.

But there are many PDEs of practical importance that aren’t linear—and to tackle these one needs nonlinear finite element analysis, which is what we now have in Version 12.0.

As an example, here’s what it takes to solve the nastily nonlinear PDE that describes the height of a 2D minimal surface (say, an idealized soap film), here over an annulus, with (Dirichlet) boundary conditions that make it wiggle sinusoidally at the edges (as if the soap film were suspended from wires):

✕
NDSolveValue[{Inactive[Div][(1/Sqrt[1 + \!\( \*SubscriptBox[\(\[Del]\), \({x, y}\)]\(u[x, y]\)\).\!\( \*SubscriptBox[\(\[Del]\), \({x, y}\)]\(u[x, y]\)\)]) Inactive[Grad][ u[x, y], {x, y}], {x, y}] == 0, DirichletCondition[u[x, y] == Sin[2 \[Pi] (x + y)], True]}, u, {x, y} \[Element] Region[Annulus[{0, 0}, {0.3, 1}]]] |

On my computer it takes just a quarter of a second to solve this equation, and get an interpolating function. Here’s a plot of the interpolating function representing the solution:

✕
Plot3D[%[x, y], {x, y} \[Element] Region[Annulus[{0, 0}, {0.3, 1}]] , MeshFunctions -> {#3 &}] |

We’ve put a lot of engineering into optimizing the execution of Wolfram Language programs over the years. Already in 1989 we started automatically compiling simple machine-precision numerical computations to instructions for an efficient virtual machine (and, as it happens, I wrote the original code for this). Over the years, we’ve extended the capabilities of this compiler, but it’s always been limited to fairly simple programs.

In Version 12.0 we’re taking a major step forward, and we’re releasing the first version of a new, much more powerful compiler that we’ve been working on for several years. This compiler is both able to handle a much broader range of programs (including complex functional constructs and elaborate control flows), and it’s also compiling not to a virtual machine but instead directly to optimized native machine code.

In Version 12.0 we still consider the new compiler experimental. But it’s advancing rapidly, and it’s going to have a dramatic effect on the efficiency of lots of things in the Wolfram Language. In Version 12.0, we’re just exposing a “kit form” of the new compiler, with specific compilation functions. But we’ll progressively be making the compiler operate more and more automatically—figuring out with machine learning and other methods when it’s worth taking the time to do what level of compilation.

At a technical level, the new Version 12.0 compiler is based on LLVM, and works by generating LLVM code—linking in the same low-level runtime library that the Wolfram Language kernel itself uses, and calling back to the full Wolfram Language kernel for functionality that isn’t in the runtime library.

Here’s the basic way one compiles a pure function in the current version of the new compiler:

✕
FunctionCompile[Function[Typed[x,"Integer64"],x^2]] |

The resulting compiled code function works just like the original function, though faster:

✕
%[12] |

A big part of what lets `FunctionCompile` produce a faster function is that you’re telling it to make assumptions about the type of argument it’s going to get. We’re supporting lots of basic types (like `"Integer32"` and `"Real64"`). But when you use `FunctionCompile`, you’re committing to particular argument types, so much more streamlined code can be produced.

A lot of the sophistication of the new compiler is associated with inferring what types of data will be generated in the execution of a program. (There are lots of graph theoretic and other algorithms involved, and needless to say, all the metaprogramming for the compiler is done with the Wolfram Language.)

Here’s an example that involves a bit of type inference (the type of `fib` is deduced to be `"Integer64""Integer64"`: an integer function returning an integer):

✕
FunctionCompile[Function[{Typed[n,"Integer64"]},Module[{fib},fib=Function[{x},If[x<=1,1,fib[x-1]+fib[x-2]]]; fib[n]]]] |

On my computer `cf`[25] runs about 300 times faster than the uncompiled function. (Of course, the compiled version fails when its output is no longer of type `"Integer64"`, but the standard Wolfram Language version continues to work just fine.)

Already the compiler can handle hundreds of Wolfram Language programming primitives, appropriately tracking what types are produced—and generating code that directly implements these primitives. Sometimes, however, one will want to use sophisticated functions in the Wolfram Language for which it doesn’t make sense to generate one’s own compiled code—and where what one really wants to do is just to call into the Wolfram Language kernel for these functions. In Version 12.0 `KernelFunction` lets one do this:

✕
FunctionCompile[Function[Typed[x,"Real64"],Typed[KernelFunction[AiryAi],{"Real64"}->"Real64"][x]]] |

OK, but let’s say one’s got a compiled code function. What can one do with it? Well, first of all one can just run it inside the Wolfram Language. One can store it too, and run it later. Any particular compilation is done for a specific processor architecture (e.g. 64-bit x86). But `CompiledCodeFunction` automatically keeps enough information to do additional compilation for a different architecture if it’s needed.

But given a `CompiledCodeFunction`, one of the interesting new possibilities is that one can directly generate code that can be run even outside the Wolfram Language environment. (Our old compiler had the `CCodeGenerate` package which provided slightly similar capabilities in simple cases—though even then relies on an elaborate toolchain of C compilers etc.)

Here’s how one can export raw LLVM code (notice that things like tail recursion optimization automatically get done—and notice also the symbolic function and compiler options at the end):

✕
FunctionCompileExportString[Function[{Typed[n,"Integer64"]},Module[{fib},fib=Function[{x},If[x<=1,1,fib[x-1]+fib[x-2]]]; fib[n]]]] |

If one uses `FunctionCompileExportLibrary`, then one gets a library file—.dylib on Mac, .dll on Windows and .so on Linux. One can use this in the Wolfram Language by doing `LibraryFunctionLoad`. But one can also use it in an external program.

One of the main things that determines the generality of the new compiler is the richness of its type system. Right now the compiler supports 14 atomic types (such as `"Boolean"`, `"Integer8"`, `"Complex64"`, etc.). It also supports type constructors like `"PackedArray"`—so that, for example, `TypeSpecifier["PackedArray"]["Real64", 2]` corresponds to a rank-2 packed array of 64-bit reals.

In the internal implementation of the Wolfram Language (which, by the way, is itself mostly in Wolfram Language) we’ve had an optimized way to store arrays for a long time. In Version 12.0 we’re exposing it as `NumericArray`. Unlike ordinary Wolfram Language constructs, you have to tell `NumericArray` in detail how it should store data. But then it works in a nice, optimized way:

✕
NumericArray[Range[10000], "UnsignedInteger16"] |

✕
ByteCount[%] |

✕
ByteCount[Range[10000]] |

In Version 11.2 we introduced `ExternalEvaluate`, that lets you do computations in languages like Python and JavaScript from within the Wolfram Language (in Python, “^” means `BitXor`):

✕
ExternalEvaluate["Python", "23424^2542"] |

In Version 11.3, we introduced external language cells, to make it easy to enter external-language programs or other input directly in a notebook:

✕
ExternalEvaluate["Python", "23424^2542"] |

In Version 12.0, we’re tightening the integration. For example, inside an external language string, you can use <* ... *> to give Wolfram Language code to evaluate:

✕
ExternalEvaluate["Python","<* Prime[1000] *> + 10"] |

This works in external language cells too:

✕
ExternalEvaluate["Python", "<* Prime[1000] *> + 10"] |

Of course, Python is not Wolfram Language, so many things don’t work:

✕
ExternalEvaluate["Python","2+ <* Range[10] *>"] |

But `ExternalEvaluate` can at least return many types of data from Python, including lists (as `List`), dictionaries (as `Association`), images (as `Image`), dates (as `DateObject`), NumPy arrays (as `NumericArray`) and pandas datasets (as `TimeSeries`, `Dataset`, etc.). (`ExternalEvaluate` can also return `ExternalObject` that’s basically a handle to an object that you can send back to Python.)

You can also directly use external functions (the slightly bizarrely named ord is basically the Python analog of `ToCharacterCode`):

✕
ExternalFunction["Python", "ord"]["a"] |

And here’s a Python pure function, represented symbolically in the Wolfram Language:

✕
ExternalFunction["Python", "lambda x:x+1"] |

✕
%[100] |

How should one access the Wolfram Language? There are many ways. One can use it directly in a notebook. One can call APIs that execute it in the cloud. Or one can use WolframScript in a command-line shell. WolframScript can run either against a local Wolfram Engine, or against a Wolfram Engine in the cloud. It lets you directly give code to execute:

And it lets you do things like define functions, for example with code in a file:

Along with the release of Version 12.0, we’re also releasing our first new Wolfram Language Client Library—for Python. The basic idea of this library is to make it easy for Python programs to call the Wolfram Language. (It’s worth pointing out that we’ve effectively had a C Language Client Library for no less than 30 years—through what’s now called WSTP.)

The way a Language Client Library works is different for different languages. For Python—as an interpreted language (that was actually historically informed by early Wolfram Language)—it’s particularly simple. After you set up the library, and start a session (locally or in the cloud), you can then just evaluate Wolfram Language code and get the results back in Python:

You can also directly access Wolfram Language functions (as a kind of inverse of `ExternalFunction`):

And you can directly interact with things like pandas structures, NumPy arrays, etc. In fact, you can in effect just treat the whole of the Wolfram Language like a giant library that can be accessed from Python. Or, of course, you can just use the nice, integrated Wolfram Language directly, perhaps creating external APIs if you need them.

One feature of using the Wolfram Language is that it lets you get away from having to think about the details of your computer system, and about things like files and processes. But sometimes one wants to work at a systems level. And for fairly simple operations, one can just use an operating system GUI. But what about for more complicated things? In the past I usually found myself using the Unix shell. But for a long time now, I’ve instead used Wolfram Language.

It’s certainly very convenient to have everything in a notebook, and it’s been great to be able to programmatically use functions like `FileNames` (ls), `FindList` (grep), `SystemProcessData` (ps), `RemoteRunProcess` (ssh) and `FileSystemScan`. But in Version 12.0 we’re adding a bunch of additional functions to support using the Wolfram Language as a “super shell”.

There’s `RemoteFile` for symbolically representing a remote file (with authentication if needed)— that you can immediately use in functions like `CopyFile`. There’s `FileConvert` for directly converting files between different formats.

And if you really want to dive deep, here’s how you’d trace all the packets on ports 80 and 443 used in reading from wolfram.com:

✕
NetworkPacketTrace[URLRead["wolfram.com"], {80, 443}] |

Within the Wolfram Language, it’s been easy for a long time to interact with web servers, using functions like `URLExecute` and `HTTPRequest`, as well as `$Cookies`, etc. But in Version 12.0 we’re adding something new: the ability of the Wolfram Language to control a web browser, and programmatically make it do what we want. The most immediate thing we can do is just to get an image of what a website looks like to a web browser:

✕
WebImage["https://www.wolfram.com"] |

The result is an image that we can compute with:

✕
EdgeDetect[%] |

To do something more detailed, we have to start a browser session (we currently support Firefox and Chrome):

✕
session = StartWebSession["Chrome"] |

Immediately a blank browser window appears on our screen. Now we can use `WebExecute` to open a webpage:

✕
WebExecute["OpenPage" -> "http://www.wolfram.com"] |

Now that we’ve opened the page, there are lots of commands we can run. This clicks the first hyperlink containing the text “Programming Lab”:

✕
WebExecute[ "ClickElement" -> "PartialHyperlinkText" -> "Programming Lab"] |

This returns the title of the page we’ve reached:

✕
WebExecute["PageTitle"] |

You can type into fields, run JavaScript, and basically do programmatically anything you could do by hand with a web browser. Needless to say, we’ve been using a version of this technology for years inside our company to test all our various websites and web services. But now, in Version 12.0, we’re making a streamlined version generally available.

For every general-purpose computer in the world today, there are probably 10 times as many microcontrollers—running specific computations without any general operating system. A microcontroller might cost a few cents to a few dollars, and in something like a mid-range car, there might be 30 of them.

In Version 12.0 we’re introducing a Microcontroller Kit for the Wolfram Language, that lets you give symbolic specifications from which it automatically generates and deploys code to run autonomously in microcontrollers. In the typical setup, a microcontroller is continuously doing computations on data coming in from sensors, and in real time putting out signals to actuators. The most common types of computations are effectively ones in control theory and signal processing.

We’ve had extensive support for doing control theory and signal processing directly in the Wolfram Language for a long time. But now what’s possible with the Microcontroller Kit is to take what’s specified in the language and download it as embedded code in a standalone microcontroller that can be deployed anywhere (in devices, IoT, appliances, etc.).

As an example, here’s how one can generate a symbolic representation of an analog signal-processing filter:

✕
ButterworthFilterModel[{3,2}] |

We can use this filter directly in the Wolfram Language—say using `RecurrenceFilter` to apply it to an audio signal. We can also do things like plot its frequency response:

✕
BodePlot[%] |

To deploy the filter in a microcontroller, we first have to derive from this continuous-time representation a discrete-time approximation that can be run in a tight loop (here, every 0.1 seconds) in the microcontroller:

✕
filter=ToDiscreteTimeModel[ButterworthFilterModel[{3,2}],0.1]//Chop |

Now we’re ready to use the Microcontroller Kit to actually deploy this to a microcontroller. The kit supports more than a hundred different types of microcontrollers. Here’s how we could deploy the filter to an Arduino Uno that we have connected to a serial port on our computer:

✕
Needs["MicrocontrollerKit`"] |

✕
MicrocontrollerEmbedCode[filter,<|"Target"->"ArduinoUno","Inputs"->"Serial","Outputs"->"Serial"|>,"/dev/cu.usbmodem141101"] |

`MicrocontrollerEmbedCode` works by generating appropriate C-like source code, compiling it for the microcontroller architecture you want, then actually deploying it to the microcontroller through its so-called programmer. Here’s the actual source code that was generated in this particular case:

✕
%["SourceCode"] |

So now we have a thing like this that runs our Butterworth filter, that we can use anywhere:

If we want to check what it’s doing, we can always connect it back into the Wolfram Language using `DeviceOpen` to open its serial port, and read and write from it.

What’s the relation between the Wolfram Language and video games? Over the years, the Wolfram Language has been used behind the scenes in many aspects of game development (simulating strategies, creating geometries, analyzing outcomes, etc.). But for some time now we’ve been working on a closer link between Wolfram Language and the Unity game environment, and in Version 12.0 we’re releasing a first version of this link.

The basic scheme is to have Unity running alongside the Wolfram Language, then to set up two-way communication, allowing both objects and commands to be exchanged. The under-the-hood plumbing is quite complex, but the result is a nice merger of the strengths of Wolfram Language and Unity.

This sets up the link, then starts a new project in Unity:

✕
Needs["UnityLink`"] |

✕
UnityOpen["NewProject"] |

Now create some complex shape:

✕
RevolutionPlot3D[{Sin[t] + Sin[5 t]/10, Cos[t] + Cos[5 t]/10}, {t, 0, Pi}, Sequence[ RegionFunction -> (Sin[5 (#4 + #5)] > 0& ), Boxed -> False, Axes -> None, PlotTheme -> "ThickSurface"]] |

Then it takes just one command to put this into the Unity game as an object called `"thingoid"`:

✕
CreateUnityGameObject["thingoid", CloudGet["https://wolfr.am/COrZtVvA"], Properties -> { "SharedMaterial" -> UnityLink`CreateUnityMaterial[Orange]}] |

Within the Wolfram Language there’s a symbolic representation of the object, and UnityLink now provides hundreds of functions for manipulating such objects, always maintaining versions both in Unity and in the Wolfram Language.

It’s very powerful that one can take things from the Wolfram Language and immediately put them into Unity—whether they’re geometry, images, audio, geo terrain, molecular structures, 3D anatomy, or whatever. It’s also very powerful that such things can then be manipulated within the Unity game, either through things like game physics, or by user action. (Eventually, one can expect to have `Manipulate`-like functionality, in which the controls aren’t just sliders and things, but complex pieces of gameplay.)

We’ve done experiments with putting Wolfram Language–generated content into virtual reality since the early 1990s. But in modern times Unity has become something of a de facto standard for setting up VR/AR environments—and with UnityLink it’s now straightforward to routinely put things from Wolfram Language into any modern XR environment.

One can use the Wolfram Language to prepare material for Unity games, but within a Unity game UnityLink also basically lets one just insert Wolfram Language code that can be executed during a game either on a local machine or through an API in the Wolfram Cloud. And, among other things, this makes it straightforward to put hooks into a game so the game can send “telemetry” (say to the Wolfram Data Drop) for analysis in the Wolfram Language. (It’s also possible to script the playing of the game—which is, for example, very useful for game testing.)

Writing games is a complex matter. But UnityLink provides an interesting new approach that should make it easier to prototype all sorts of games, and to learn the ideas of game development. One reason for this is that it effectively lets one script a game at a higher level by using symbolic constructs in the Wolfram Language. But another reason is that it lets the development process be done incrementally in a notebook, and explained and documented every step of the way. For example, here’s what amounts to a computational essay describing the development of a “piano game”:

UnityLink isn’t a simple thing: it contains more than 600 functions. But with those functions it’s possible to access pretty much all the capabilities of Unity, and to set up pretty much any imaginable game.

For something like reinforcement learning it’s essential to have a manipulable external environment in the loop when one’s doing machine learning. Well, `ServiceExecute` lets you call APIs (what’s the effect of posting that tweet, or making that trade?), and `DeviceExecute` lets you actuate actual devices (turn the robot left) and get data from sensors (did the robot fall over?).

But for many purposes what one instead wants is to have a simulated external environment. And in a way, just the pure Wolfram Language already to some extent does that, for example providing access to a rich “computational universe” full of modifiable programs and equations (cellular automata, differential equations, …). And, yes, the things in that computational universe can be informed by the real world—say with the realistic properties of oceans, or chemicals or mountains.

But what about environments that are more like the ones we modern humans typically learn in—full of built engineering structures and so on? Conveniently enough, `SystemModel` gives access to lots of realistic engineering systems. And through UnityLink we can expect to have access to rich game-based simulations of the world.

But as a first step, in Version 12.0 we’re setting up connections to some simple games—in particular from the OpenAI “gym”. The interface is much as it would be for interacting with the real world, with the game accessed like a “device” (after appropriate sometimes-“open-source-painful” installation):

✕
env = DeviceOpen["OpenAIGym", "MontezumaRevenge-v0"] |

We can read the state of the game:

✕
DeviceRead[env] |

And we can show it as an image:

✕
Image[DeviceRead[env]["ObservedState"]] |

With a bit more effort, we can take 100 random actions in the game (always checking that we didn’t “die”), then show a feature space plot of the observed states of the game:

✕
FeatureSpacePlot[ Table[If[DeviceRead[env]["Ended"], Return[], Image[DeviceExecute[env, "Step", DeviceExecute[env, "RandomAction"]]["ObservedState"]]], 100]] |

In Version 11.3 we began our first connection to the blockchain. Version 12.0 adds a lot of new features and capabilities, perhaps most notably the ability to write to public blockchains, as well as read from them. (We also have our own Wolfram Blockchain for Wolfram Cloud users.) We’re currently supporting Bitcoin, Ethereum and ARK blockchains, both their mainnets and testnets (and, yes, we have our own nodes connecting directly to these blockchains).

In Version 11.3 we allowed raw reading of transactions from blockchains. In Version 12.0 we’ve added a layer of analysis, so that, for example, you can ask for a summary of “CK” tokens (AKA CryptoKitties) on the Ethereum blockchain:

✕
BlockchainTokenData["CK"] |

It’s quick to look at all token transactions in history, and make a word cloud of how active different tokens have been:

✕
WordCloud[SortBy[BlockchainTokenData[All,{"Name","TransfersCount"}],Last]] |

But what about doing our own transaction? Let’s say we want to use a Bitcoin ATM (like the one that, bizarrely, exists at a bagel store near me) to transfer cash to a Bitcoin address. Well, first we create our crypto keys (and we need to make sure we remember our private key!):

✕
keys=GenerateAsymmetricKeyPair["Bitcoin"] |

Next, we have to take our public key and generate a Bitcoin address from it:

✕
BlockchainKeyEncode[keys["PublicKey"],"Address",BlockchainBase->"Bitcoin"] |

Make a QR code from that and you’re ready to go to the ATM:

✕
BarcodeImage[%,"QR"] |

But what if we want to write to the blockchain ourselves? Here we’ll use the Bitcoin testnet (so we’re not spending real money). This shows an output from a transaction we did before—that includes 0.0002 bitcoin (i.e. 20,000 satoshi):

✕
$BlockchainBase={"Bitcoin", "Testnet"}; |

✕
First[BlockchainTransactionData["17a422eebfbf9cdee19b600740597bafea45cc4c703c67afcc8fb889f4cf7f28","Outputs"]] |

Now we can set up a transaction which takes this output, and, for example, sends 8000 satoshi to each of two addresses (that we defined just like for the ATM transaction):

✕
BlockchainTransaction[<| "Inputs" -> {<| "TransactionID" -> "17a422eebfbf9cdee19b600740597bafea45cc4c703c67afcc8fb889f4cf7f28", "Index" -> 0|>}, "Outputs" -> {<|"Amount" -> Quantity[8000, "Satoshi"], "Address" -> "munDTMqa9V9Uhi3P21FpkY8UfYzvQqpmoQ"|>, <| "Amount" -> Quantity[8000, "Satoshi"], "Address" -> "mo9QWLSJ1g1ENrTkhK9SSyw7cYJfJLU8QH"|>}, "BlockchainBase" -> {"Bitcoin", "Testnet"}|>] |

OK, so now we’ve got a blockchain transaction object—that would offer a fee (shown in red because it’s “actual money” you’ll spend) of all the leftover cryptocurrency (here 4000 satoshi) to a miner willing to put the transaction in the blockchain. But before we can submit this transaction (and “spend the money”) we have to sign it with our private key:

✕
BlockchainTransactionSign[%, keys["PrivateKey"]] |

Finally, we just apply `BlockchainTransactionSubmit` and we’ve submitted our transaction to be put on the blockchain:

✕
BlockchainTransactionSubmit[%] |

Here’s its transaction ID:

✕
txid=%["TransactionID"] |

If we immediately ask about this transaction, we’ll get a message saying it isn’t in the blockchain:

✕
BlockchainTransactionData[txid] |

But after we wait a few minutes, there it is—and it’ll soon spread to every copy of the Bitcoin testnet blockchain:

✕
BlockchainTransactionData[txid] |

If you’re prepared to spend real money, you can use exactly the same functions to do a transaction on a main net. You can also do things like buy CryptoKitties. Functions like `BlockchainContractValue` can be used for any (for now, only Ethereum) smart contract, and are set up to immediately understand things like ERC-20 and ERC-721 tokens.

Dealing with blockchains involves lots of cryptography, some of which is new in Version 12.0 (notably, handling elliptic curves). But in Version 12.0 we’re also extending our non-blockchain cryptographic functions. For example, we’ve now got functions for directly dealing with digital signatures. This creates a digital signature using the private key from above:

✕
message="This is my genuine message"; |

✕
signature=GenerateDigitalSignature[message,keys["PrivateKey"]] |

Now anyone can verify the message using the corresponding public key:

✕
VerifyDigitalSignature[{message,signature},keys["PublicKey"]] |

In Version 12.0, we added several new types of hashes for the `Hash` function, particularly to support various cryptocurrencies. We also added ways to generate and verify derived keys. Start from any password, and `GenerateDerivedKey` will “puff it out” to something longer (to be more secure you should add “salt”):

✕
GenerateDerivedKey["meow"] |

Here’s a version of the derived key, suitable for use in various authentication schemes:

✕
GenerateDerivedKey["meow"]["PHCString"] |

The Wolfram Knowledgebase contains all sorts of financial data. Typically there’s a financial entity (like a stock), then there’s a property (like price). Here’s the complete daily history of Apple’s stock price (it’s very impressive that it looks best on a log scale):

✕
DateListLogPlot[Entity["Financial", "NASDAQ:AAPL"][Dated["Price",All]]] |

But while the financial data in the Wolfram Knowledgebase, and standardly available in the Wolfram Language, is continuously updated, it’s not real time (mostly it’s 15-minute delayed), and it doesn’t have all the detail that many financial traders use. For serious finance use, however, we’ve developed Wolfram Finance Platform. And now, in Version 12.0, it’s got direct access to Bloomberg and Reuters financial data feeds.

The way we architect the Wolfram Language, the framework for the connections to Bloomberg and Reuters is always available in the language—but it’s only activated if you have Wolfram Finance Platform, as well as the appropriate Bloomberg or Reuters subscriptions. But assuming you have these, here’s what it looks like to connect to the Bloomberg Terminal service:

✕
ServiceConnect["BloombergTerminal"] |

All the financial instruments handled by the Bloomberg Terminal now become available as entities in the Wolfram Language:

✕
Entity["BloombergTerminal","AAPL US Equity"] |

Now we can ask for properties of this entity:

✕
%["PX_LAST"] |

Altogether there are more than 60,000 properties accessible from the Bloomberg Terminal:

✕
Length[EntityProperties["BloombergTerminal"]] |

Here are 5 random examples (yes, they’re pretty detailed; those are Bloomberg names, not ours):

✕
RandomSample[EntityProperties["BloombergTerminal"],5] |

We support the Bloomberg Terminal service, the Bloomberg Data License service, and the Reuters Elektron service. One sophisticated thing one can now do is to set up a continuous task to asynchronously receive data, and call a “handler function” every time a new piece of data comes in:

✕
ServiceSubmit[ ContinuousTask[ServiceRequest[ServiceConnect["Reuters"], "MarketData",{"Instrument"-> "AAPL.O","TriggerFields"->{"BID","ASK"}}]], HandlerFunctions-><|"MarketDataEvents"->(action[#Result]&)|>] |

I’ve talked about lots of new functions and new functionality in the Wolfram Language. But what about the underlying infrastructure of the Wolfram Language? Well, we’ve been working hard on that too. For example, between Version 11.3 and Version 12.0 we’ve managed to fix nearly 8000 reported bugs. We’ve also made lots of things faster and more robust. And in general we’ve been tightening the software engineering of the system, for example reducing the initial download size by nearly 10% (despite all the functionality that’s been added). (We’ve also done things like improve the predictive prefetching of knowledgebase elements from the cloud—so when you need similar data it’s more likely to be already cached on your computer.)

It’s a longstanding feature of the computing landscape that operating systems are continually getting updated—and to take advantage of their latest features, applications have to get updated too. We’ve been working for several years on a major update to our Mac notebook interface—which is finally ready in Version 12.0. As part of the update, we’ve rewritten and restructured large amounts of code that have been developed and polished over more than 20 years, but the result is that in Version 12.0, everything about our system on the Mac is fully 64-bit, and makes use of the latest Cocoa APIs. This means that the notebook front end is significantly faster—and can also go beyond the previous 2 GB memory limit.

There’s also a platform update on Linux, where now the notebook interface fully supports Qt 5, which allows all rendering operations to take place “headlessly”, without any X server—greatly streamlining deployment of the Wolfram Engine in the cloud. (Version 12.0 doesn’t yet have high-dpi support for Windows, but that’s coming very soon.)

The development of the Wolfram Cloud is in some ways separate from the development of the Wolfram Language, and Wolfram Desktop applications (though for internal compatibility we’re releasing Version 12.0 at the same time in both environments). But in the past year since Version 11.3 was released, there’s been dramatic progress in the Wolfram Cloud.

Especially notable are the advances in cloud notebooks—supporting more interface elements (including some, like embedded websites and videos, that aren’t even yet available in desktop notebooks), as well as greatly increased robustness and speed. (Making our whole notebook interface work in a web browser is no small feat of software engineering, and in Version 12.0 there are some pretty sophisticated strategies for things like maintaining consistent fast-to-load caches, along with full symbolic DOM representations.)

In Version 12.0 there’s now just a simple menu item (File > Publish to Cloud …) to publish any notebook to the cloud. And once the notebook is published, anyone in the world can interact with it—as well as make their own copy so they can edit it.

It’s interesting to see how broadly the cloud has entered what can be done in the Wolfram Language. In addition to all the seamless integration of the cloud knowledgebase, and the ability to reach out to things like blockchains, there are also conveniences like Send To… sending any notebook through email, using the cloud if there’s no direct email server connection available.

Even though this has been a long piece, it’s not even close to telling the whole story of what’s new in Version 12.0. Along with the rest of our team, I’ve been working very hard on Version 12.0 for a long time now—but it’s still exciting to see just how much is actually in it.

But what’s critical (and a lot of work to achieve!) is that everything we’ve added is carefully designed to fit coherently with what’s already there. From the very first version more than 30 years ago of what’s now the Wolfram Language, we’ve been following the same core principles—and this is part of what’s allowed us to so dramatically grow the system while maintaining long-term compatibility.

It’s always difficult to decide exactly what to prioritize developing for each new version, but I’m very pleased with the choices we made for Version 12.0. I’ve given many talks over the past year, and I’ve been very struck with how often I’ve been able to say about things that come up: “Well, it so happens that that’s going to be part of Version 12.0!”

I’ve personally been using internal preliminary builds of Version 12.0 for nearly a year, and I’ve come to take for granted many of its new capabilities—and to use and enjoy them a lot. So it’s a great pleasure that today we have the final Version 12.0—with all these new capabilities officially in it, ready to be used by anyone and everyone…

]]>**Read Stephen Wolfram’s Reddit AMA about this essay »**

I’m a person who’s only satisfied if I feel I’m being productive. I like figuring things out. I like making things. And I want to do as much of that as I can. And part of being able to do that is to have the best personal infrastructure I can. Over the years I’ve been steadily accumulating and implementing “personal infrastructure hacks” for myself. Some of them are, yes, quite nerdy. But they certainly help me be productive. And maybe in time more and more of them will become mainstream, as a few already have.

Now, of course, one giant “productivity hack” that I’ve been building for the world for a very long time is the whole technology stack around the Wolfram Language. And for me personally, another huge “productivity hack” is my company, which I started more than 32 years ago. Yes, it could (and should) be larger, and have more commercial reach. But as a nicely organized private company with about 800 people it’s an awfully efficient machine for turning ideas into real things, and for leveraging what skills I have to greatly amplify my personal productivity.

I could talk about how I lead my life, and how I like to balance doing leadership, doing creative work, interacting with people, and doing things that let me learn. I could talk about how I try to set things up so that what I’ve already built doesn’t keep me so busy I can’t start anything new. But instead what I’m going to focus on here is my more practical personal infrastructure: the technology and other things that help me live and work better, feel less busy, and be more productive every day.

At an intellectual level, the key to building this infrastructure is to structure, streamline and automate everything as much as possible—while recognizing both what’s realistic with current technology, and what fits with me personally. In many ways, it’s a good, practical exercise in computational thinking, and, yes, it’s a good application of some of the tools and ideas that I’ve spent so long building. Much of it can probably be helpful to lots of other people too; some of it is pretty specific to my personality, my situation and my patterns of activity.

To explain my personal infrastructure, I first have to say a bit about my daily life. Something that often surprises people is that for 28 years I’ve been a remote CEO. I’m about as hands-on a CEO as they come. But I’m only physically “in the office” a few times a year. Mostly I’m just at home, interacting with the company with great intensity—but purely through modern virtual means:

I’m one of those CEOs who actually does a lot of stuff myself, as well as managing other people to do things. Being a remote CEO helps me achieve that, and stay focused. And partly following my example, our company has evolved a very distributed culture, with people working scattered all over the world (it’s all about being productive, rather than about “showing up”):

At my desk, though, my basic view of all this is just:

It’s always set up the same way. On the right is my main “public display” monitor that I’ll be screensharing most of the day with people I’m talking to. On the left is my secondary “private display” monitor that’s got my email and messages and other things that aren’t directly relevant to the meetings I’m doing.

For the past year or so, I’ve been livestreaming many of our software design meetings—and there are now 250 hours of archived screensharing, all from that right monitor of mine.

Particularly since I’m at my desk much of each day, I’ve tried to optimize its ergonomics. The keyboard is at the right height for optimal typing. The monitors are at a height that—especially given my “computer distance” multifocal glasses—forces my head to be in a good position when I look at them, and not hunched over. I still use a “roll-around” mouse (on the left, since I’m left-handed)—because at least according to my latest measurements I’m still faster with that than with any other pointing technology.

At the touch of a button, my desk goes to standing height:

But while standing may be better than sitting, I like to at least start my day with something more active, and for more than a decade I’ve been making sure to walk for a couple of hours every morning. But how can I be productive while I’m walking? Well, nearly 15 years ago (i.e. long before it was popular!) I set up a treadmill with a computer in the room next to my office:

The biomechanics weren’t too hard to work out. I found out that by putting a gel strip at the correct pivot point under my wrists (and putting the mouse on a platform) I can comfortably type while I’m walking. I typically use a 5% incline and go at 2 mph—and I’m at least fit enough that I don’t think anyone can tell I’m walking while I’m talking in a meeting. (And, yes, I try to get potentially frustrating meetings scheduled during my walking time, so if I do in fact get frustrated I can just “walk it off” by making the treadmill go a little faster.)

For many years I’ve kept all kinds of personal analytics data on myself, and for the past couple of years this has included continuous heart-rate data. Early last summer I noticed that for a couple of weeks my resting heart rate had noticeably gone down. At first I thought it was just because I happened to be systematically doing something I liked then. But later in the summer, it happened again. And then I realized: those were times when I wasn’t walking inside on a treadmill; instead (for different reasons) I was walking outside.

For many years my wife had been extolling the virtues of spending time outside. But it had never really seemed practical for me. Yes, I could talk on the phone (or, in rare cases, actually talk to someone I was walking with). Or I could be walking with a tablet, perhaps watching someone else screensharing—as I did, rather unstylishly, for a week late last summer during my version of a vacation:

I’d actually been thinking about walking and working for a long time. Twenty years ago I imagined doing it with an augmented reality display and a one-handed (chorded) keyboard. But the technology didn’t arrive, and I wasn’t even sure the ergonomics would work out (would it make me motion sick, for example?).

But then, last spring, I was at a fancy tech event, and I happened to be just out of the frame of a photo op that involved Jeff Bezos walking with a robotic dog. I wasn’t personally so excited about the robotic dog. But what really interested me was the person walking out of the frame on the other side, intently controlling the dog—using a laptop that he had strapped on in front of him as if he were selling popcorn.

Could one actually work like this, typing and everything? After my “heart-rate discovery” I decided I had to try it. I thought I’d have to build something myself, but actually one can just buy “walking desks”, and so I did. And after minor modifications, I discovered that I could walk and type perfectly well with it, even for a couple of hours. I was embarrassed I hadn’t figured out such a simple solution 20 years ago. But starting last fall—whenever the weather’s been good—I’ve tried to spend a couple of hours of each day walking outside like this:

And even when I’m intently concentrating on my computer, it’s somehow nice to be outside—and, yes, it seems to have made my resting heart rate go down. And I seem to have enough peripheral vision—or perhaps I’ve just been walking in “simple enough” environments—that I haven’t tripped even when I’m not consciously paying attention. No doubt it helps that I haven’t mostly been walking in public places, so there aren’t other people around. Of course, that also means that I haven’t had the opportunity to get the kind of curious stares I did in 1987 when I first walked down a city street talking on a shoe-sized cellphone….

I’ve had the same big wooden desk for 25 years. And needless to say, I had it constructed with some special features. One of my theories of personal organization is that any flat surface represents a potential “stagnation point” that will tend to accumulate piles of stuff—and the best way to avoid such piles is just to avoid having permanent flat surfaces. But one inevitably needs some flat surface, if only just to sign things (it’s not all digital yet), or to eat a snack. So my solution is to have pullouts. If one needs them, pull them out. But one can’t leave them pulled out, so nothing can accumulate on them:

These days I don’t deal with paper much. But whenever something does come across my desk, I like to file it. So behind my desk I have an array of drawers—with the little hack that there’s a slot at the top of each drawer that allows me to immediately slide things into the drawer, without opening it:

I used to fill up a banker’s box with filed papers every couple of months; now it seems to take a couple of years. And perhaps as a sign of how paperless I’ve become, I have a printer under my desk that I use so rarely that I now seem to go through a ream of paper only every year or so.

There are also other things that have changed over the years. I always want my main computer to be as powerful as possible. And for years that meant that it had to have a big fan to dissipate heat. But since I really like my office to be perfectly quiet (it adds a certain calmness that helps my concentration), I had to put the CPU part of my computer in a different room. And to achieve this, I had a conduit in the floor, through which I had to run often-finicky long-distance video cables. Well, now, finally, I have a powerful computer that doesn’t need a big fan—and so I just keep it behind my desk. (I actually also have three other not-so-quiet computers that I keep in the same room as the treadmill, so that when I’m on the treadmill I can experience all three main modern computing environments, choosing between them with a KVM switch.)

When I mention to people that I’m a remote CEO, they often say, “You must do lots of videoconferencing”. Well, actually, I do basically no videoconferencing. Screensharing is great, and critical. But typically I find video distracting. Often I’ll do a meeting where I have lots of people in case we need to get their input. But for most of the meeting I don’t need all of them to be paying attention (and I’m happy if they’re getting other work done). But if video is on, seeing people who are not paying attention just seems to viscerally kill the mood of almost any meeting.

Given that I don’t have video, audio is very important, and I’m quite a stickler for audio quality in meetings. No speakerphones. No bad cellphone connections. I myself remain quite old school. I wear a headset (with padding added to compensate for my lack of top-of-head hair) with a standard boom microphone. And—partly out of caution about having a radio transmitter next to my head all day—my headset is wired, albeit with a long wire that lets me roam around my office.

Even though I don’t use “talking head” video for meetings, I do have a document camera next to my computer. One time I’ll use this is when we’re talking about phones or tablets. Yes, I could connect their video directly into my computer. But if we’re discussing user experience on a phone it’s often helpful to be able to actually see my finger physically touching the phone.

The document camera also comes in handy when I want to show pages from a physical book, or artifacts of various kinds. When I want to draw something simple I’ll use the annotation capabilities of our screensharing system. But when I’m trying to draw something more elaborate I’ll usually do the retro thing of putting a piece of paper under the document camera, then just using a pen. I like the fact that the image from the document camera comes up in a window on my screen, that I can resize however I want. (I periodically try using drawing tablets but I don’t like the way they treat my whole screen as a canvas, rather than operating in a window that I can move around.)

In some ways I lead a simple life, mostly at my desk. But there are plenty of times when I’m away from my desk—like when I’m someplace else in my house, or walking outside. And in those cases I’ll normally take a 13″ laptop to use. When I go further afield, it gets a bit more complicated.

If I’m going to do serious work, or give a talk, I’ll take the 13″ laptop. But I never like to be computerless, and the 13″ laptop is a heavy thing to lug around. So instead I also have a tiny 2-lb laptop, which I put in a little bag (needless to say, both the bag and the computer are adorned with our Spikey logo):

And for at least the past couple of years—unless I’m bringing the bigger computer, usually in a backpack—I have taken to “wearing” my little computer wherever I go. I originally wanted a bag where the computer would fit completely inside, but the nicest bag I could find had the computer sticking out a bit. To my surprise, though, this has worked well. And it’s certainly amusing when I’m talking to someone and quickly “draw” my computer, and they look confused, and ask, “Where did that come from?”

I always have my phone in my pocket, and if I have just a few moments that’s what I’ll pull out. It works fine if I’m checking mail, and deleting or forwarding a few messages. If I actually want to write anything serious, though, out will come my little computer, with its full keyboard. Of course, if I’m standing up it’s pretty impractical to try to balance the computer on one hand and type with the other. And sometimes if I know I’m going to be standing for a while, I’ll bring a tablet with me. But other times, I’ll just be stuck with my phone. And if I run out of current things I can usefully do (or I don’t have an internet connection) I’ll typically start looking at the “things to read” folder that I maintain synched on all my devices.

Back in 2007 I invented WolframTones because I wanted to have a unique ringtone for my phone. But while WolframTones has been successful as an example of algorithmic music composition, the only trace of it on my phone is the image of WolframTones compositions that I use as my home screen:

How do I take notes when I’m “out and about”? I’ve tried various technological solutions, but in the end none have proved both practical and universally socially acceptable. So I’ve kept doing the same thing for 40 years: in my pocket I have a pen, together with a piece of paper folded three times (so it’s about the size of a credit card). It’s very low-tech, but it works. And when I come back from being out I always take a few moments to transcribe what I wrote down, send out emails, or whatever.

I have little “tech survival kits” that I bring with me. Here are the current contents from my backpack:

The centerpiece is a tiny charger, that charges both my computer (through USB-C) and my phone. I bring various connectors, notably so I can connect to things like projectors. I also bring a very light 2- to 3-prong power adaptor, so I don’t find my charger falling out of overused power outlets.

When I’m going on “more serious expeditions” I’ll add some things to the kit:

There’s a “charging brick” (unfortunately now in short supply) that’ll keep my computer going for many hours. For events like trade shows, I’ll bring a tiny camera that takes pictures every 30 seconds, so I can remember what I saw. And if I’m really going out into the wilds, I’ll bring a satphone as well. (Of course, I always have other stuff too, like a very thin and floppy hat, a light neoprene bag-within-a-bag, glasses wipes, hand sanitizer, mosquito wipes, business cards, pieces of chocolate, etc.)

In my efforts to keep organized on trips, I’ll typically pack several plastic envelopes:

In “Presentation” there’ll be the adaptors (VGA, HDMI, …) I need to connect to projectors. Sometimes there’ll be a wired Ethernet adaptor. (For very low-key presentations, I’ll also sometimes bring a tiny projector too.) In “Car” there’ll be a second cellphone that can be used as a GPS, with a magnetic back and a tiny thing for attaching to the air vent in a car. There’ll be a monaural headset, a phone charger, and sometimes a tiny inverter for my computer. If I’m bringing the satphone, there’ll also be a car kit for it, with an antenna that magnets to the roof of the car, so it can “see” the satellites. In “Hotel” there’ll be a binaural headset, a second computer charger, and a disk with an encrypted backup of my computer, in case I lose my computer and have to buy and configure a new machine. The fourth plastic envelope is used to store things I get on the trip, and it contains little envelopes—approximately one for each day of my trip—in which I put business cards.

Years ago, I always used to bring a little white-noise fan with me, to mask background noise, particularly at night. But at some point I realized that I didn’t need a physical fan, and instead I just have an app that simulates it (I used to use pink noise, but now I just use “air conditioner sound”). It’s often something of a challenge to predict just how loud the outside noise one’s going to encounter (say, the next morning) will be, and so how loud one should set the masking sound. And, actually, as I write this, I realize I should use modern audio processing in the Wolfram Language to just listen to external sounds, and adjust the masking sound to cover them.

Another thing I need when I travel is a clock. And nowadays it’s just a piece of Wolfram Language code running on my computer. But because it’s software, it can have a few extra features. I always leave my computer on my home timezone, so the “clock” has a slider to specify local time (yes, if I’m ever in a half-hour timezone again I’ll have to tweak the code). It also has a button Start sleep timer. When I press it, it starts a count-up timer, which lets me see how long I’ve been asleep, whatever my biological clock may say. (Start sleep timer also sends an email which gives my assistant an idea of whether or not I’ll make it to that early-next-morning meeting. The top right-hand “mouse corner” is a hack for preventing the computer from going to sleep.)

Whenever it’s practical, I like to drive myself places. It was a different story before cellphones. But nowadays if I’m driving I’m productively making a phone call. I’ll have meetings that don’t require me to look at anything scheduled for my “drive times” (and, yes, it’s nice to have standard conference call numbers programmed in my phone, so I can voice-dial them). And I maintain a “call-while-driving” list of calls that I can do while driving, particularly if I’m in an unusual-for-me timezone.

I’ve always had the problem that if I try to work on a computer while I’m being driven by someone else, I get car sick. I thought I had tried everything. Big cars. Little cars. Hard suspension. Soft suspension. Front seat. Back seat. Nothing worked. But a couple of years ago, quite by chance, I tried listening to music with big noise-canceling headphones—and I didn’t get car sick. But what if when I’m being driven I want to be on the phone while I’m using my computer? Well, at the 2018 Consumer Electronics Show, despite my son’s admonition that “just because you can’t tell what they’re selling at a booth doesn’t mean it’s interesting”, I stopped at a booth and got these strange objects, which, despite looking a bit odd, do seem to prevent car sickness for me, at least much of the time:

I give quite a lot of talks—to a very wide range of audiences. I particularly like giving talks about subjects I haven’t talked about before. I give talks to the fanciest business, tech and science groups. I give talks to schoolkids. I enjoy interacting with audiences (Q&A is always my favorite part), and I enjoy being spontaneous. And I essentially always end up doing livecoding.

When I was young I traveled quite a bit. I did have portable computers even back in the 1980s (my first was an Osborne 1 in 1981), though mostly in those days my only way to stay computer-productive was to have workstation computers shipped to my destinations. Then in the early 1990s, I decided I wasn’t going to travel anymore (not least because I was working so intensely on A New Kind of Science). So for a while I basically didn’t give any talks. But then technology advanced. And it started being realistic to give talks through videoconferencing.

I went through several generations of technology, but a number of years ago I built out a videoconferencing setup in my basement. The “set” can be reconfigured in various ways (podium, desk, etc.) But basically I have a back-projection screen on which I can see the remote audience. The camera is in front of the screen, positioned so I’m looking straight at it. If I’m using notes or a script (which, realistically, is rare) I have a homemade teleprompter consisting of a half-silvered mirror and a laptop that I can look at the camera through.

While it’s technically feasible for me to be looking straight at the camera when I’m livecoding, this makes it look to the audience as if I’m staring off into space, which seems weird. It’s better to look slightly down when I’m obviously looking at a screen. And in fact with some setups it’s good for the audience to see the top of a computer right at the bottom of the screen, to “explain” what I’m looking at.

Videoconferenced talks work quite well in many settings (and, for some extra fun, I’ve sometimes used a telepresence robot). But in recent years (partly as a result of my children wanting to do it with me) I’ve decided that traveling is OK—and I’ve been all over the place:

I’ll usually be giving talks—often several per day. And I’ve gradually developed an elaborate checklist of what’s needed to have them work. A podium that’s at the right height and horizontal enough to let me type easily on my computer (and preferably not so massive that I’m hidden from the audience). An attachable microphone that leaves my hands free to type. A network connection that lets me reach our servers. And, of course, to let the audience actually see things, a computer projector.

I remember the very first computer projector I used, in 1980. It was a Hughes “liquid crystal light valve”, and once I got it connected to a CRT terminal, it worked beautifully. In the years since then I’ve used computer projectors all over the world, both in the fanciest audiovisual situations, and in outlying places with ancient equipment and poor infrastructure. And it’s amazing how random it is. In places where one can’t imagine the projector is going to work, it’ll be just fine. And in places where one can’t imagine it won’t work, it’ll fail horribly.

Some years ago I was giving a talk at TED—with some of the fanciest audiovisual equipment I’d ever seen. And that was one of the places where things failed horribly. Fortunately we did a test the day before. But it took a solid three hours to get the top-of-the-line computer projector to successfully project my computer’s screen.

And as a result of that very experience I decided I’d better actually understand how computers talk to projectors. It’s a complicated business, that involves having the computer and the projector negotiate to find a resolution, aspect ratio, frame rate, etc. that will work for both of them. Underneath, there are things called EDID strings that are exchanged, and these are what typically get tangled up. Computer operating systems have gotten much better about handling this in recent years, but for high-profile, high-production-value events, I have a little box that spoofs EDID strings to force my computer to send a specific signal, regardless of what the projector seems to be asking it for.

Some of the talks I give are completely spontaneous. But often I’ll have notes—and occasionally even a script. And I’ll always write these in a Wolfram Notebook. I then have code that “paginates” them, basically replicating “paragraphs” at the end of each page, so I have freedom in when I “turn the page”. In past years I used to transfer these notes to an iPad that I’d set up to “turn the page” whenever I touched its screen. But in recent years I’ve actually just synched files, and used my little computer for my notes—which has the advantage that I can edit them right up to the moment I start giving the talk.

In addition to notes, I’ll sometimes also have material that I want to immediately bring into the talk. Now that we have our new Presenter Tools system, I may start creating more slide-show-like material. But that’s not how I’ve traditionally worked. Instead, I’ll typically just have a specific piece of Wolfram Language code I want to input, without having to take the time to explicitly type it. Or perhaps I’ll want to pick an image from a “slide farm” that I want to immediately put on the screen, say in response to a question. (There’s a lot of trickiness about projector resolutions in, for example, slides of cellular automata, because unless they’re “pixel perfect” they’ll alias—and it’s not good enough just to scale them like typical slide software would.)

So how do I deal with bringing in this material? Well, I have a second display connected to my computer—whose image isn’t projected. (And, yes, this can contribute to horrible tangling of EDID strings.) Then on that second display I can have things to click or copy. (I have a Wolfram Language function that will take a notebook of inputs and URLs, and make me a palette that I can click to type inputs, open webpages, etc.)

In the past we used to have a little second monitor to attach to my laptop—essentially a disembodied laptop screen. But it took all sorts of kludges to get both it and the projector connected to my laptop (sometimes one would be USB, one would be HDMI, etc.) But now we can just use an iPad—and it’s all pure software (though the interaction with projectors can still be finicky):

For a while, just to be stylish, I was using a computer with a Spikey carved out of its case, and backlit. But the little rhombuses in it were a bit fragile, so nowadays I mostly just use “Spikey skins” on my computers:

The three main applications I use all day are Wolfram Desktop, a web browser, and email. My main way of working is to create (or edit) Wolfram Notebooks. Here are a few notebooks I worked on today:

On a good day I’ll type at least 25,000 characters into Wolfram Notebooks (and, yes, I record all my keystrokes). I always organize my notebooks into sections and subsections and so on (which, very conveniently, automatically exist in hierarchical cells). Sometimes I’ll write mostly text in a notebook. Sometimes I’ll screen capture something from elsewhere and paste it in, as a way to keep notes. Depending on what I’m doing, I’ll also actually do computations in a notebook, entering Wolfram Language input, getting results, etc.

Over the years, I’ve accumulated over a hundred thousand notebooks, representing product designs, plans, research, writings, and, basically, everything I do. All these notebooks are ultimately stored in my filesystem (yes, I sync with the cloud, use cloud files, and file servers, etc.) And I take pains to keep my filesystem organized—with the result I can typically find any notebook I’m looking for just by navigating my filesystem, faster than I could formulate a search for it.

I believe I first thought seriously about how to organize my files back in 1978 (which was also when I started using the Unix operating system). And over the past 40 years I’ve basically gone through five generations of filesystem organization, with each generation basically being a reflection of how I’m organizing my work at that stage in my life.

For example, during the period from 1991 to 2002 when I was writing my big book A New Kind of Science, a substantial part of my filesystem was organized simply according to sections of the book:

And it’s very satisfying that today I can go immediately from, say, an image in the online version of the book, to the notebook that created it (and the stability of the Wolfram Language means that I can immediately run the code in the notebook again—though sometimes it can now be written in a more streamlined way).

The sections of the book are basically laid out in the NewScience/Book/Layout/ folder of my “third-generation” filesystem. Another part of that filesystem is NewScience/BookResearch/Topics. And in this folder are about 60 subfolders named for broad topics that I studied while working on the book. Within each of these folders are then further subfolders for particular projects I did while studying those topics—which often then turned into particular sections or notes in the book.

Some of my thinking about computer filesystems derives from my experience in the 1970s and 1980s with physical filesystems. Back when I was a teenager doing physics I voraciously made photocopies of papers. And at first I thought the best way to file these papers would be in lots of different categories, with each category stored in a different physical file folder. I thought hard about the categories, often feeling quite pleased with the cleverness of associating a particular paper with a particular category. And I had the principle that if too many papers accumulated in one category, I should break it up into new categories.

All this at first seemed like a good idea. But fairly quickly I realized it wasn’t. Because too often when I wanted to find a particular paper I couldn’t figure out just what cleverness had caused me to associate it with what category. And the result was that I completely changed my approach. Instead of insisting on narrow categories, I allowed broad, general categories—with the result that I could easily have 50 or more papers filed in a single category (often ending up with multiple well-stuffed physical file folders for a given category):

And, yes, that meant that I would sometimes have to leaf through 50 papers or more to find one I wanted. But realistically this wouldn’t take more than a few minutes. And even if it happened several times a day it was still a huge win, because it meant that I could actually successfully find the things I wanted.

I have pretty much the same principle about some parts of my computer filesystem today. For example, when I’m collecting research about some topic, I’ll just toss all of it into a folder named for that topic. Sometimes I’ll even do this for years. Then when I’m ready to work on that topic, I’ll go through the folder and pick out what I want.

These days my filesystem is broken into an active part (that I continuously sync onto all my computers), and a more archival part, that I keep on a central fileserver (and that, for example, contains my older-generation filesystems).

There are only a few top-level folders in my active filesystem. One is called Events. Its subfolders are years. And within each year I’ll have a folder for each of the outside events I go to in that year. In that folder I’ll store material about the event, notebooks I used for talks there, notes I made at the event, etc. Since in a given year I won’t go to more than, maybe, 50 events, it’s easy to scan through the Events folder for a given year, and find the folder for a particular event.

Another top-level folder is called Designs. It contains all my notes about my design work on the Wolfram Language and other things we’re building. Right now there are about 150 folders about different active areas of design. But there’s also a folder called ARCHIVES, which contains folders about earlier areas that are no longer active.

And in fact this is a general principle in the project-oriented parts of my filesystem. Every folder has a subfolder called ARCHIVES. I try to make sure that the files (or subfolders) in the main folder are always somehow active or pending; anything that’s finished with I put in ARCHIVES. (I put the name in capitals so it stands out in directory listings.)

For most projects I’ll never look at anything in ARCHIVES again. But of course it’s easy to do so if I want to. And the fact that it’s easy is important, because it means I don’t have nagging concerns about saying “this is finished with; let’s put it in ARCHIVES”, even if I think there’s some chance it might become active again.

As it happens, this approach is somewhat inspired by something I saw done with physical documents. When I was consulting at Bell Labs in the early 1980s I saw that a friend of mine had two garbage cans in his office. When I asked him why, he explained that one was for genuine garbage and the other was a buffer into which he would throw documents that he thought he’d probably never want again. He’d let the buffer garbage can fill up, and once it was full, he’d throw away the lower documents in it, since from the fact that he hadn’t fished them out, he figured he’d probably never miss them if they were thrown away permanently.

Needless to say, I don’t follow exactly this approach, and in fact I keep everything, digital or paper. But the point is that the ARCHIVES mechanism gives me a way to easily keep material while still making it easy to see everything that’s active.

I have a bunch of other conventions too. When I’m doing designs, I’ll typically keep my notes in files with names like `Notes-01.nb` or `SWNotes-01.nb`. It’s like my principle of not having too many file categories: I don’t tend to try to categorize different parts of the design. I just sequentially number my files, because typically it’ll be the most recent—or most recent few—that are the most relevant when I continue with a particular design. And if the files are just numbered sequentially, it’s easy to find them; one’s not trying to remember what name one happened to give to some particular direction or idea.

A long time ago I started always naming my sequential files `file-01`, `file-02`, etc. That way pretty much any sorting scheme will sort the files in sequence. And, yes, I do often get to `file-10`, etc. But in all these years I have yet to get even close to `file-99`.

When I’m specifically working on a particular project, I’ll usually just be using files in the folder associated with that project. But on a good day, I’ll have lots of ideas about lots of different projects. And I also get hundreds of emails every day, relevant to all sorts of different projects. But often it’ll be months or years before I’m finally ready to seriously concentrate on one of these other projects. So what I want to do is to store the material I accumulate in such a way that even long in the future I can readily find it.

For me, there are typically two dimensions to where something should be stored. The first is (not surprisingly) the content of what it’s about. But the second is the type of project in which I might use it. Is it going to be relevant to some feature of some product? Is it going to be raw material for some piece I write? Is it a seed for a student project, say at our annual Summer School? And so on.

For some types of projects, the material I’m storing typically consists of a whole file, or several files. For others, I just need to store an idea which can be summarized in a few words or paragraphs. So, for example, the seed for a student project is typically just an idea, that I can describe with a title, and perhaps a few lines of explanation. And in any given year I just keep adding such project ideas to a single notebook—which, for example, I’ll look at—and summarize—right before our annual summer programs.

For pieces like this that I’m potentially going to write, it’s a little different. At any given time, there are perhaps 50 pieces that I’m considering at some point writing. And what I do is to create a folder for each of them. Each will typically have files with names like `Notes-01.nb`, into which I accumulate specific ideas. But then the folder will also contain complete files, or groups of files, that I accumulate about the topic of the piece. (Sometimes I’ll organize these into subfolders, with names like Explorations and Materials.)

In my filesystem, I have folders for different types of projects: Writings, Designs, StudentProjects, etc. I find it important to have only a modest number of such folders (even with my fairly complex life, not much more than a dozen). When something comes in—say from a piece of email, or from a conversation, or from something I see on the web, or just from an idea I have—I need to be able to quickly figure out what type of project (if any) it might be relevant to.

At some level it’s as simple as “what file should I put it into”? But the key point is to have a pre-existing structure that makes it quick to decide that—and then to have this structure be one in which I can readily find things even far into the future.

There are plenty of tricky issues. Particularly if years go by, the way one names or thinks about a topic may change. And sometimes that means at some point I’ll just rename a folder or some such. But the crucial thing as far as I’m concerned is that at any given time the total number of folders into which I’m actively putting things is small enough that I can basically remember all of them. I might have a dozen folders for different types of projects. Then some of these will need subfolders for specific projects about specific topics. But I try to limit the total number of “active accumulation folders” to at most a few hundred.

Some of those “accumulation folders” I’ve had for a decade or more. A few will come into existence and be gone within a few months. But most will last at most a few years—basically the time between when I conceptualize a project, and when the project is, for practical purposes, finished.

It’s not perfect, but I end up maintaining two hierarchies of folders. The first, and most important, is in my filesystem. But the second is in my email. There are two basic reasons I maintain material in email folders. The first is immediate convenience. Some piece of mail comes in and I think “that’s relevant to such-and-such a project that I’m planning to do”—and I want to store it in an appropriate place. Well, if that place is a mail folder, all I have to do is move the mail with one mouse motion (or maybe with one press of a Touch Bar button). I don’t have to, for example, find a file or filesystem folder to put it into.

There’s also another reason it’s good to leave mail as mail: threading. In the Wolfram Language we’ve now got capabilities both for importing mailboxes, and for connecting to live mail servers. And one of the things one quickly sees is how complicated the graphs (actually, hypergraphs) of email conversations can be. Mail clients certainly aren’t perfect as a way to view these conversations, but it’s a lot better to use one than, say, to have a collection of separate files.

When projects are fairly well defined, but aren’t yet very active, I tend to use filesystem folders rather than email folders. Typically what will be coming in about these projects are fairly isolated (and non-threaded) pieces of mail. And I find it best either just to drag those pieces of mail into appropriate project folders, or to copy out their contents and add them to notebooks.

When a project is very active, there may be lots of mail coming in about it, and it’s important to preserve the threading structure. And when a project isn’t yet so well defined, I just want to throw everything about it into a single “bucket”, and not have to think about organizing it into subfolders, notebooks, etc.

If I look at my mail folders, I see many that parallel folders in my filesystem. But I see some that do not, particularly related to longer-term project concepts. And I have many such folders that have been there for well over a decade (my current overall mail folder organization is about 15 years old). Sometimes their names aren’t perfect. But there are few enough folders, and I’ve seen them for long enough, that I have a sense of what I’m filing in them, even though their names don’t quite capture it.

It’s always very satisfying when I’m ready to work on a project, and I open the mail folder for it, and start going through messages, often from long ago. Just in the past few weeks, as we wrap up a major new version of the Wolfram Language, I’m starting to look ahead, and I’ve been going through folders with messages from 2005, and so on. When I saved those messages, I didn’t yet have a definite framework for the project they’re about. But now I do. So when I go through the messages I can quickly put them into the appropriate active notebooks and so on. Then I delete the messages from the mail folder, and eventually, once it is empty, delete the whole mail folder. (Unlike with files, I don’t find it useful to have an ARCHIVES folder for mail; the mail is just too voluminous and not organized enough, so to find any particular item I’ll probably end up having to search for it anyway, and of course I certainly have all of my mail stored.)

OK, so I have my filesystem, and I have mail. At our company we also have an extensive project management system, as well as all sorts of databases, request trackers, source control systems, etc. Mostly the nature of my current work does not cause me to interact directly with these, and I don’t explicitly store my own personal output in them. At different times, and with different projects, I have done so. But right now my interaction with these systems is basically only as a viewer, not an author.

Beyond these systems, there are lots of things that I interact with basically through webpages. These might be public sites like wolframalpha.com or wolfram.com. They might be internal sites at our company. And they might be preliminary (say, “test” or “devel”) versions of what will in the future be public websites or web-based services. I have a personal homepage that gives me convenient access to all these things:

The source for the homepage is (needless to say) a Wolfram Notebook. I can edit this notebook in my filesystem, then press a button to deploy a version to the Wolfram Cloud. I’ve got an extension in my web browser so that every time I create a new browser window or tab, the initial content will be my personal homepage.

And when I’m going to start doing something, there are just a few places I go. One is this web homepage, which I access many hundreds of times every day. Another is my email and its folders. Another is my desktop filesystem. And basically the only other one of any significance is my calendar system.

From time to time, I’ll see other people’s computers, and their desktops will be full of files. My desktop is completely empty, and plain white (convenient for whole-screen screensharing and livestreaming). I’d be mortified if there were any files to be seen on my desktop. I’d consider it a sign of defeat in my effort to keep what I’m doing organized. The same can be said of generic folders like Documents and Downloads. Yes, in some situations applications etc. will put files there. But I consider these directories to be throwaways. Nothing in them do I intend to be part of my long-term organizational structure. And they’re not synched to the cloud, or across my different computers.

Whatever the organization of my files may be, one feature of them is that I keep them a long time. In fact, my oldest file dates are from 1980. Back then, there was something a bit like the cloud, except it was called timesharing. I’ve actually lost some of the files that I had on timesharing systems. But the ones I had on on-premise computers are still with me (though, to be fair, some had to be retrieved from 9-track backup tapes).

And today, I make a point of having all my files (and all my email) actively stored on-premise. And, yes, that means I have this in my basement:

The initial storage is on a standard RAID disk array. This is backed up to computers at my company headquarters (about 1000 miles away), where standard tape backups are done. (In all these years, I’ve only ever had to retrieve from a backup tape once.) I also sync my more active files to the cloud, and to all my various computers.

My major two personal forms of output are mail messages and Wolfram Notebooks. And over the 30 years since we first introduced notebooks we’ve optimized our notebook system to the point where I can just press a key to create a default new notebook, and then I’m immediately off and running writing what automatically becomes a good-looking structured document. (And, by the way, it’s very nice to see that we’ve successfully maintained compatibility for 30 years: notebooks I created back in 1988 still just work.)

Sometimes, however, I’m making a notebook that’s not so much for human consumption as for input to some automated process. And for this, I use a whole variety of specially set up notebooks. For example, if I want to create an entry in our new Wolfram Function Repository, I just go to the menu item (available in any Version 12 system) File > New > Repository Item > Function Repository Item:

This effectively “prompts” me for items and sections to add. When I’m done, I can press Submit to Repository to send the notebook off to our central queue for repository item reviews (and, just because I’m the CEO doesn’t mean I get out of the review process—or want to).

I actually create a fair amount of content that’s structured for further processing. A big category is Wolfram Language documentation. And for authoring this we have an internal system we call DocuTools, that’s all based on a giant palette developed over many years, that I often say reminds one of an airplane cockpit in its complexity:

The idea of DocuTools is to make it as ergonomic as possible to author documentation. It has more than 50 subpalettes (a few shown above), and altogether no less than 1016 buttons. If I want to start a new page for a Wolfram Language function I just press New Function Page, and up pops:

A very important part of this page is the stripe at the top that says “Future”. This means that even though the page will be stored in our source control system, it’s not ready yet: it’s just something we’re considering for the future. And the system that builds our official documentation will ignore the page.

Usually we (which quite often actually means me) will write documentation for a function before the function is implemented. And we’ll include all sorts of details about features the function should have. But when the function is actually first implemented, some of those features may not be ready yet. And to deal with this we (as we call it) “futurize” parts of the documentation, giving it a very visible pink background. It’s still there in the source control system, and we see it every time we look at the source for the documentation page. But it’s not included when the page for documentation that people will see is built.

DocuTools is of course implemented in the Wolfram Language, making extensive use of the symbolic structure of Wolfram Notebooks. And over the years it’s grown to handle many things that aren’t strictly documentation; in fact, for me it’s become the main hub for the creation of almost all notebook-based content.

There’s a button, for example, for Stephen Wolfram Blog. Press it and one gets a standard notebook ready to write into. But in DocuTools there’s a whole array of buttons that allow one to insert suggestions and edits. And when I’ve written a blog what will come back is typically something like this:

The pink boxes are “you really need to fix this”; the tan are “here’s a comment”. Click one and up comes a little form:

Of course, there are plenty of change-tracking and redlining systems out there in the world. But with the Wolfram Language it becomes easy to create a custom one that’s optimized for my needs, so that’s what I’ve had done. Before I had this, it used to take many hours to go through edit suggestions (I remember a horrifying 17-hour plane ride where I spent almost the whole time going through suggestions for a single post). But now—because it’s all optimized for me—I can zip through perhaps 10 times faster.

Very often tools that are custom built for me end up being adapted so everyone else can use them too. An example is a system for authoring courses and creating videos. I wanted to be able to do this as a “one-man band”—a bit like how I do livestreaming. My idea was to create a script that contains both words to say and code to input, then to make the video by screen recording in real time while I went through the script. But how would the inputs work? I couldn’t type them by hand because it would interrupt the real-time flow of what I was saying. But the obvious thing is just to “autotype” them directly into a notebook.

But how should all this be orchestrated? I start from a script:

Then I press Generate Recording Configuration. Immediately a title screen comes up in one area of my screen, and I set up my screen-recording system to record from this area. Elsewhere on my screen is the script. But what about the controls? Well, they’re just another Wolfram Notebook, that happens to act as a palette containing buttons:

But how can I actually operate this palette? I can’t use my mouse, because then I’d take focus away from the notebook that’s being screen recorded. So the idea that I had is to put the palette on an extended desktop, that happens to be being displayed on an iPad. So then to “perform” the script, I just press buttons on the palette.

There’s a big Advance Script button. And let’s say I’ve read to a point in the script where I need to type something into the notebook. If I want to simulate actual typing I press Slow Type. This will enter the input character-at-a-time into the notebook (yes, we measured the inter-key delay distribution for human typing, and simulate it). After a while it gets annoying to see all that slow typing. So then I just use the Type button, which copies the whole input immediately into the notebook. If I press the button again, it’ll perform its second action: Evaluate. And that’s the equivalent of pressing `Shift+Enter` in the notebook (with some optional extra explanatory popups suitable for the video).

I could go on about other tools I’ve had built using the Wolfram Language, but this gives a flavor. But what do I use that isn’t Wolfram Language? Well, I use a web browser, and things that can be reached through it. Still, quite often, I’m just going to the Wolfram Cloud, and for example viewing or using cloud notebooks there.

Sometimes I’ll use our public Wolfram Cloud. But more often I’ll use a private Wolfram Cloud. The agendas for most of our internal meetings are notebooks that are hosted on our internal Wolfram Cloud. I also personally have a local private Wolfram Cloud running, that I host an increasing number of applications on.

Here’s the dock on my computer as of right now:

It’s got a filesystem browser; it’s got an email client; it’s got three web browsers (yes, I like to test our stuff on multiple browsers). Then I’ve got a calendar client. Next is the client for our VoIP phone system (right now I’m alternating between using this, and using audio along with our screensharing system). Then, yes, at least right now I have a music app. I have to say it’s rather rare that my day gives me a chance to listen to music. Probably the main time when I end up doing it is when I’m very behind on email, and need something to cheer me up as I grind through thousands of messages. As soon as I’m actually writing anything nontrivial, though, I have to pause the music, or I can’t concentrate. (And I have to find music without vocals—because I’ve noticed I can’t read at full speed if I’m hearing vocals.)

Sometimes I’ll end up launching a standard word processor, spreadsheet, etc. app because I’m opening a document associated with one of these apps. But I have to admit that in all these years I’ve essentially never authored a document from scratch with any of these apps; I end up just using technology of ours instead.

Occasionally I’ll open a terminal window, and directly use operating system commands. But this is becoming less and less common—because more and more I’m just using the Wolfram Language as my “super shell”. (And, yes, it’s incredibly convenient to store and edit commands in a notebook, and to instantly be able to produce graphical and structured output.)

As I write this, I realize a little optimization I haven’t yet made. On my personal homepage there are some links that do fairly complex things. One, for example, initiates the process for me doing an unscheduled livestream: it messages our 24/7 system monitoring team so they can take my feed, broadcast it, and monitor responses. But I realize that I still have quite a few custom operating system commands, that do things like update from the source code repository, that I type into a terminal window. I need to set these up in my private cloud, so I can just have links on my personal homepage that run Wolfram Language code for these commands. (To be fair, some of these commands are very old; for example, my fmail command that sends a mail message in the future, was written nearly 30 years ago.)

But, OK, if I look at my dock of apps, there’s a definite preponderance of Spikey ones. But why, for example, do I need three identical standard Spikeys? They’re all the Wolfram Desktop app. But there are three versions of it. The first one is our latest distributed version. The second one is our latest internal version, normally updated every day. And the third one (which is in white) is our “prototype build”, also updated every day, but with lots of “bleeding edge” features that aren’t ready to go into serious testing.

It requires surprisingly fancy operating system footwork to get these different versions installed every night, and to correctly register document types with them. But it’s very important to my personal workflow. Typically I’ll use the latest internal version (and, yes, I have a directory with many previous versions too), but occasionally, say for some particular meeting, I’ll try out the prototype build, or I’ll revert to the released build, because things are broken. (Dealing with multiple versions is one of those things that’s easier in the cloud—and we have a whole array of different configurations running in internal private clouds, with all sorts of combinations of kernel, front end, and other versions.)

When I give talks and so on, I almost always use the latest internal version. I find that livecoding in front of an audience is a great way to find bugs—even if it sometimes makes me have to explain, as I put it, the “disease of the software company CEO”: to always want to be running the latest version, even if it hasn’t been seriously tested and was built the night before.

A critical part of my personal infrastructure is something that in effect dramatically extends my personal memory: my “metasearcher”. At the top of my personal homepage is a search box. Type in something like “rhinoceros elephant” and I’ll immediately find every email I’ve sent or received in the past 30 years in which that’s appeared, as well as every file on my machine, and every paper document in my archives:

To me it’s extremely convenient to have a count of the messages by year; it often helps me remember the history or story behind whatever I’m asking. (In this case, I can see a peak in 2008, which is when we were getting ready to launch Wolfram|Alpha—and I was working on data about lots of kinds of things, including species.)

Of course, a critical piece of making my metasearcher work is that I’ve stored so much stuff. For example, I actually have all the 815,000 or so emails that I’ve written in the past 30 years, and all the 2.3 million (mostly non-spam) ones I’ve received. And, yes, it helps tremendously that I’ve had a company with organized IT infrastructure etc. for the past 32 years.

But email, of course, has the nice feature that it’s “born digital”. What about things that were, for example, originally on paper? Well, I have been something of an “informational packrat” for most of my life. And in fact I’ve been pretty consistently keeping documents back to when I started elementary school in 1968. They’ve been re-boxed three times since then, and now the main ones are stored like this:

(I also have file folder storage for documents on people, organizations, events, projects and topics.) My rate of producing paper documents increased through about 1984, then decayed quite rapidly, as I went more digital. Altogether I have about a quarter million pages of primary non-bulk-printed documents—mostly from the earlier parts of my life.

About 15 years ago I decided I needed to make these searchable, so I initiated the project of scanning all of them. Most of the documents are one or a few pages in length, so they can’t be handled by an automatic feeder—and so we set up a rig with a high-resolution camera (and in those days it needed flash). It took several person-years of work, but eventually all the documents were scanned.

We automatically cropped and white-balanced them (using Wolfram Language image processing), then OCR’ed them, and put the OCR’ed text as a transparent layer into the scanned image. If I now search for “rhinoceros” I find 8 documents in my archive. Perhaps not surprisingly given that search term, they’re a bit random, including for example the issue of my elementary school magazine from Easter 1971.

OCR works on printed text. But what about handwritten text? Correspondence, even if it’s handwritten, usually at least comes on printed letterhead. But I have many pages of handwritten notes with basically nothing printed on them. Recognizing handwriting purely from images (without the time series of strokes) is still beyond current technology, but I’m hoping that our neural-net-based machine learning systems will soon be able to tackle it. (Conveniently, I’ve got quite a few documents where I have both my handwritten draft, and a typed version, so I’m hoping to have a training set for at least my personal handwriting.)

But even though I can’t search for handwritten material, I can often find it just by “looking in the right box”. My primary scanned documents are organized into 140 or so boxes, each covering a major period or project in my life. And for each box, I can pull up thumbnails of pages, grouped into documents. So, for example, here are school geography notes from when I was 11 years old, together with the text of a speech I gave:

I have to say that pretty much whenever I start looking through my scanned documents from decades ago I end up finding something unexpected and interesting, that very often teaches me something about myself, and about how I ended up developing in some particular direction.

It may be something fairly specific to my life, and the fact that I’ve worked on building long-term things, as well as that I’ve kept in touch with a large number of people over a long period of time, but I’m amazed by the amount of even quite ancient personal history that I seem to encounter practically every day. Some person or some organization will contact me, and I’ll look back at information about interactions I had with them 35 years ago. Or I’ll be thinking about something, and I’ll vaguely remember that I worked on something similar 25 years ago, and look back at what I did. I happen to have a pretty good memory, but when I actually look at material from the past I’m always amazed at how many details I’ve personally forgotten.

I first got my metasearcher set up nearly 30 years ago. The current version is based on Wolfram Language `CreateSearchIndex`/`TextSearch` functionality, running on my personal private cloud. It’s using `UpdateSearchIndex` to update every few minutes. The metasearcher also “federates in” results from APIs for searching our corporate websites and databases.

But not everything I want can readily be found by search. And another mechanism I have for finding things is my “personal timeline”. I’ve been meaning for ages to extend this, but right now it basically just contains information on my external events, about 40 of them per year. And the most important part is typically my “personal trip report”, which I meticulously write, if at all possible within 24 hours.

Usually the trip report is just text (or at least, text structured in a notebook). But when I go to events like trade shows I typically bring a tiny camera with me, that takes a picture every half-minute. If I’m wearing one of those lanyard name tags I’ll typically clip the camera on the top of the name tag, among other things putting it at an ideal height to capture name tags of people I meet. When I write my personal trip report I’ll typically review the pictures, and sometimes copy a few into my trip notebook.

But even with all my various current sources of archival material (which now include chat messages, livestreams, etc.), email still remains the most important. Years ago I decided to make it easy for people to find an email address for me. My calculation was that if someone wants to reach me, then in modern times they’ll eventually find a way to do it, but if it’s easy for them just to send email, that’s how they’ll contact me. And, yes, having my email address out there means I get lots of email from people I don’t know around the world. Some of it is admittedly strange, but a lot is interesting. I try to look at all of it, but it’s also sent to a request tracker system, so my staff can make sure important things get handled. (It is sometimes a little odd for people to see request tracker ticket metadata like SWCOR #669140 in email subject lines, but I figure it’s a small price to pay for making sure the email is actually responded to.)

I might mention that for decades email has been the primary means of communication inside our (geographically distributed) company. Yes, we have project management, source control, CRM and other systems, as well as chat. But at least for the parts of the company that I interact with, email is overwhelmingly dominant. Sometimes it’s individual emails being sent between people. Sometimes it’s email groups.

It’s been a running joke for a long time that we have more email groups than employees. But we’ve been careful to organize the groups, for example identifying different types by prefixes to their names (t- is a mailing list for a project team, d- a mailing list for a department, l- a more open mailing list, r- a mailing list for automated reports, q- a request list, etc.) And for me at least this makes it plausible to remember what the right list is for some mail I want to send out.

I know a lot of people, from many different parts of my life. Back in the 1980s I used to just keep a list of them in a text file (before then it was a handwritten address book). But by the 1990s I decided I needed to have a more systematic database for myself—and created what I started calling pBase. In recent years the original technology of pBase began to seem quite paleolithic, but I now have a modern implementation using the Wolfram Language running in my personal private cloud.

It’s all quite nice. I can search for people by name or attributes, or—if I’m for example going to be visiting somewhere—I can just have pBase show me a map of our latest information about who’s nearby:

How does pBase relate to social networks? I’ve had a Facebook account for a long time, but it’s poorly curated, and always seems to ride at the maximum number of possible friends. LinkedIn I take much more seriously, and make a point of adding people only if I’ve actually talked to them (I currently have 3005 connections, so, yes, I’ve talked to quite a few people).

It’s very convenient that every so often I can download data from my LinkedIn account via `ServiceExecute` to update what’s in pBase. But LinkedIn captures only a fraction of people I know. It doesn’t include many of my more prominent friends and acquaintances, as well as most academics, many students, etc.

Eventually I’ll probably get pBase developed more, and perhaps make the technology generally available. But within our company, there’s already a system that illustrates some potential aspirations: our internal company directory—which is running in our internal private cloud, and basically uses Wolfram|Alpha-style natural language understanding to let one ask natural language questions.

I might mention in addition to our company directory, we also maintain another database that I, at least, find very useful, particularly when I’m trying to figure out who might know the answer to some unusual question, or who we might tap for some new project. We call it our Who Knows What database. And for each person it gives a profile of experience and interests. Here’s the entry for me (and here’s the source with the question details):

In terms of personal databases, another useful one for me is the database of books I own. I haven’t been buying too many books in the past decade or so, but before then I accumulated a library of about 6000 volumes, and it’s not uncommon—particularly when I’m doing more historically oriented research—that I’ll want to consult quite a few of them. But how should they be organized? “Big” classification schemes like Dewey Decimal or Library of Congress are overkill, and don’t do a great job of matching my personal “cognitive map” of topics.

Like my filesystem folders, or my physical folders of papers, I’ve found the best scheme is to put the books into fairly broad categories—small enough in number that I can spatially remember where they are in my library. But how should books be arranged within a category?

Well, here I get to tell a cautionary tale (that my wife regularly uses as an example) of what can go wrong in my kind of approach. Always liking to understand the historical progression of ideas, I thought it would be nice to be able to browse a category of books on a shelf in historical order (say, by first publication date). But this makes it difficult to find a specific book, or, for example, to reshelve it. (It would be easier if books had their publication dates printed on their spines. But they don’t.)

About 20 years ago I was preparing to move all my books to a new location, with different lengths of shelves. And I had the issue of trying to map out how to arrange book categories on the new shelves (“how many linear feet is quantum field theory and where can it fit in?”) So I thought: “Why not just measure the width of each book, and while I’m at it also measure its height and its color?” Because my idea was that then I could make a graphic of each shelf, with books shown with realistic widths and colors, then put an arrow in the graphic to indicate the location (easily identified visually from “landmarks” of other books) of a particular book.

I got a colorimeter (it was before ubiquitous digital cameras) and started having the measurements made. But it turned out to be vastly more labor-intensive than expected, and, needless to say, didn’t get finished before the books had to be moved. Meanwhile, the day the books were moved, it was noticed that the packing boxes fit more books if one didn’t just take a single slab of books off a shelf, but instead put other books around the edges.

The result was that 5100 books arrived, basically scrambled into random order. It took three days to sort them. And at this point, I decided just to keep things simpler, and alphabetize by author in each category. And this certainly works fine in finding books. But one result of my big book inventory project is that I do now have a nice, computable version of at least all the books connected to writing A New Kind of Science, and it’s actually in the Wolfram Data Repository:

✕
ResourceData["Books in Stephen Wolfram's Library"] |

In 2012 I wrote a piece about personal analytics and the data I’ve collected on myself. Back then I had about a third of a million outgoing emails in my archive; now it’s half a million more, and I can extend my diurnal plot of email I’ve sent:

(The big empty spaces are when I’m asleep, and, yes, as I’ve changed projects—e.g. finishing A New Kind of Science in 2002—my sleep habits have changed; I’m also now trying an experiment of going to sleep earlier.)

I have systems that keep all sorts of data, including every keystroke I type, every step I take and what my computer screen looks like every minute (sadly, the movie of this is very dull). I also have a whole variety of medical and environmental sensors, as well as data from devices and systems that I interact with.

It’s interesting every so often to pick up those Wolfram Data Drop databins and use them to do some data science on my life. And, yes, in broad terms I find that I am extremely consistent and habitual—yet every day there are different things that happen, that make my “productivity” (as measured in a variety of ways) bounce around, often seemingly randomly.

But one thing about collecting all this data is that I can use it to create dashboards, and these I find useful every single day. For example, running in my private cloud is a monitoring system for my email:

The yellow curve is my total number of pending email messages; the red is the number I haven’t even opened yet. These curves are pretty sensitive to all kinds of features of my life, and for example when I’m intensely working on some project, I’ll often see my email “go to seed” for a little while. But somehow in trying to pace myself and decide when I can do what, I find this email dashboard very helpful.

It’s also helpful that every day I get emails reporting on the previous day. How many keystrokes did I type, and in what applications? What files did I create? How many steps did I take? And so on.

I keep all kinds of health and medical data on myself too, and have done so for a long time. It’s always great to have started measuring something a long time ago, so one can plot a several-decade time series and see if anything’s changed. And, actually, the thing I’ve noticed is that often my value (say blood level) for something has remained numerically essentially the same for years—but many of the “normal ranges” quoted by labs have bounced all over the place. (Realistically this isn’t helped by labs inferring normal ranges from their particular observed populations, etc.)

I got my whole genome sequenced in 2010. And although I haven’t learned anything dramatic from it, it certainly helps me feel connected to genomic research when I can see some SNP variant mentioned in a paper, and I can immediately go look to see if I have it. (With all the various vicissitudes of strands, orientations and build numbers, I tend to stick to first principles, and just look for flanking sequences with `StringPosition`.)

Like so many of the things I’ve described in this piece, what has worked for me in doing personal analytics is to do what’s easy to do. I’ve never yet quite solved the problem, for example, of recording what I eat (our image identification isn’t yet quite good enough, and even made-just-for-me apps to enter food have always seemed a bit too onerous). But whenever I have a system that just operates automatically, that’s when I successfully collect good personal analytics data. And having dashboards and daily emails helps both in providing ongoing feedback, and in being able to check if something’s gone wrong with the system.

I’ve described—in arguably quite nerdy detail—how some of my personal technology infrastructure is set up. It’s always changing, and I’m always trying to update it—and for example I seem to end up with lots of bins of things I’m not using anymore (yes, I get almost every “interesting” new device or gadget that I find out about):

But although things like devices change, I’ve found that the organizational principles for my infrastructure have remained surprisingly constant, just gradually getting more and more polished. And—at least when they’re based on our very stable Wolfram Language system—I’ve found that the same is true for the software systems I’ve had built to implement them.

What of the future? Some things will certainly get upticked. I realized while writing this piece that I can now upgrade to 4k monitors (or higher) without affecting screensharing (the feed is automatically downsampled). Before too long maybe I’ll be using AR to annotate my environment in real time. Maybe eventually I’ll have some way to do XR-based as-if-in-person videoconferencing. Maybe—as I’ve been assuming will be possible for 40+ years—I’ll finally be able to type faster using something like EEG. And so on.

But the more important changes will be in having better-developed, and more automated, workflows. In time I expect it’ll be possible to use our machine learning tools to do automatic “computational history”, for example assembling a useful and appropriately clustered timeline of things I’ve done, say in a particular area.

In my efforts at historical research, I’ve had occasion to use lots of archives of people and organizations. There’s usually a certain amount of indexing and tagging that’s been done. (Who is that letter to and from? When was it written? What are its keywords? Where was it filed? And so on.) But things tend to be very granular, and it’s usually hard work to determine the overall arc of what happened.

My first goal is to make all the material I personally have useful for myself. But I’m thinking of soon starting to open up some of the older material for other people to see. And I’m studying how—in modern times, with all the cloud infrastructure, machine learning, visualization, computational documents, etc. that we have—I can build the best possible system for presenting and exploring archives.

As I think about my day, I ask myself what aspects of it aren’t well optimized. A lot of it actually comes down to things like email processing, and time spent for example actually responding to questions. Now, of course, I’ve spent lots of effort to try to structure things so as many questions as possible become self-answering, or can be addressed with technology and automation that we’ve built. And, in my role as CEO, I also try hard to delegate to other people whenever I can.

But there’s still plenty left. And I certainly wonder whether with all the technology we now have, more could be automated, or delegated to machines. Perhaps all that data I’ve collected on myself will one day let one basically just built a “bot of me”. Having seen so many of my emails—and being able to look at all my files and personal analytics—maybe it’s actually possible to predict how I’d respond to any particular question.

We’re not there yet. But it will be an interesting moment when a machine can, for example, have three ideas about how to respond to something, and then show me drafts that I can just pick from and approve. The overall question of what direction I want to go in will almost by definition have to stay with me, but the details of how to get there I’m hoping can increasingly be automated.

In the course of this piece, I’ve mentioned all sorts of devices and systems. Here’s a list of the specific products I’m currently using. Note that I’m not “endorsing” things; I’m just explaining what I happen to use, based on my research, and my particular constraints and history.

I’m listing items in the order they appear in this piece, usually not repeating if they’re mentioned multiple times. Note that some of the items here aren’t directly available anymore.

Apple 27″ Cinema Displays (1440p) [Having just discovered it’ll work with screensharing, I’m now going to upgrade to 4k displays]

Use Zoom to connect to a central location where the signal goes through OBS Studio, then we broadcast through Restream to Twitch, Facebook Live and YouTube Live

Logitech wired optical mouse [Though I’ve considered more modern and more numerously buttoned mice]

Varilux lenses [I looked at reading channel widths and Zernike polynomials etc. for custom lenses, but my correction is barely over a diopter, so I didn’t bother]

FitBit Charge 2 + Wolfram Language

Apple iPad Pro 10.5″ [I was using an iPad Mini for a while, but I wasn’t finding myself in situations where the reduced weight was a good tradeoff for reduced screen size]

Apple Mac Pro running macOS; custom-built desktop running Windows 10; custom-built desktop running Ubuntu 18 LTS

Wolfram-branded Pilot Precise Grip pens [You have to come to a Wolfram trade show booth to get one!]

[You have to be a Wolfram insider, or come to the Wolfram Summer Camp, etc. to get one....]

USB flash drive + USB-C to USB-A adaptor; USB to micro and mini USB adaptor; Apple EarPods; Apple USB-C Digital AV Multiport Adaptor; 2- to 3- prong power adaptor; FINsix Dart-C

Etro hat (discontinued type)

[A Wolfram swag item from 2012]

Iridium 9555 antenna adaptor; Iridium portable auxiliary antenna; Iridium DC charger

Apple Mail

Apple Terminal

Weather: La Crosse Technology V40-PRO-INT; Toothbrush: Oral-B 7000; Scale: Fibit Aria 2; Office environment: Electric Imp April Development Board; Air quality: Xiaomi PM2.5; Thermometer: Kinsa Smart Stick; Pulse oximeter: BodiMetrics O2 Vibe; etc. etc. etc.

We call it “Spikey”, and in my life today, it’s everywhere:

It comes from a 3D object—a polyhedron that’s called a rhombic hexecontahedron:

But what is its story, and how did we come to adopt it as our symbol?

Back in 1987, when we were developing the first version of Mathematica, one of our innovations was being able to generate resolution-independent 3D graphics from symbolic descriptions. In our early demos, this let us create wonderfully crisp images of Platonic solids. But as we approached the release of Mathematica 1.0, we wanted a more impressive example. So we decided to take the last of the Platonic solids—the icosahedron—and then make something more complex by a certain amount of stellation (or, more correctly, cumulation). (Yes, that’s what the original notebook interface looked like, 30 years ago…)

At first this was just a nice demo that happened to run fast enough on the computers we were using back then. But quite soon the 3D object it generated began to emerge as the de facto logo for Mathematica. And by the time Mathematica 1.0 was released in 1988, the stellated icosahedron was everywhere:

In time, tributes to our particular stellation started appearing—in various materials and sizes:

But just a year after we released Mathematica 1.0, we were getting ready to release Mathematica 1.2, and to communicate its greater sophistication, we wanted a more sophisticated logo. One of our developers, Igor Rivin, had done his PhD on polyhedra in hyperbolic space—and through his efforts a hyperbolic icosahedron adorned our Version 1.2 materials:

My staff gave me an up-to-date-Spikey T-shirt for my 30th birthday in 1989, with a quote that I guess even after all these years I’d still say:

After Mathematica 1.2, our marketing materials had a whole collection of hyperbolic Platonic solids, but by the time Version 2.0 arrived in 1991 we’d decided our favorite was the hyperbolic dodecahedron:

Still, we continued to explore other “Spikeyforms”. Inspired by the “wood model” style of Leonardo da Vinci’s stellated icosahedron drawing (with amazingly good perspective) for Luca Pacioli’s book De divina proportione, we commissioned a Version 2.0 poster (by Scott Kim) showing five intersecting tetrahedra arranged so that their outermost vertices form a dodecahedron:

Looking through my 1991 archives today, I find some “explanatory” code (by Ilan Vardi)—and it’s nice to see that it all just runs in our latest Wolfram Language (though now it can be written a bit more elegantly):

Over the years, it became a strange ritual that when we were getting ready to launch a new integer version of Mathematica, we’d have very earnest meetings to “pick our new Spikey”. Sometimes there would be hundreds to choose from, generated (most often by Michael Trott) using all kinds of different algorithms:

But though the color palettes evolved, and the Spikeys often reflected (though perhaps in some subtle way) new features in the system, we’ve now had a 30-year tradition of variations on the hyperbolic dodecahedron:

In more recent times, it’s become a bit more streamlined to explore the parameter space—though by now we’ve accumulated hundreds of parameters:

A hyperbolic dodecahedron has 20 points—ideal for celebrating the 20th anniversary of Mathematica in 2008. But when we wanted something similar for the 25th anniversary in 2013 we ran into the problem that there’s no regular polyhedron with 25 vertices. But (essentially using `SpherePoints[25]`) we managed to create an approximate one—and made a 3D printout of it for everyone in our company, sized according to how long they’d been with us:

In 2009, we were getting ready to launch Wolfram|Alpha—and it needed a logo. There were all sorts of concepts:

We really wanted to emphasize that Wolfram|Alpha works by doing computation (rather than just, say, searching). And for a while we were keen on indicating this with some kind of gear-like motif. But we also wanted the logo to be reminiscent of our longtime Mathematica logo. So this led to one of those classic “the-CEO-must-be-crazy” projects: make a gear mechanism out of Spikey-like forms.

Longtime Mathematica and Wolfram Language user (and Hungarian mechanical engineer) Sándor Kabai helped out, suggesting a “Spikey Gear”:

And then, in a throwback to the Version 2 intersecting tetrahedra, he came up with this:

In 2009, 3D printing was becoming very popular, and we thought it would be nice for Wolfram|Alpha to have a logo that was readily 3D printable. Hyperbolic polyhedra were out: their spikes would break off, and could be dangerous. (And something like the Mathematica Version 4 Spikey, with “safety spikes”, lacked elegance.)

For a while we fixated on the gears idea. But eventually we decided it’d be worth taking another look at ordinary polyhedra. But if we were going to adopt a polyhedron, which one should it be?

There are of course an infinite number of possible polyhedra. But to make a nice logo, we wanted a symmetrical and somehow “regular” one. The five Platonic solids—all of whose faces are identical regular polygons—are in effect the “most regular” of all polyhedra:

Then there are the 13 Archimedean solids, all of whose vertices are identical, and whose faces are regular polygons but of more than one kind:

One can come up with all sorts of categories of “regular” polyhedra. One example is the “uniform polyhedra”, as depicted in a poster for The Mathematica Journal in 1993:

Over the years that Eric Weisstein was assembling what in 1999 became MathWorld, he made an effort to include articles on as many notable polyhedra as possible. And in 2006, as part of putting every kind of systematic data into Mathematica and the Wolfram Language, we started including polyhedron data from MathWorld. The result was that when Version 6.0 was released in 2007, it included the function `PolyhedronData` that contained extensive data on 187 notable polyhedra:

It had always been possible to generate regular polyhedra in Mathematica and the Wolfram Language, but now it became easy. With the release of Version 6.0 we also started the Wolfram Demonstrations Project, which quickly began accumulating all sorts of polyhedron-related Demonstrations.

One created by my then-10-year-old daughter Catherine (who happens to have continued in geometry-related directions) was “Polyhedral Koalas”—featuring a pull-down for all polyhedra in `PolyhedronData[]`:

So this was the background when in early 2009 we wanted to “pick a polyhedron” for Wolfram|Alpha. It all came to a head on the evening of Friday, February 6, when I decided to just take a look at things myself.

I still have the notebook I used, and it shows that at first I tried out the rather dubious idea of putting spheres at the vertices of polyhedra:

But (as the Notebook History system recorded) just under two minutes later I’d generated pure polyhedron images—all in the orange we thought we were going to use for the logo:

The polyhedra were arranged in alphabetical order by name, and on line 28, there it was—the rhombic hexecontahedron:

A couple of minutes later, I had homed in on the rhombic hexecontahedron, and at exactly 12:24:24am on February 7, 2009, I rotated it into essentially the symmetrical orientation we now use:

I wondered what it would look like in gray scale or in silhouette, and four minutes later I used `ColorSeparate` to find out:

I immediately started writing an email—which I fired off at 12:32am:

“I [...] rather like the RhombicHexecontahedron ….

It’s an interesting shape … very symmetrical … I think it might have

about the right complexity … and its silhouette is quite reasonable.”

I’d obviously just copied “RhombicHexecontahedron” from the label in the notebook (and I doubt I could have spelled “hexecontahedron” correctly yet). And indeed from my archives I know that this was the very first time I’d ever written the name of what was destined to become my all-time-favorite polyhedron.

It was dead easy in the Wolfram Language to get a picture of a rhombic hexecontahedron to play with:

✕
PolyhedronData["RhombicHexecontahedron"] |

And by Monday it was clear that the rhombic hexecontahedron was a winner—and our art department set about rendering it as the Wolfram|Alpha logo. We tried some different orientations, but soon settled on the symmetrical “head-on” one that I’d picked. (We also had to figure out the best “focal length”, giving the best foreshortening.)

Like our Version 1.0 stellated icosahedron, the rhombic hexecontahedron has 60 faces. But somehow, with its flower-like five-fold “petal” arrangements, it felt much more elegant. It took a fair amount of effort to find the best facet shading in a 2D rendering to reflect the 3D form. But soon we had the first official version of our logo:

It quickly started to show up everywhere, and in a nod to our earlier ideas, it often appeared on a “geared background”:

A few years later, we tweaked the facet shading slightly, giving what is still today the logo of Wolfram|Alpha:

What is a rhombic hexecontahedron? It’s called a “hexecontahedron” because it has 60 faces, and ἑξηκοντα (hexeconta) is the Greek word for 60. (Yes, the correct spelling is with an “e”, not an “a”.) It’s called “rhombic” because each of its faces is a rhombus. Actually, its faces are golden rhombuses, so named because their diagonals are in the golden ratio ≃ 1.618:

The rhombic hexecontahedron is a curious interpolation between an icosahedron and a dodecahedron (with an icosidodecahedron in the middle). The 12 innermost points of a rhombic hexecontahedron form a regular icosahedron, while the 20 outermost points form a regular dodecahedron. The 30 “middle points” form an icosidodecahedron, which has 32 faces (20 “icosahedron-like” triangular faces, and 12 “dodecahedron-like” pentagonal faces):

Altogether, the rhombic hexecontahedron has 62 vertices and 120 edges (as well as 120−62+2=60 faces). There are 3 kinds of vertices (“inner”, “middle” and “outer”), corresponding to the 12+30+20 vertices of the icosahedron, icosidodecahedron and dodecahedron. These types of vertices have respectively 3, 4 and 5 edges meeting at them. Each golden rhombus face of the rhombic hexecontahedron has one “inner” vertex where 5 edges meet, one “outer” vertex where 3 edges meet and two “middle” vertices where 4 edges meet. The inner and outer vertices are the acute vertices of the golden rhombuses; the middle ones are the obtuse vertices.

The acute vertices of the golden rhombuses have angle 2 tan^{−1}(*ϕ*^{−1}) ≈ 63.43°, and the obtuse ones 2 tan^{−1}(*ϕ*) ≈ 116.57°. The angles allow the rhombic hexecontahedron to be assembled from Zometool using only red struts (the same as for a dodecahedron):

Across the 120 edges of the rhombic hexecontahedron, the 60 “inward-facing hinges” have dihedral angle 4𝜋/5=144°, and the 60 “outward-facing” ones have dihedral angle 2𝜋/5=72°. The solid angles subtended by the inner and outer vertices are 𝜋/5 and 3𝜋/5.

To actually draw a rhombic hexecontahedron, one needs to know 3D coordinates for its vertices. A convenient way to get these is to use the fact that the rhombic hexecontahedron is invariant under the icosahedral group, so that one can start with a single golden rhombus and just apply the 60 matrices that form a 3D representation of the icosahedral group. This gives for example final vertex coordinates {±*ϕ*,±1,0}, {±1,±*ϕ*,±(1+*ϕ*)}, {±2*ϕ*,0,0}, {±*ϕ*,±(1+2*ϕ*),0}, {±(1+*ϕ*),±(1+*ϕ*),±(1+*ϕ*)}, and cyclic permutations of these, with each possible sign being taken.

In addition to having faces that are golden rhombuses, the rhombic hexecontahedron can be constructed out of 20 golden rhombohedra (whose 6 faces are all golden rhombuses):

There are other ways to build rhombic hexecontahedra out of other polyhedra. Five intersecting cubes can do it, as can 182 dodecahedra with touching faces:

Rhombic hexecontahedra don’t tessellate space. But they do interlock in a satisfying way (and, yes, I’ve seen tens of paper ones stacked up this way):

There are also all sorts of ring and other configurations that can be made with them:

Closely related to the rhombic hexecontahedron (“RH”) is the rhombic triacontahedron (“RT”). Both the RH and the RT have faces that are golden rhombuses. But the RH has 60, while the RT has 30. Here’s what a single RT looks like:

RTs fit beautifully into the “pockets” in RHs, leading to forms like this:

The aforementioned Sándor Kabai got enthusiastic about the RH and RT around 2002. And after the Wolfram Demonstrations Project was started, he and Slovenian mathematician Izidor Hafner ended up contributing over a hundred Demonstrations about RH, RT and their many properties:

As soon as we’d settled on a rhombic hexecontahedron Spikey, we started making 3D printouts of it. (It’s now very straightforward to do this with `Printout3D[PolyhedronData[...]]`, and there are also precomputed models available at outside services.)

At our Wolfram|Alpha launch event in May 2009, we had lots of 3D Spikeys to throw around:

But as we prepared for the first post-Wolfram|Alpha holiday season, we wanted to give everyone a way to make their own 3D Spikey. At first we explored using sets of 20 plastic-covered golden rhombohedral magnets. But they were expensive, and had a habit of not sticking together well enough at “Spikey scale”.

So that led us to the idea of making a Spikey out of paper, or thin cardboard. Our first thought was then to create a net that could be folded up to make a Spikey:

My daughter Catherine was our test folder (and still has the object that was created), but it was clear that there were a lot of awkward hard-to-get-there-from-here situations during the folding process. There are a huge number of possible nets (there are already 43,380 even for the dodecahedron and icosahedron)—and we thought that perhaps one could be found that would work better:

But after failing to find any such net, we then had a new (if obvious) idea: since the final structure would be held together by tabs anyway, why not just make it out of multiple pieces? We quickly realized that the pieces could be 12 identical copies of this:

And with this we were able to create our “Paper Sculpture Kits”:

Making the instructions easy to understand was an interesting challenge, but after a few iterations they’re now well debugged, and easy for anyone to follow:

And with paper Spikeys in circulation, our users started sending us all sorts of pictures of Spikeys “on location”:

It’s not clear who first identified the Platonic solids. Perhaps it was the Pythagoreans (particularly living near so many polyhedrally shaped pyrite crystals). Perhaps it was someone long before them. Or perhaps it was a contemporary of Plato’s named Theaetetus. But in any case, by the time of Plato (≈400 BC), it was known that there are five Platonic solids. And when Euclid wrote his Elements (around 300 BC) perhaps the pinnacle of it was the proof that these five are all there can be. (This proof is notably the one that takes the most steps—32—from the original axioms of the Elements.)

Platonic solids were used for dice and ornaments. But they were also given a central role in thinking about nature, with Plato for example suggesting that perhaps everything could in some sense be made of them: earth of cubes, air of octahedra, water of icosahedra, fire of tetrahedra, and the heavens (“ether”) of dodecahedra.

But what about other polyhedra? In the 4th century AD, Pappus wrote that a couple of centuries earlier, Archimedes had discovered 13 other “regular polyhedra”—presumably what are now called the Archimedean solids—though the details were lost. And for a thousand years little more seems to have been done with polyhedra. But in the 1400s, with the Renaissance starting up, polyhedra were suddenly in vogue again. People like Leonardo da Vinci and Albrecht Dürer routinely used them in art and design, rediscovering some of the Archimedean solids—as well as finding some entirely new polyhedra, like the icosidodecahedron.

But the biggest step forward for polyhedra came with Johannes Kepler at the beginning of the 1600s. It all started with an elegant, if utterly wrong, theory. Theologically convinced that the universe must be constructed with mathematical perfection, Kepler suggested that the six planets known at the time might move on nested spheres geometrically arranged so as to just fit the suitably ordered five Platonic solids between them:

In his 1619 book Harmonices mundi (“Harmony of the World”) Kepler argued that many features of music, planets and souls operate according to similar geometric ratios and principles. And to provide raw material for his arguments, Kepler studied polygons and polyhedra, being particularly interested in finding objects that somehow formed complete sets, like the Platonic solids.

He studied possible “sociable polygons”, that together could tile the plane—finding, for example, his “monster tiling” (with pentagons, pentagrams and decagons). He studied “star polyhedra” and found various stellations of the Platonic solids (and in effect the Kepler–Poinsot polyhedra). In 1611 he had published a small book about the hexagonal structure of snowflakes, written as a New Year’s gift for a sometime patron of his. And in this book he discussed 3D packings of spheres (and spherical atoms), suggesting that what’s now called the Kepler packing (and routinely seen in the packing of fruit in grocery stores) is the densest possible packing (a fact that wasn’t formally proved until into the 2000s—as it happens, with the help of Mathematica).

There are polyhedra lurking in Kepler’s various packings. Start from any sphere, then look at its neighbors, and join their centers to make the vertices of a polyhedron. For Kepler’s densest packing, there are 12 spheres touching any given sphere, and the polyhedron one gets is the cuboctahedron, with 12 vertices and 14 faces. But Kepler also discussed another packing, 8% less dense, in which 8 spheres touch a given sphere, and 6 are close to doing so. Joining the centers of these spheres gives a polyhedron called the rhombic dodecahedron, with 14 vertices and 12 faces:

Having discovered this, Kepler started looking for other “rhombic polyhedra”. The rhombic dodecahedron he found has rhombuses composed of pairs of equilateral triangles. But by 1619 Kepler had also looked at golden rhombuses—and had found the rhombic triacontahedron, and drew a nice picture of it in his book, right next to the rhombic dodecahedron:

Kepler actually had an immediate application for these rhombic polyhedra: he wanted to use them, along with the cube, to make a nested-spheres model that would fit the orbital periods of the four moons of Jupiter that Galileo had discovered in 1610.

Why didn’t Kepler discover the rhombic hexecontahedron? I think he was quite close. He looked at non-convex “star” polyhedra. He looked at rhombic polyhedra. But I guess for his astronomical theories he was satisfied with the rhombic triacontahedron, and looked no further.

In the end, of course, it was Kepler’s laws—which have nothing to do with polyhedra—that were Kepler’s main surviving contribution to astronomy. But Kepler’s work on polyhedra—albeit done in the service of a misguided physical theory—stands as a timeless contribution to mathematics.

Over the next three centuries, more polyhedra, with various forms of regularity, were gradually found—and by the early 1900s there were many known to mathematicians:

But, so far as I can tell, the rhombic hexecontahedron was not among them. And instead its discovery had to await the work of a certain Helmut Unkelbach. Born in 1910, he got a PhD in math at the University of Munich in 1937 (after initially studying physics). He wrote several papers about conformal mapping, and—perhaps through studying mappings of polyhedral domains—was led in 1940 to publish a paper (in German) about “The Edge-Symmetric Polyhedra”.

His goal, he explains, is to exhaustively study all possible polyhedra that satisfy a specific, though new, definition of regularity: that their edges are all the same length, and these edges all lie in some symmetry plane of the polyhedron. The main result of his paper is a table containing 20 distinct polyhedra with that property:

Most of these polyhedra Unkelbach knew to already be known. But Unkelbach singles out three types that he thinks are new: two hexakisoctahedra (or disdyakis dodecahedra), two hexakisicosahedra (or dysdyakis triacontahedra), and what he calls the Rhombenhexekontaeder, or in English, the rhombic hexecontahedron. He clearly considers the rhombic hexecontahedron his prize specimen, including a photograph of a model he made of it:

How did he actually “derive” the rhombic hexecontahedron? Basically, he started from a dodecahedron, and identified its two types of symmetry planes:

Then he subdivided each face of the dodecahedron:

Then he essentially considered pushing the centers of each face in or out to a specified multiple *α* of their usual distance from the center of the dodecahedron:

For *α* < 1, the resulting faces don’t intersect. But for most values of *α*, they don’t have equal-length sides. That only happens for the specific case —and in that case the resulting polyhedron is exactly the rhombic hexecontahedron.

Unkelbach actually viewed his 1940 paper as a kind of warmup for a study of more general “k-symmetric polyhedra” with looser symmetry requirements. But it was already remarkable enough that a mathematics journal was being published at all in Germany after the beginning of World War II, and soon after the paper, Unkelbach was pulled into the war effort, spending the next few years designing acoustic-homing torpedoes for the German navy.

Unkelbach never published on polyhedra again, and died in 1968. After the war he returned to conformal mapping, but also started publishing on the idea that mathematical voting theory was the key to setting up a well-functioning democracy, and that mathematicians had a responsibility to make sure it was used.

But even though the rhombic hexecontahedron appeared in Unkelbach’s 1940 paper, it might well have languished there forever, were it not for the fact that in 1946 a certain H. S. M. (“Donald”) Coxeter wrote a short review of the paper for the (fairly new) American Mathematical Reviews. His review catalogs the polyhedra mentioned in the paper, much as a naturalist might catalog new species seen on an expedition. The high point is what he describes as “a remarkable rhombic hexecontahedron”, for which he reports that “its faces have the same shape as those of the triacontahedron, of which it is actually a stellation”.

Polyhedra were not exactly a hot topic in the mathematics of the mid-1900s, but Coxeter was their leading proponent—and was connected in one way or another to pretty much everyone who was working on them. In 1948 he published his book Regular Polytopes. It describes in a systematic way a variety of families of regular polyhedra, in particular showing the great stellated triacontahedron (or great rhombic triacontahedron)—which effectively contains a rhombic hexecontahedron:

But Coxeter didn’t explicitly mention the rhombic hexecontahedron in his book, and while it picked up a few mentions from polyhedron aficionados, the rhombic hexecontahedron remained a basically obscure (and sometimes misspelled) polyhedron.

Crystals had always provided important examples of polyhedra. But by the 1800s, with atomic theory increasingly established, there began to be serious investigation of crystallography, and of how atoms are arranged in crystals. Polyhedra made a frequent appearance, in particular in representing the geometries of repeating blocks of atoms (“unit cells”) in crystals.

By 1850 it was known that there were basically only 14 possible such geometries; among them is one based on the rhombic dodecahedron. A notable feature of these geometries is that they all have specific two-, three-, four- or six-fold symmetries—essentially a consequence of the fact that only certain polyhedra can tessellate space, much as in 2D the only regular polygons that can tile the plane are squares, triangles and hexagons.

But what about for non-crystalline materials, like liquids or glasses? People had wondered since before the 1930s whether at least approximate five-fold symmetries could exist there. You can’t tessellate space with regular icosahedra (which have five-fold symmetry), but maybe you could at least have icosahedral regions with little gaps in between.

None of this was settled when in the early 1980s electron diffraction crystallography on a rapidly cooled aluminum-manganese material effectively showed five-fold symmetry. There were already theories about how this could be achieved, and within a few years there were also electron microscope pictures of grains that were shaped like rhombic triacontahedra:

And as people imagined how these triacontahedra could pack together, the rhombic hexecontahedron soon made its appearance—as a “hole” in a cluster of 12 rhombic triacontahedra:

At first it was referred to as a “20-branched star”. But soon the connection with the polyhedron literature was made, and it was identified as a rhombic hexecontahedron.

Meanwhile, the whole idea of making things out of rhombic elements was gaining attention. Michael Longuet-Higgins, longtime oceanographer and expert on how wind makes water waves, jumped on the bandwagon, in 1987 filing a patent for a toy based on magnetic rhombohedral blocks, that could make a “Kepler Star” (rhombic hexecontahedron) or a “Kepler Ball” (rhombic triacontahedron):

And—although I only just found this out—the rhombohedral blocks that we considered in 2009 for widespread “Spikey making” were actually produced by Dextro Mathematical Toys (aka Rhombo.com), operating out of Longuet-Higgins’s house in San Diego.

The whole question of what can successfully tessellate space—or even tile the plane—is a complicated one. In fact, the general problem of whether a particular set of shapes can be arranged to tile the plane has been known since the early 1960s to be formally undecidable. (One might verify that 1000 of these shapes can fit together, but it can take arbitrarily more computational effort to figure out the answer for more and more of the shapes.)

People like Kepler presumably assumed if a set of shapes was going to tile the plane, they must be able to do so in a purely repetitive pattern. But following the realization that the general tiling problem is undecidable, Roger Penrose in 1974 came up with two shapes that could successfully tile the plane, but not in a repetitive way. By 1976 Penrose (as well as Robert Ammann) had come up with a slightly simpler version:

And, yes, the shapes here are rhombuses, though not golden rhombuses. But with angles 36°,144° and 72°,108°, they arrange with 5- and 10-fold symmetry.

By construction, these rhombuses (or, more strictly, shapes made from them) can’t form a repetitive pattern. But it turns out they can form a pattern that can be built up in a systematic, nested way:

And, yes, the middle of step 3 in this sequence looks rather like our flattened Spikey. But it’s not exactly right; the aspect ratios of the outer rhombuses are off.

But actually, there is still a close connection. Instead of operating in the plane, imagine starting from half a rhombic triacontahedron, made from golden rhombuses in 3D:

Looking at it from above, it looks exactly like the beginning of the nested construction of the Penrose tiling. If one keeps going, one gets the Penrose tiling:

Looked at “from the side” in 3D, one can tell it’s still just identical golden rhombuses:

Putting four of these “Wieringa roofs” together one can form exactly the rhombic hexecontahedron:

But what’s the relation between these nested constructions and the actual way physical quasicrystals form? It’s not yet clear. But it’s still neat to see even hints of rhombic hexecontahedra showing up in nature.

And historically it was through their discussion in quasicrystals that Sándor Kabai came to start studying rhombic hexecontahedra with Mathematica, which in turn led Eric Weisstein to find out about them, which in turn led them to be in Mathematica and the Wolfram Language, which in turn led me to pick one for our logo. And in recognition of this, we print the nestedly constructed Penrose tiling on the inside of our paper Spikey:

Our Wolfram|Alpha Spikey burst onto the scene in 2009 with the release of Wolfram|Alpha. But we still had our long-running and progressively evolving Mathematica Spikey too. So when we built a new European headquarters in 2011 we had not just one, but two Spikeys vying to be on it.

Our longtime art director Jeremy Davis came up with a solution: take one Spikey, but “idealize” it, using just its “skeleton”. It wasn’t hard to decide to start from the rhombic hexecontahedron. But then we flattened it (with the best ratios, of course)—and finally ended up with the first implementation of our now-familiar logo:

When I started writing this piece, I thought the story would basically end here. After all, I’ve now described how we picked the rhombic hexecontahedron, and how mathematicians came up with it in the first place. But before finishing the piece, I thought, “I’d better look through all the correspondence I’ve received about Spikey over the years, just to make sure I’m not missing anything.”

And that’s when I noticed an email from June 2009, from an artist in Brazil named Yolanda Cipriano. She said she’d seen an article about Wolfram|Alpha in a Brazilian news magazine—and had noticed the Spikey—and wanted to point me to her website. It was now more than nine years later, but I followed the link anyway, and was amazed to find this:

I read more of her email: “Here in Brazil this object is called ‘Giramundo’ or ‘Flor Mandacarú’ (Mandacaru Flower) and it is an artistic ornament made with [tissue paper]”.

What?! There was a Spikey tradition in Brazil, and all these years we’d never heard about it? I soon found other pictures on the web. Only a few of the Spikeys were made with paper; most were fabric—but there were lots of them:

I emailed a Brazilian friend who’d worked on the original development of Wolfram|Alpha. He quickly responded “These are indeed familiar objects… and to my shame I was never inquisitive enough to connect the dots”—then sent me pictures from a local arts and crafts catalog:

But now the hunt was on: what were these things, and where had they come from? Someone at our company volunteered that actually her great-grandmother in Chile had made such things out of crochet—and always with a tail. We started contacting people who had put up pictures of “folk Spikeys” on the web. Quite often all they knew was that they got theirs from a thrift shop. But sometimes people would say that they knew how to make them. And the story always seemed to be the same: they’d learned how to do it from their grandmothers.

The typical way to build a folk Spikey—at least in modern times—seems to be to start off by cutting out 60 cardboard rhombuses. The next step is to wrap each rhombus in fabric—and finally to stitch them all together:

OK, but there’s an immediate math issue here. Are these people really correctly measuring out 63° golden rhombuses? The answer is typically no. Instead, they’re making 60° rhombuses out of pairs of equilateral triangles—just like the standard diamond shapes used in quilts. So how then does the Spikey fit together? Well, 60° is not far from 63°, and if you’re sewing the faces together, there’s enough wiggle room that it’s easy to make the polyhedron close even without the angles being precisely right. (There are also “quasi-Spikeys” that—as in Unkelbach’s construction—don’t have rhombuses for faces, but instead have pointier “outside triangles”.)

Folk Spikeys on the web are labeled in all sorts of ways. The most common is as “Giramundos”. But quite often they are called “Estrelas da Felicidade” (“stars of happiness”). Confusingly, some of them are also labeled “Moravian stars”—but actually, Moravian stars are different and much pointier polyhedra (most often heavily augmented rhombicuboctahedra) that happen to have recently become popular, particularly for light fixtures.

Despite quite a bit of investigation, I still don’t know what the full history of the “folk Spikey” is. But here’s what I’ve found out so far. First, at least what survives of the folk Spikey tradition is centered around Brazil (even though we have a few stories of other appearances). Second, the tradition seems to be fairly old, definitely dating from well before 1900 and quite possibly several centuries earlier. So far as I can tell—as is common with folk art—it’s a purely oral tradition, and so far I haven’t found any real historical documentation about it.

My best information has come from a certain Paula Guerra, who sold folk Spikeys at a tourist-oriented cafe she operated a decade ago in the historic town of São Luíz do Paraitinga. She said people would come into her cafe from all over Brazil, see the folk Spikeys and say, “I haven’t seen one of those in 50 years…”

Paula herself learned about folk Spikeys (she calls them “stars”) from an older woman living on a multigenerational local family farm, who’d been making them since she was a little girl, and had been taught how to do it by her mother. Her procedure—which seems to have been typical—was to get cardboard from anywhere (originally, things like hat boxes), then to cover it with fabric scraps, usually from clothes, then to sew the whole perhaps-6″-across object together.

How old is the folk Spikey? Well, we only have oral tradition to go by. But we’ve tracked down several people who saw folk Spikeys being made by relatives who were born around 1900. Paula said that a decade ago she’d met an 80-year-old woman who told her that when she was growing up on a 200-year-old coffee farm there was a shelf of folk Spikeys from four generations of women.

At least part of the folk Spikey story seems to center around a mother-daughter tradition. Mothers, it is said, often made folk Spikeys as wedding presents when their daughters went off to get married. Typically the Spikeys were made from scraps of clothes and other things that would remind the daughters of their childhood—a bit like how quilts are sometimes made for modern kids going to college.

But for folk Spikeys there was apparently another twist: it was common that before a Spikey was sewn up, a mother would put money inside it, for her daughter’s use in an emergency. The daughter would then keep her Spikey with her sewing supplies, where her husband would be unlikely to pick it up. (Some Spikeys seem to have been used as pincushions—perhaps providing an additional disincentive for them to be picked up.)

What kinds of families had the folk Spikey tradition? Starting around 1750 there were many coffee and sugar plantations in rural Brazil, far from towns. And until perhaps 1900 it was common for farmers from these plantations to get brides—often as young as 13—from distant towns. And perhaps these brides—who were typically from well-off families of Portuguese descent, and were often comparatively well educated—came with folk Spikeys.

In time the tradition seems to have spread to poorer families, and to have been preserved mainly there. But around the 1950s—presumably with the advent of roads and urbanization and the move away from living on remote farms—the tradition seems to have all but died out. (In rural schools in southern Brazil there were however apparently girls in the 1950s being taught in art classes how to make folk Spikeys with openings in them—to serve as piggy banks.)

Folk Spikeys seem to have shown up with different stories in different places around Brazil. In the southern border region (near Argentina and Uruguay) there’s apparently a tradition that the “Star of St. Miguel” (aka folk Spikey) was made in villages by healer women (aka “witches”), who were supposed to think about the health of the person being healed while they were sewing their Spikeys.

In other parts of Brazil, folk Spikeys sometimes seem to be referred to by the names of flowers and fruits that look vaguely similar. In the northeast, “Flor Mandacarú” (after flowers on a cactus). In tropical wetland areas, “Carambola” (after star fruit). And in central forest areas “Pindaíva” (after a spiky red fruit).

But the most common current name for a folk Spikey seems to be “Giramundo”—an apparently not-very-recent Portuguese constructed word meaning essentially “whirling world”. The folk Spikey, it seems, was used like a charm, and was supposed to bring good luck as it twirled in the wind. The addition of tails seems to be recent, but apparently it was common to hang up folk Spikeys in houses, perhaps particularly on festive occasions.

It’s often not clear what’s original, and what’s a more recent tradition that happens to have “entrained” folk Spikeys. In the Three Kings’ Day parade (as in the three kings from the Bible) in São Luiz do Paraitinga, folk Spikeys are apparently used to signify the Star of Bethlehem—but this seems to just be a recent thing, definitely not indicative of some ancient religious connection.

We’ve found a couple of examples of folk Spikeys showing up in art exhibitions. One was in a 1963 exhibition about folk art from northeastern Brazil organized by architect Lina Bo Bardi. The other, which happens to be the largest 3D Spikey I’ve ever seen, was in a 1997 exhibition of work by architect and set designer Flávio Império:

So… where did the folk Spikey come from? I still don’t know. It may have originated in Brazil; it may have come from Portugal or elsewhere in Europe. The central use of fabrics and sewing needed to make a “60° Spikey” work might argue against an Amerindian or African origin.

One modern Spikey artisan did say that her great grandmother—who made folk Spikeys and was born in the late 1800s—came from the Romagna region of Italy. (One also said she learned about folk Spikeys from her French-Canadian grandmother.) And I suppose it’s conceivable that at one time there were folk Spikeys all over Europe, but they died out enough generations ago that no oral tradition about them survives. Still, while a decent number of polyhedra appear, for example, in European paintings from earlier centuries, I don’t know of a single Spikey among them. (I also don’t know of any Spikeys in historical Islamic art.)

But ultimately I’m pretty sure that somewhere there’s a single origin for the folk Spikey. It’s not something that I suspect was invented more than once.

I have to say that I’ve gone on “art origin hunts” before. One of the more successful was looking for the first nested (Sierpiński) pattern—which eventually led me to a crypt in a church in Italy, where I could see the pattern being progressively discovered, in signed stone mosaics from just after the year 1200.

So far the Spikey has proved more elusive—and it certainly doesn’t help that the primary medium in which it appears to have been explored involved fabric, which doesn’t keep the way stone does.

Whatever its ultimate origins, Spikey serves us very well as a strong and dignified icon. But sometimes it’s fun to have Spikey “come to life”—and over the years we’ve made various “personified Spikeys” for various purposes:

When you use Wolfram|Alpha, it’ll usually show its normal, geometrical Spikey. But just sometimes your query will make the Spikey “come to life”—as it does for pi queries on Pi Day:

Polyhedra are timeless. You see a polyhedron in a picture from 500 years ago and it’ll look just as clean and modern as a polyhedron from my computer today.

I’ve spent a fair fraction of my life finding abstract, computational things (think cellular automaton patterns). And they too have a timelessness to them. But—try as I might—I have not found much of a thread of history for them. As abstract objects they could have been created at any time. But in fact they are modern, created because of the conceptual framework we now have, and with the tools we have today—and never seen before.

Polyhedra have both timelessness and a rich history that goes back thousands of years. In their appearance, polyhedra remind us of gems. And finding a certain kind of regular polyhedron is a bit like finding a gem out in the geometrical universe of all possible shapes.

The rhombic hexecontahedron is a wonderful such gem, and as I have explored its properties, I have come to have even more appreciation for it. But it is also a gem with a human story—and it is so interesting to see how something as abstract as a polyhedron can connect people across the world with such diverse backgrounds and objectives.

Who first came up with the rhombic hexecontahedron? We don’t know, and perhaps we never will. But now that it is here, it’s forever. My favorite polyhedron.

Help spread Spikeyism! Spikey Paper Sculpture kits are available from the Wolfram store. Assemble yours and send us a picture (Twitter, Facebook, email)!