summaryrefslogtreecommitdiff
path: root/content
diff options
context:
space:
mode:
Diffstat (limited to 'content')
-rw-r--r--content/_index.md17
-rw-r--r--content/blog/2020/email-server-extras.md414
-rw-r--r--content/blog/2020/email-server.md718
-rw-r--r--content/blog/_index.md7
-rw-r--r--content/know/_index.md32
-rw-r--r--content/know/category/_index.md8
-rw-r--r--content/know/category/mathematics.md9
-rw-r--r--content/know/category/physics.md9
-rw-r--r--content/know/category/quantum-mechanics.md9
-rw-r--r--content/know/concept/_index.md8
-rw-r--r--content/know/concept/blochs-theorem/index.pdc115
-rw-r--r--content/know/concept/convolution-theorem/index.pdc100
-rw-r--r--content/know/concept/dirac-delta-function/index.pdc109
-rw-r--r--content/know/concept/dirac-notation/index.pdc129
-rw-r--r--content/know/concept/fourier-transform/index.pdc117
-rw-r--r--content/know/concept/gram-schmidt-method/index.pdc47
-rw-r--r--content/know/concept/hilbert-space/index.pdc202
-rw-r--r--content/know/concept/legendre-transform/index.pdc89
-rw-r--r--content/know/concept/parsevals-theorem/index.pdc76
-rw-r--r--content/know/concept/partial-fraction-decomposition/index.pdc60
-rw-r--r--content/know/concept/pauli-exclusion-principle/index.pdc125
-rw-r--r--content/know/concept/probability-current/index.pdc98
-rw-r--r--content/know/concept/slater-determinant/index.pdc54
-rw-r--r--content/know/concept/sturm-liouville-theory/index.pdc346
-rw-r--r--content/know/concept/time-independent-perturbation-theory/index.pdc329
-rw-r--r--content/know/concept/wentzel-kramers-brillouin-approximation/index.pdc198
-rw-r--r--content/uses.md110
27 files changed, 3535 insertions, 0 deletions
diff --git a/content/_index.md b/content/_index.md
new file mode 100644
index 0000000..e9e5dcc
--- /dev/null
+++ b/content/_index.md
@@ -0,0 +1,17 @@
+---
+title: "Home"
+date: 2021-02-22T17:15:50+01:00
+draft: false
+---
+
+Welcome to my website.
+
+Once in a blue moon, I'll post something here
+related to my areas of interest:
+programming, optimization,
+mathematics, physics and even linguistics.
+
+This site is served to you by [nginx](https://nginx.org/),
+and statically generated by [Hugo](https://gohugo.io).
+I intend to keep it forever free of advertising and trackers,
+and to maintain my A+ score for [TLS quality](https://www.ssllabs.com/ssltest/analyze.html?d=prefetch.eu).
diff --git a/content/blog/2020/email-server-extras.md b/content/blog/2020/email-server-extras.md
new file mode 100644
index 0000000..72299c9
--- /dev/null
+++ b/content/blog/2020/email-server-extras.md
@@ -0,0 +1,414 @@
+---
+title: "Setting up an email server in 2020 with OpenSMTPD and Dovecot: extras"
+publishDate: 2020-04-27
+date: 2021-02-22T17:19:49+01:00
+draft: false
+---
+
+#
+
+This sequel to my earlier [guide](/blog/2020/email-server/) discusses
+extra tips and tricks to extend your email setup.
+This page will be updated continuously as I come up with ideas.
+
+Last updated 2020-04-29.
+
+
+## General
+
+### Multiple domains
+
+You can generalize your setup to handle multiple domains
+with very little effort. In the following,
+I'll assume that your two domains are called `foo.com` and `bar.com`.
+
+
+#### DNS records
+
+There should be MX, SPF, DKIM and DMARC records for both domains,
+as explained in the previous guide. Fortunately, these records
+can have identical contents for both domains!
+
+However, it remains essential that the mail server's mailname
+and reverse DNS domain name match up exactly,
+so you should create MX records with that in mind.
+Therefore, if the email server for both domains has `mx1.foo.com`
+as reverse DNS name, the MX records should look like this:
+```sh
+foo.com. MX 42 mx1.foo.com.
+bar.com. MX 42 mx1.foo.com.
+```
+This is perfectly valid: the only thing that matters is that
+what your SMTP server calls itself agrees with what reverse DNS
+says that the server is actually called.
+
+
+#### Dovecot
+
+To make Dovecot aware of multiple domains,
+you only need to update the `/etc/dovecot/users` file
+to add accounts for both domains.
+However, in the original guide, I said to only write `user`
+in the file, without the `@foo.com`, for an address `user@foo.com`.
+Unsurprisingly, that isn't an option for multiple domains,
+so you must put the full address in `/etc/dovecot/users`.
+
+Then update `/etc/dovecot/dovecot.conf` to reflect that,
+by changing `%n` to `%u` in `username_format`:
+```sh
+userdb {
+ driver = passwd-file
+ args = username_format=%u /etc/dovecot/users
+ override_fields = uid=vmail gid=vmail home=/home/vmail/%d/%n
+}
+```
+Also note the change in the `home` setting:
+the inbox of a user `user@foo.com` will now be stored
+in `/home/vmail/foo.com/user`.
+That's all you need to change.
+
+
+#### OpenSMTPD
+
+To inform OpenSMTPD of all the domains,
+create a new file `/etc/smtpd/domains`,
+and in there put all desired names on their own line:
+```sh
+foo.com
+bar.com
+```
+And as I mentioned when discussing the DNS records,
+you should check that `/etc/smtpd/mailname` agrees
+with your server's reverse DNS.
+
+Then, in the main configuration file, tell OpenSMTPD to
+use the new domains file when deciding whether to accept an message,
+by declaring a new table and changing the `match` line for inbound mail:
+```sh
+table domains "/etc/smtpd/domains"
+# ...
+match from any for domain <domains> action "RECV"
+```
+
+#### Rspamd
+
+The last thing to do is to inform Rspamd of the multiple domains.
+It's really easy: simply add multiple domain blocks:
+```c
+domain {
+ foo.com {
+ path = "/path/to/dkim/private.key";
+ selector = "hello";
+ }
+}
+domain {
+ bar.com {
+ path = "/path/to/dkim/private.key";
+ selector = "world";
+ }
+}
+```
+
+### Advanced security
+
+SPF, DKIM and DMARC are email's traditional DNS-based security systems,
+but in 2018 the IETF released [RFC 8460](https://tools.ietf.org/html/rfc8460) and [RFC 8461](https://www.rfc-editor.org/rfc/rfc8461.txt),
+which respectively define TLSRPT and MTA-STS,
+two fancy new systems focused on TLS-encrypted email transport.
+
+These security mechanisms are pretty new,
+so you won't get a huge benefit from enabling them,
+but big email providers' draconian spam filters might like it.
+
+
+#### TLSRPT
+
+TLS reporting, or TLSRPT for short, is very simple:
+all it does is provide a contact email address in case
+somebody has trouble with the TLS configuration of your SMTP server.
+
+To enable it for your custom email domain `example.com`,
+simply create a DNS TXT record for the `_smtp._tls` subdomain:
+```sh
+_smtp._tls.example.com. TXT "v=TLSRPTv1; rua=mailto:<contact>"
+```
+Where `<contact>` is an email address of your choosing.
+That's all!
+
+
+#### MTA-STS
+
+MTA Strict Transport Security (MTA-STS) tells other servers
+that you take TLS encryption of messages very seriously,
+so they should avoid sending you unencrypted email,
+and should only accept certain certificates from your side.
+
+Compared to the previously discussed DNS-based security extensions,
+MTA-STS is a bit more work to set up,
+because you'll also need an HTTP web server.
+
+The DNS part is still pretty simple:
+create yet another DNS TXT record,
+this time for the subdomain `_mta-sts`:
+```sh
+_mta-sts.example.com. TXT "v=STSv1; id=<id>"
+```
+The `<id>` should identify the version of your policy,
+so other servers can quickly see if something changed.
+I recommend using today's date.
+
+For the next part, I'll assume that you already have
+a web server running on a server with the IP address `1.2.3.4`.
+I use [nginx](https://nginx.org/) for this, running
+on the same server as OpenSMTPD and Dovecot,
+but you don't have to do the same.
+
+Create an A record which binds your server
+to the subdomain `mta-sts` (without underscore):
+```sh
+mta-sts.example.com. A 1.2.3.4
+```
+Set your web server to serve the file
+`https://mta-sts.example.com/.well-known/mta-sts.txt`
+(we'll discuss that file in a moment).
+Note that this policy file **must** be served over HTTPS,
+so you need a valid TLS certificate for that domain.
+
+The contents of the `mta-sts.txt` policy file are as follows,
+where `mx1.example.com` and `mx2.example.com` are the hosts
+mentioned in `example.com`'s DNS MX records:
+```sh
+version: STSv1
+mode: enforce
+mx: mx1.example.com
+mx: mx2.example.com
+max_age: <age>
+```
+All MX servers must be mentioned this way.
+If you're feeling cautious, you may want to set
+`mode` to `testing` in the beginning.
+This policy is valid for `<age>` seconds,
+which is recommended to be several weeks,
+but to start with, I suggest using 86400 seconds (one day).
+Finally, ensure that this file has CRLF Windows-style line endings.
+
+To correctly pass an MTA-STS test, the TLS certificate
+presented by e.g. `mx1.example.com` should be valid for `mx1.exaple.com`.
+To achieve this without needing to manage too many certificates,
+you can specify multiple domains when requesting a certificate,
+or you can use a wildcard domain (`*.example.com`).
+Note, however, that MTA-STS testing tools don't like
+the latter option, so I recommend the former.
+
+Once you're done, check your work by using either
+[ESMTP](https://esmtp.email/tools/mta-sts/)'s or [Ayke](https://aykevl.nl/apps/mta-sts/)'s
+online MTA-STS validation tools,
+ignoring any warnings about DNSSEC or DANE.
+If all is good, great!
+
+Even if you did everything correctly,
+these tools will warn you that you're not using DNSSEC/DANE.
+It might then be tempting to set that up for even more security,
+but I recommend against that for private servers: take a look at [this](https://dane.sys4.de/common_mistakes).
+
+
+
+## OpenSMTPD
+
+### Client certificates (in addition to passwords)
+
+You can configure OpenSMTPD to request a client certificate
+for sending emails, as a second factor for authentication.
+
+
+#### Certificates
+
+We need to start with some cryptography to create and verify certificates.
+I recommend that you do all of this on your trusted *client* device,
+and only copy the necessary files to the server later.
+
+DISCLAIMER:
+All the keys and certificates that we'll generate in this section are
+for **private use** only, to handle a small number of trusted clients.
+I'm not a cryptography expert, so you should **not** listen to me
+for large-scale systems that may involve untrusted devices.
+
+The first step is to set up a private Certificate Authority (CA),
+which issues the client certificates and can be used to verify them.
+Start by generating an RSA private key,
+which you should store in a safe place and not share with anyone:
+```sh
+$ openssl genrsa -out mailca.key 2048
+```
+Extract a public certificate from this key as follows.
+Because we're lazy, we give it a lifetime of 36500 days:
+```sh
+$ openssl req -new -x509 -days 36500 -key mailca.key -out mailca.crt
+```
+When running this command, OpenSSL will ask you some questions
+about who this certificate is intended for.
+Since this is for personal use, your answers don't matter,
+so just use the defaults.
+Some fields (I think only *Country Name* and *Organization Name*)
+cannot be empty, but the others can.
+
+Moving on to the client, once again generate an RSA private key:
+```sh
+$ openssl genrsa -out mailclient.key 2048
+```
+From this private key, create a Certificate Signing Request (CSR)
+as follows, where you'll be asked the same questions as before:
+```sh
+$ openssl req -new -key mailclient.key -out mailclient.csr
+```
+By feeding this CSR to the CA, we can create a signed client certificate
+that can be verified using the CA's public certificate.
+```sh
+$ openssl x509 -req -in mailclient.csr -out mailclient.crt \
+ -days 36499 -CA mailca.crt -CAkey mailca.key
+```
+If you want to multiple client certificates,
+just repeat the last few steps for each one.
+
+
+#### Server
+
+OpenSMTPD needs to verify the validity of client certificates
+using the CA's public certificate, so you should copy that
+to somewhere on the server, e.g. `/etc/smtpd/mailca.crt`,
+and declare it to OpenSMTPD by adding this near
+the top of `/etc/smtpd/smtpd.conf`:
+```sh
+ca "mailca" cert "/etc/smtpd/mailca.crt"
+```
+Then replace the entire configuration for outbound mail as follows.
+Note that this removes SMTPS support, leaving only STARTTLS:
+```sh
+# Outbound
+listen on eth0 port 587 tls-require verify pki "example.com" ca "mailca" auth <passwds> filter "rspamd"
+action "SEND" relay srs
+match from any auth for any action "SEND"
+```
+The magic word here is "`verify`", which tells OpenSMTPD
+to ask for a client certificate and to verify it using the given CA.
+
+
+#### Client
+
+Now you won't be able to send emails if your client doesn't
+present its certificate to the server!
+Unfortunately, not all mail clients support this; personally
+I use [Thunderbird](https://www.thunderbird.net/) with success.
+I won't include any client-specific configuration here,
+but I will say this:
+
+For some clients (like Thunderbird), you'll have an easier time
+importing your client certificate if you encode it in the
+[PKCS #12](https://en.wikipedia.org/wiki/PKCS_12) storage format:
+```sh
+$ openssl pkcs12 -export -in mailclient.crt -inkey mailclient.key \
+ -certfile mailca.crt -out mailclient.pfx
+```
+OpenSSL will ask you to set a password, which you'll need to
+enter again when importing the certificate into the client.
+
+
+
+### Client certificates (instead of passwords)
+
+If you really want to, you can use the client certificates
+as a substitute for passwords. This is especially useful
+if you set up a catchall inbox in Dovecot,
+because this will allow you to send emails
+from arbitrary addresses from your domain.
+
+To do this, follow the same procedure as in the previous section,
+but with a slightly different OpenSMTPD configuration:
+```sh
+listen on eth0 port 587 tls-require verify pki "example.com" ca "mailca" filter "rspamd" tag "VALID"
+action "SEND" relay srs
+match from any tag "VALID" for any action "SEND"
+```
+All incoming connections that present a good certificate
+will be tagged as being `VALID`, and their mail will be relayed.
+
+Unfortunately, we're not quite done yet here,
+because Rspamd is now very confused...
+
+
+#### Rspamd
+
+When OpenSMTPD passes a message through Rspamd, it also includes
+some metadata, most notably whether the sender has authenticated
+successfully with OpenSMTPD... which is now no longer the case
+for submissions, because we've removed the `auth` directive!
+
+Rspamd therefore starts regarding these outgoing emails
+as *incoming* emails, because they don't seem
+to come from a trusted user. So instead of signing them with DKIM
+and handing them back to OpenSMTPD, it will do a full spam scan.
+If they get a high spam score (which is likely for short test emails),
+*your* spam filter, running on *your* server,
+will be flagging *your* messages as spam!
+
+The solution is to whitelist your domain(s) in Rspamd,
+so it won't scan them. To do this, create a new file
+`/etc/rspamd/local.d/settings.conf` with these contents,
+where `foo.com` and `bar.com` are the domains to whitelist:
+```c
+outbound {
+ priority = high;
+ from = "@foo.com";
+ from = "@bar.com";
+ apply {
+ actions {
+ add_header = 1000;
+ }
+ }
+}
+```
+Setting `priority` to `high` ensures that Rspamd checks
+this rule before doing anything else.
+You can add any number of `from` directives;
+this rule will be applied if any of them match.
+It only sets the threshold for the action `add_header` to `1000`.
+That is, if the email doesn't get a spam score of at least 1000
+(the default is 6) Rspamd will not add any spam tags.
+
+Because Rspamd is still regarding your emails as inbound,
+you also need to change the global settings of
+the DKIM signer in `/etc/rspamd/local.d/dkim_signing.conf`,
+such that they include the following:
+```c
+sign_inbound = true;
+allow_hdrfrom_mismatch = true;
+allow_username_mismatch = true;
+```
+This tells Rspamd to add DKIM signatures to incoming emails,
+which in this case includes yours.
+Allowing these mismatches ensures that the messages still get signed,
+even if you're sending from an arbitrary address.
+
+
+
+## Dovecot
+
+### Catchall inbox
+
+In Dovecot, you can create a catch-all inbox that will accept all
+emails sent to your domain that don't match anyone in `/etc/dovecot/users`.
+Just add another `userdb` block *after* the first:
+```sh
+userdb {
+ driver = static
+ args = uid=vmail gid=vmail home=/var/vmail/catchall allow_all_users=yes
+}
+```
+The `static` driver means there is no table file:
+all configuration is directly within this `userdb` block.
+If we don't specify `allow_all_users=yes`, then Dovecot
+will check whether users exist using the `passdb` table,
+and will conclude that the recipient is invalid.
+
+
+
diff --git a/content/blog/2020/email-server.md b/content/blog/2020/email-server.md
new file mode 100644
index 0000000..3b7f439
--- /dev/null
+++ b/content/blog/2020/email-server.md
@@ -0,0 +1,718 @@
+---
+title: "Setting up an email server in 2020 with OpenSMTPD and Dovecot"
+publishDate: 2020-04-27
+date: 2021-02-22T17:27:49+01:00
+draft: false
+---
+
+#
+
+So, you want to set up your own email server? In that case, welcome.
+
+There are many reasons to run a custom email server,
+ranging from privacy concerns about providers like Google,
+to just wanting to do it for fun and/or learning.
+Since you're here, I assume you've already found a reason.
+
+Beware: this is a messy topic, and the available documentation
+is even messier, so it could take a while before you get it to work properly.
+I've compiled this guide according to my experiences
+in an attempt to make this dark art more accessible,
+but your mileage may vary considerably. I hope you find it useful.
+
+This guide is aimed at people who are comfortable with
+the Linux/*BSD command line.
+
+When you're done, take a look at the
+[sequel](/blog/2020/email-server-extras/)
+for ideas to extend your setup.
+
+Last content update on 2020-04-29. Last correction on 2021-02-20.
+
+
+
+## Preparation
+
+Setting up email is relatively complex compared to e.g. a static website,
+because you need to configure not one, but *two* server programs,
+*and* you need to shoehorn modern security features into email's Stone-Age design.
+I'll start by explaining the general structure of a mail server setup.
+
+
+### How email works
+
+The programs involved in the exchange of emails are called [agents](https://en.wikipedia.org/wiki/Email_agent_(infrastructure)).
+Officially, there are 5 different types of agent: MUA, MSA, MTA, MDA and MRA.
+But fortunately, it's reasonable to treat the MRA and MSA
+as being part of the MUA and MTA, respectively.
+
+The *Mail User Agent* (MUA) is simply the client on your device at home
+that you use to send and receive emails, and this guide assumes
+you already have a favourite program for this, e.g. [Thunderbird](https://www.thunderbird.net/en-US/).
+Nowadays it's fashionable to use a web interface for emails,
+but that's also beyond the scope of this guide.
+
+The *Mail Delivery Agent* (MDA) is a program that watches over
+the server's copy of your mailbox: it manages your inbox,
+remembers which messages you have or haven't read,
+keeps a copy of your drafts, etc.
+When you open your mailbox, your MUA will connect to
+your server's MDA using the [IMAP](https://en.wikipedia.org/wiki/Internet_Message_Access_Protocol) protocol
+(or [POP3](https://en.wikipedia.org/wiki/Post_Office_Protocol), but that one's [obsolete](https://pop2imap.com/)).
+
+The *Mail Transfer Agent* (MTA) is responsible for
+making messages arrive at the right destination.
+When you send an email, your MUA will pass it on to your server's MTA,
+which will in turn pass it on to the recipient's mail server.
+Likewise, when someone sends *you* an email from another server,
+the MTA will receive it and hand it over to the MDA so you can read it later.
+In both cases the MTA speaks the [SMTP](https://en.wikipedia.org/wiki/Simple_Mail_Transfer_Protocol) protocol.
+
+In this guide our MDA will be [Dovecot](https://dovecot.org/),
+which is a very popular choice for that role.
+As for the MTA, there exist several options,
+the most popular being [Postfix](http://www.postfix.org/) and [Exim](https://exim.org/).
+However, this guide uses the newer, lesser-known [OpenSMTPD](https://opensmtpd.org/),
+which in my experience is *much* easier to set up:
+Postfix and Exim have complex configurations and
+are geared towards large-scale email providers,
+whereas OpenSMTPD is more beginner-friendly.
+
+
+
+### Security
+
+The base email system is horribly insecure on its own,
+so we still need to duct-tape on some security features.
+In this context, "security" has two meanings:
+spam protecion and privacy protection (encryption).
+
+Spam protection also means two things here:
+defending yourself against spammers, and
+preventing that *your* emails get flagged as spam.
+The former is optional, but the latter is not:
+big providers such as Google and Microsoft
+use infamously strict spam filters,
+and if they decide that your server is a spammer,
+there's almost nothing you can do about it.
+Spam protection techniques will be discussed
+in more detail over the course of this guide.
+
+Privacy protection is important in the 21st century:
+you don't want a random router in the Internet to read all your emails,
+which may contain sensitive information such as
+private conversations and account password reset links.
+You should therefore try to make sure that emails are
+transported over an encrypted channel.
+To do this, you have two options for encryption:
+*mandatory* and *opportunistic* encryption.
+
+Mandatory encryption is only practical for client-server
+communication (not server-server), and is provided by IMAPS and SMTPS,
+which wrap the IMAP and SMTP protocols in [TLS](https://en.wikipedia.org/wiki/Transport_Layer_Security),
+in the same way that [HTTPS](https://en.wikipedia.org/wiki/HTTPS) does for [HTTP](https://en.wikipedia.org/wiki/Hypertext_Transfer_Protocol).
+
+For server-server communication, the only option is
+opportunistic encryption in the form of [STARTTLS](https://en.wikipedia.org/wiki/STARTTLS),
+where communication is only encrypted if both parties agree
+after a short unencrypted discussion.
+That last part is vulnerable to [MitM](https://en.wikipedia.org/wiki/Man-in-the-middle_attack) attacks,
+where anyone along the path of the email servers' discussion
+can alter the exchange to block the use of encryption,
+which sometimes actually [happens](https://www.eff.org/deeplinks/2014/11/starttls-downgrade-attacks) in practice.
+
+The only way to make sure that STARTTLS is used in that case
+is to refuse any exchange unless the servers agree to use encryption.
+Unfortunately, that's a risky approach that I can't recommend,
+because not all servers support encryption (unbelievable, right?).
+For example, I've received airline booking confirmations,
+full of personal details, and made with billion-dollar companies,
+sent across the Internet without any protection.
+
+This guide includes intructions to enable encryption,
+but assumes that you already have a TLS certificate for that.
+If not, find a guide to get one from [Let's Encrypt](https://letsencrypt.org/) (it's free!),
+and remember that you'll need to renew it every few months.
+Using a self-signed certificate *may* work, but I don't recommend it.
+
+In the rest of this guide I'll assume that
+you have a public full-chain TLS certificate at `/etc/ssl/certs/example.com.pem`,
+and a private encryption key at `/etc/ssl/private/example.com.pem`.
+
+
+
+### Server
+
+Obviously, you'll need a server to run the MTA and MDA on.
+You can host your own at home, but the more reliable option is
+to rent one in a data center ([VPS](https://en.wikipedia.org/wiki/Virtual_private_server)).
+This guide was written with a Linux server in mind,
+but in theory it should also work on the BSDs
+([OpenBSD](https://www.openbsd.org/), [FreeBSD](https://www.freebsd.org/),
+[NetBSD](https://www.netbsd.org/), etc.) with minimal adaptation.
+
+The server must be online 24/7, you must have root SSH access,
+it must have a static IP address, and TCP network port 25 must be open.
+Especially check that last one: you may need to explicitly ask
+your home ISP or the server provider to enable port 25,
+because they often close it to prevent spam.
+You can usually do this from their web interface.
+
+You also must have a domain name, which I'll call `example.com`.
+This will be necessary for basically everything:
+DNS records, TLS certificate, MTA network configuration, etc.
+If you don't have one yet, you can choose between many registrars
+to rent one from. Personally I use and can recommend [Gandi](https://www.gandi.net/).
+
+Note that it's a **bad** idea to use a domain like `foo.bar.com`,
+where you control the `foo` part but *not* the `bar` part:
+in that case, a spammer in control of `qux.bar.com`
+could negatively affect *your* reputation
+in the eyes of other email providers.
+
+Lastly, when setting up an email server, you also have the choice
+between using to *system* users or *virtual* users.
+With system users, if an email arrives for `john@example.com`,
+then the MTA and MDA will expect that there exists
+a `john` Unix user on the server to deliver it to.
+With virtual users, you have much more flexibility, so that's what we'll use.
+All email will be managed under a single Unix user/group called `vmail`.
+Create it as follows:
+```sh
+# GNU CoreUtils:
+$ groupadd vmail
+$ useradd -g vmail vmail
+# BusyBox:
+$ addgroup vmail
+$ adduser -D -G vmail vmail
+# *BSD:
+$ no clue, but it should be similar
+```
+
+
+## DNS records
+
+Now we must set up all the necessary DNS records, which
+is usually possible from the domain registrar's web interface.
+It may take a while for your changes to propagate over the Internet,
+so I recommend doing this section now and the rest tomorrow.
+
+Firstly, you should already have an A and/or AAAA record
+to associate your domain `example.com` with the server's IP address.
+For email it is **essential** that you also have [reverse DNS](https://en.wikipedia.org/wiki/Reverse_DNS_lookup)
+set up correctly. If you're renting your server remotely,
+you can often do this from the provider's configuration tool,
+otherwise, you should create a PTR-type DNS record,
+although that's beyond the scope of this guide.
+
+Once you're done, I recommend testing your DNS records
+using the [MX Lookup](https://mxtoolbox.com/MXLookup.aspx) online tool.
+
+
+
+### MX
+
+To inform the rest of the Internet that your server is an email server,
+create an MX (Mail eXchanger) DNS record for your domain.
+Note the dot at the end of the domain name:
+```
+example.com. MX 42 example.com.
+```
+When a message is sent to an email address ending in `@example.com`,
+the sender will query DNS for any MX records for `example.com`.
+There it will find a domain name (in this case `example.com` again),
+for which it will look up the IP address using an A/AAAA record.
+The domain name in the record must **not** have an associated CNAME record;
+it must be directly translatable to an IP address.
+
+You may have multiple MX records, containing different domain names,
+each with a preference number (`42` in the example above).
+The sender will try MX records with *lower* numbers first,
+and if that server is unavailable, it will try a higher number.
+If you have multiple mail servers (which is a good idea),
+you can thus declare those as follows:
+```
+example.com. MX 13 mx1.example.com.
+example.com. MX 42 mx2.example.com.
+```
+Here, a server sending an email to your domain `example.com`
+will try to send it to the IP address of `mx1.example.com` first,
+and if that fails, it will move on to `mx2.example.com`.
+If both `mx1` and `mx2` have the same number, then the sender
+will randomly choose one, which is useful for load balancing,
+although that's probably overkill for a private server.
+
+
+
+### SPF
+
+The [Sender Policy Framework](https://en.wikipedia.org/wiki/Sender_Policy_Framework) (SPF),
+is a feature which helps prevent spammers from impersonating
+your server in an attempt to get around blacklists.
+This security feature is **required** nowadays:
+if you don't use it, you'll probably get flagged as spam.
+
+SPF works by specifying which IP addresses are authorized
+to send emails from your domain name.
+You must publish this information in a
+TXT-type DNS record (**not** SPF-type, which also exists!) with the following contents:
+```
+example.com. TXT "v=spf1 mx -all"
+```
+Everything after the version `v=spf1` is a list of *verification mechanisms*
+for a spam filter to try out in the given order.
+The `-all` at the end says to reject your email
+if all of the previous mechanisms fail.
+See the [SPF spec](https://tools.ietf.org/html/rfc7208) for details.
+
+I recommend only using the `mx` mechanism, which tells the verifier
+to look at the A/AAAA addresses of the domains in your MX records.
+This allows you to add, remove, or change your servers
+without needing to update this record.
+
+
+
+### DKIM
+
+Then we have [DomainKeys Identified Mail](https://en.wikipedia.org/wiki/DomainKeys_Identified_Mail) (DKIM),
+which is a more comprehensive form of anti-impersonation,
+and, like SPF, is practically **mandatory** in the modern era.
+
+It adds a cryptographic signature to all emails from your server,
+which the receiver's spam filter will verify using the email's contents,
+and a public key that you need to publish in a DNS record.
+Again, you should implement *both* SPF and DKIM, despite their overlap.
+
+To set up DKIM, create an RSA keypair, using the `openssl` utility:
+```sh
+$ openssl genrsa -out /path/to/dkim/private.key 2048
+$ openssl rsa -in /path/to/dkim/private.key -out /path/to/dkim/public.key
+```
+The minimum size is 1024 bits, but I recommend 2048 bits.
+Bigger is better, but because DNS is involved you can't stretch it
+to 4096 bits without causing discomfort to [some](https://serverfault.com/questions/747185/dkim-can-i-use-a-rsa-key-larger-than-2048bit-i-e-4096) servers.
+And I think it goes without saying that you should keep the private key private.
+
+Importantly, the DKIM DNS record **cannot** be
+attached directly to your domain `example.com`;
+instead, it should belong to a subdomain of the form
+`<selector>._domainkey.example.com`,
+where `<selector>` is an alphanumeric string you can choose (e.g. today's date),
+just remember your choice for later when configuring the DKIM signer.
+And if you change your key, keep the old record around
+for a while so old emails can still be verified.
+
+Your DKIM policy must be published in a TXT record
+as follows, where `<pubkey>` is the public RSA key `MI...AB`
+stored in `/path/to/dkim/public.key`, with the newlines removed:
+```
+<selector>._domainkey.example.com. TXT "v=DKIM1; t=s; h=sha256; p=<pubkey>"
+```
+Here, `v=DKIM1` is the version and must be the first tag.
+The flag `t=s` enables strict mode, as recommended by the [DKIM spec](https://tools.ietf.org/html/rfc6376),
+meaning that emails sent from subdomains immediately fail verification.
+The optional tag `h=sha256` blocks the use of the old SHA1 algorithm.
+
+
+
+### DMARC
+
+Lastly, we have [Domain-based Message Authentication, Reporting and Conformance](https://en.wikipedia.org/wiki/DMARC) (DMARC),
+which is *technically* optional, but *highly* recommended,
+because it will make you look more legitimate in the eyes of Google and Microsoft.
+It can modify the behaviour of SPF and DKIM,
+and also provides advice about what a receiver should do
+if one of your emails fails verification.
+
+To enable it, create yet another TXT record, which,
+similarly to DKIM, **must** belong to the subdomain `_dmarc.example.com`,
+and give it the following contents,
+where `<admin>` is an email address of your choosing,
+which may or may not belong to your domain:
+```
+_dmarc.example.com. TXT "v=DMARC1; p=reject; sp=reject; pct=100; aspf=s; adkim=s; fo=1; ruf=mailto:<admin>"
+```
+The version tag `v=DMARC1` must come first,
+followed by `p=` and `sp=`, which control what to do to unverified messages
+coming from the main domain and subdomains, respectively.
+Unsurprisingly, `reject` means that delivery should be refused,
+`none` asks to let it through anyway, and `quarantine` tells
+the filter to take a closer look or to put it in a spam folder.
+The percentage `pct=100` says how many of your emails to apply the policy to.
+Next, `aspf=s` and `adkim=s` enable strict mode for both SPF and DKIM,
+which blocks subdomains from passing the test.
+Finally, `fo=1` asks the filter to create a forensic report
+if any type of verification fails, and `ruf=` gives an address to send it to.
+If in doubt, see the [DMARC spec](https://tools.ietf.org/html/rfc7489).
+
+
+
+## MDA: Dovecot
+
+[Dovecot](https://www.dovecot.org/) is a very popular IMAP server,
+focused on being lightweight, simple, and secure,
+and has extensive and up-to-date documentation.
+It's very flexible and scalable, and keeps up well
+with the lastest security best-practices.
+
+If you installed Dovecot via a package manager,
+you'll probably have lots of configuration files
+in the `/etc/dovecot` directory.
+I want you to delete all of them. Yes, `rm -rf` that crap.
+Dovecot is simple to configure, and doesn't care where
+you put its settings, so having all that chaos in `/etc/dovecot`
+just makes things unnecessarily confusing.
+
+
+
+### Network
+
+Create a new configuration file `/etc/dovecot/dovecot.conf`,
+and start by filling in the details of your TLS certificate,
+making clear that unencrypted connections are unacceptable:
+```sh
+ssl = required
+ssl_cert = </etc/ssl/certs/example.com.pem
+ssl_key = </etc/ssl/private/example.com.key
+
+ssl_min_protocol = TLSv1.2
+ssl_prefer_server_ciphers = yes
+
+disable_plaintext_auth = yes
+```
+The final `disable_plaintext_auth` option tells Dovecot
+to reject any passwords that were sent unencrypted.
+This means it must be [hashed](https://en.wikipedia.org/wiki/Cryptographic_hash_function)
+or sent over an encrypted connection, or both.
+
+Next, tell Dovecot which protocols to use
+and where to expect them as follows:
+```sh
+protocols = lmtp imap
+
+service lmtp {
+ unix_listener lmtp {
+ user = vmail
+ group = vmail
+ }
+}
+
+service imap-login {
+ inet_listener imap {
+ port = 143
+ }
+ inet_listener imaps {
+ port = 993
+ }
+}
+```
+LMTP is the Local Mail Transport Protocol, which is basically SMTP
+but for exchanges within a single server or over a trusted network.
+When an email is received, Dovecot will start a child process
+under the `vmail` user/group to deliver the message to its recipient.
+
+Since we set `ssl = required` earlier, clients will only get their mail
+if the STARTTLS handshake was successful during the IMAP exchange,
+or if they connect via IMAPS to force the use of encryption.
+You can therefore optionally remove one of the two
+`inet_listener`s according to your preferences.
+
+
+
+### Users
+
+Next, we need to inform Dovecot which email addresses it should handle,
+and what to do with their messages. Create a file `/etc/dovecot/users` for this,
+which describes a user on each line in a similar format as `/etc/passwd`:
+```
+user:password:uid:gid::homedir
+```
+In this guide, we're using the `vmail` user for all accounts,
+so leave the `uid`, `gid`, and `homedir` fields blank.
+We'll be storing all emails in `vmail`'s home directory.
+The `user` field should be the email address excluding the `@example.com`
+(in fact, you *can* include it, but this guides assumes a small-scale
+server managing only one domain, so we exclude it).
+Create the password hash to put in the `password` field as follows:
+```sh
+# If your server is fast and has lots of RAM:
+$ doveadm pw -s ARGON2ID-CRYPT
+# If you're using a potato:
+$ doveadm pw -s SHA512-CRYPT
+```
+After you've entered your password, simply copy-paste the entire
+hash string outputted by the program into the `password` field.
+
+Now, Dovecot needs a file describing user accounts on two separate occasions:
+* To check whether a client logging into the IMAP server
+ is valid and has given the right password.
+ This is handled by the `passdb` block(s) in the configuration.
+* To know which email addresses the server is responsible for.
+ This is given by the `userdb` block(s) in the configuration.
+
+These functions aren't necessarily fulfilled by the same `users` file:
+you can map multiple email addresses to one acccount,
+or multiple accounts to one email address.
+For simplicity, though, we'll use the `users` file for both:
+```sh
+passdb {
+ driver = passwd-file
+ args = scheme=ARGON2ID-CRYPT username_format=%n /etc/dovecot/users
+ #args = scheme=SHA512-CRYPT username_format=%n /etc/dovecot/users
+}
+
+userdb {
+ driver = passwd-file
+ args = username_format=%n /etc/dovecot/users
+ override_fields = uid=vmail gid=vmail home=/home/vmail/%n
+}
+```
+The `driver` option sets the kind of table Dovecot should expect.
+We tell it to use a file in the `passwd`-like format described above,
+but other possibilities include e.g. an SQL database.
+The options available in `args` depend on the chosen `driver`.
+
+In the `passdb` block, the hashing algorithm is given by `scheme`,
+while `username_format=%n` says that the `users` file
+only contains `name` out of `name@example.com`.
+
+In the `userdb` block, we force the use of `vmail:vmail`
+for all accounts, and tell Dovecot to put their data in `/home/vmail/%n`,
+where `%n` means the address up until the `@`, so
+e.g. mail to `name@example.com` is stored in `/home/vmail/name`.
+
+Now that Dovecot knows where to store messages,
+we just need to specify in what format to store them:
+```sh
+mail_location = maildir:~/Maildir
+```
+The two standard mailbox formats to choose from are `maildir` and `mbox`.
+I highly recommend `maildir`; it's more modern than the ancient `mbox` format.
+That `~/Maildir` says which subfolder to use.
+Ensure that `/home/vmail` is owned by `vmail:vmail`,
+so that Dovecot has write access.
+
+
+
+## MTA: OpenSMTPD
+
+[OpenSMTPD](https://opensmtpd.org/) is an MTA by the [OpenBSD](https://www.openbsd.org/) project,
+who are known for their focus on security and minimalism.
+Compared to other MTAs it's a joy to set up, thanks to
+its intuitive configuration syntax and to-the-point manual.
+This guide is for OpenSMTPD version 6.4 or newer:
+older versions used a substantially different syntax.
+
+If you have any problems with OpenSMTPD,
+take a look at the maintainer's [blog](https://poolp.org/),
+which contains a lot of useful information,
+and was a big help when writing this guide.
+
+
+
+### Users
+
+To begin, delete the contents of the `/etc/smtpd/aliases` file,
+if it exists, which maps recipient addresses to system users.
+In our case, we're using `vmail` for everyone,
+and we'll let Dovecot manage the details by simply writing:
+```
+@ vmail
+```
+Then create a new file `/etc/smtpd/passwds`
+and fill it in according to the following format:
+```
+name@example.com <hash>
+```
+Generate the password hash with this command for each user.
+Be sure to use the same password for every account as in Dovecot:
+```sh
+$ smtpctl encrypt '<password>'
+```
+Then, like with Dovecot, just delete the contents of
+the main config file `/etc/smtpd/smtpd.conf`,
+and start by putting in the following:
+```sh
+table aliases "/etc/smtpd/aliases"
+table passwds "/etc/smtpd/passwds"
+```
+
+
+### Network
+
+Write your domain name on a single line in `/etc/smtpd/mailname`.
+This is the name that OpenSMTPD will use to introduce itself
+to other servers, and it's important that this matches
+the reverse DNS domain name of the server's IP:
+```sh
+example.com
+# Or mx1.example.com or whatever
+```
+Then continue in `/etc/smtpd/smtpd.conf` by importing your TLS certificate:
+```sh
+pki "prefet.ch" cert "/etc/ssl/certs/example.com.pem"
+pki "prefet.ch" key "/etc/ssl/private/example.com.key"
+```
+And tell OpenSMTPD which keys to use for the [Sender Rewriting Scheme](https://en.wikipedia.org/wiki/Sender_Rewriting_Scheme),
+which prevents forwarded emails from breaking SPF and looking like spam:
+```sh
+srs key "<secret1>"
+srs key backup "<secret2>" # optional, read below
+```
+It's recommended to change the key every year or so,
+but in that case you need to ensure that emails from the last month
+can still be verified using the old one, so if you change it,
+simply move it to the backup slot for a month.
+
+It's very important that the secrets can't be guessed,
+otherwise *anyone* can send mail through your server,
+so I recommend generating these keys randomly as follows:
+```sh
+$ head -c 30 /dev/urandom | base64
+```
+Next, define the spam filters as follows.
+For the last line to work, you'll need to [download](https://github.com/poolpOrg/filter-rspamd)
+and build the `filter-rspamd` adapter binary for yourself,
+created by OpenSMTPD's official maintainer.
+We'll set up the Rspamd service in the next section,
+which will be responsible for spam filtering and DKIM signing:
+```sh
+filter "rdns" phase connect match !rdns disconnect "550 DNS error"
+filter "fcrdns" phase connect match !fcrdns disconnect "550 DNS error"
+filter "rspamd" proc-exec "/etc/smtpd/filter-rspamd"
+```
+I cannot overstate the importance of the first two lines:
+these will block hundreds of spam attempts, and have,
+at least for me, never blocked anything legitimate so far.
+
+The only thing left to do here is to tell OpenSMTPD which ports to listen on
+and what to do with the incoming traffic.
+This comes in two parts: first, we listen on port 25 for incoming
+messages for your domain coming from other email servers:
+```sh
+# Inbound
+listen on eth0 port 25 tls pki "example.com" filter { "rdns", "fcrdns", "rspamd" }
+action "RECV" lmtp "/var/run/dovecot/lmtp" rcpt-to virtual <aliases>
+match from any for domain "example.com" action "RECV"
+```
+Line 1 says to listen on `port 25` of interface `eth0`,
+providing *optional* `tls` using the certificate for `example.com`,
+and passing everything through the three filters definer earlier.
+Making TLS mandatory is a **bad** idea here, because not all servers can use TLS.
+
+Line 2 defines an action called `RECV`,
+which relays an email to Dovecot's LMTP socket,
+with the `rcpt-to` and `virtual` making sure
+that Dovecot will actually accept the message.
+
+Line 3 then simply says that any incoming mail
+for your domain should have the action `RECV` applied to it,
+unless the spam filters rejected it.
+
+Secondly, we listen on port 465 (SMTPS)
+and/or port 587 (STARTTLS) for messages getting sent
+from your email client to the rest of the world,
+so we require user authentication:
+```sh
+# Outbound
+listen on eth0 port 465 smtps pki "example.com" auth <passwds> filter "rspamd"
+listen on eth0 port 587 tls-require pki "example.com" auth <passwds> filter "rspamd"
+action "SEND" relay srs
+match from any auth for any action "SEND"
+```
+The only difference between lines 1 and 2 is the port and the protocol.
+Both demand a mandatory TLS connection, and that users authenticate
+themselves according to the password file created earlier.
+The `filter` at the end is for DKIM signing of outgoing mail.
+
+Lines 3 and 4 are only triggered after successful `auth`entication,
+and, unsurprisingly, `relay` the email to its destination.
+The `srs` at the end enables using the SRS settings from earlier.
+
+OpenSMTPD is the only program in this setup that needs to handle
+untrusted connections, when other MTAs send you messages.
+Since, like most server software, it may have [vulnerabilities](https://opensmtpd.org/security.html),
+it is **very** important that you keep it as up-to-date as possible.
+
+
+
+## Spam filter: Rspamd
+
+[Rspamd](https://www.rspamd.com/) is a modern spam filtering solution,
+with many features that you could spend hours tweaking.
+In this guide, however, we'll keep it short,
+because we're only really interested in its ability add
+our server's DKIM signature to outgoing messages.
+
+Besides, according to my limited experience,
+for small-scale servers spam filtering isn't essential,
+as long as you tell OpenSMTPD to check reverse DNS as described above.
+However, there are some much more experienced people who disagree with me.
+
+Basically, for our purposes, don't touch any of Rspamd's default
+configuration except for creating/editing the file
+`/etc/rspamd/local.d/dkim_signing.conf` with the following contents,
+where `<selector>` is the DKIM selector you chose in the DNS record:
+```sh
+allow_username_mismatch = true;
+
+domain {
+ example.com {
+ path = "/path/to/dkim/private.key";
+ selector = "<selector>";
+ }
+}
+```
+Make sure that the DKIM `private.key` file is
+readable (and *only* readable) by `rspamd:rspamd`.
+Allowing username mismatches is necessary,
+because OpenSMTPD will only tell Rspamd about `username`
+while the DKIM signer actually expects `username@example.com`.
+
+And... that's it! Of course, don't forget to start all the necessary daemons.
+
+
+
+## Testing
+
+Everything is set up now, so it's time to test. Fingers crossed!
+
+As mentioned earlier, you can check the correctness
+of your DNS using the [MX Lookup](https://mxtoolbox.com/MXLookup.aspx) tool.
+You can use the same website to test OpenSMTPD
+with the [SMTP Diagnostics](https://mxtoolbox.com/diagnostic.aspx) tool.
+
+All decent email clients include an option to set the server for an email account.
+This guide excludes instructions for that,
+because it will vary a lot from client to client.
+If asked for your login type, choose plain/normal/unencrypted passwords.
+Don't worry, the client-server connection is TLS-encrypted,
+so nobody will be able to steal it.
+
+Next, to test sending and receiving messages,
+use the aptly-named [Is my email working?](http://ismyemailworking.com/) website.
+After that, specifically test that SPF, DKIM an DMARC
+are working correctly using the [DKIM validator](https://dkimvalidator.com/).
+If everything is good so far, congratulations!
+
+Now comes the big scary final test:
+sending an email to one of the "big guys", Google or Microsoft.
+Their spam filters are very strict, so if you get through, great!
+Because these companies probably use AI-powered account-aware filters,
+you should *not* put anything identifiable in the test email.
+For example, if your name is "John Smith",
+do *not* put "John" nor "Smith" in the message,
+and do *not* send it from an addres like `john.smith@example.com`.
+
+If something failed, then you have some investigating to do.
+Either one of the daemons is misconfigured, or there's a problem
+with your domain name and/or DNS records.
+Do some research, and you'll get there, don't give up.
+
+But if everything works, congratulations!
+You're now the proud administrator of a private email server.
+Have fun with it, and don't forget to update your
+TLS certificate and DKIM and SRS keys.
+
+PS: and please don't spam; you'll ruin it for everyone else.
+
diff --git a/content/blog/_index.md b/content/blog/_index.md
new file mode 100644
index 0000000..3d4ffc2
--- /dev/null
+++ b/content/blog/_index.md
@@ -0,0 +1,7 @@
+---
+title: "Blog"
+date: 2021-02-22T17:38:58+01:00
+draft: false
+---
+
+Just a bunch of random ramblings.
diff --git a/content/know/_index.md b/content/know/_index.md
new file mode 100644
index 0000000..41aeef6
--- /dev/null
+++ b/content/know/_index.md
@@ -0,0 +1,32 @@
+---
+title: "Knowledge base"
+date: 2021-02-22T19:57:05+01:00
+draft: false
+layout: "know"
+---
+
+
+# Knowledge base
+
+Welcome to my knowledge base!
+
+Over the years, I've learned a lot of physics, mathematics, and computing.
+These are vast, difficult subjects, and I've spent many hours of my life
+trying to make sense of obscure, poorly explained concepts.
+To help me remember what I learn, I write notes in LaTeX.
+
+This knowledge base is based on my notes, and
+is freely available to anyone who might need it.
+I hope it helps you in your studies or work.
+Currently there's isn't much here yet,
+but I have over 200 pages of LaTeX waiting to be converted.
+
+Keep in mind that I'm only human,
+so there are probably mistakes in my work.
+I take no responsibility for any injuries incurred as a consequence.
+If you're doing something important,
+you should check things yourself!
+
+The contents of this knowledge base are found here:
+* [List of concepts](/know/concept/)
+* [List of categories](/know/category/)
diff --git a/content/know/category/_index.md b/content/know/category/_index.md
new file mode 100644
index 0000000..b796457
--- /dev/null
+++ b/content/know/category/_index.md
@@ -0,0 +1,8 @@
+---
+title: "List of categories"
+date: 2021-02-22T20:38:58+01:00
+draft: false
+layout: "know-list"
+---
+
+This is an alphabetical list of the categories in this knowledge base.
diff --git a/content/know/category/mathematics.md b/content/know/category/mathematics.md
new file mode 100644
index 0000000..693252f
--- /dev/null
+++ b/content/know/category/mathematics.md
@@ -0,0 +1,9 @@
+---
+title: "Mathematics"
+firstLetter: "M"
+date: 2021-02-23T14:44:07+01:00
+draft: false
+layout: "category"
+---
+
+This page will fill itself.
diff --git a/content/know/category/physics.md b/content/know/category/physics.md
new file mode 100644
index 0000000..7b0eaed
--- /dev/null
+++ b/content/know/category/physics.md
@@ -0,0 +1,9 @@
+---
+title: "Physics"
+firstLetter: "P"
+date: 2021-02-23T14:44:11+01:00
+draft: false
+layout: "category"
+---
+
+This page will fill itself.
diff --git a/content/know/category/quantum-mechanics.md b/content/know/category/quantum-mechanics.md
new file mode 100644
index 0000000..bc36a6f
--- /dev/null
+++ b/content/know/category/quantum-mechanics.md
@@ -0,0 +1,9 @@
+---
+title: "Quantum mechanics"
+firstLetter: "Q"
+date: 2021-02-23T14:38:56+01:00
+draft: false
+layout: "category"
+---
+
+This page will fill itself.
diff --git a/content/know/concept/_index.md b/content/know/concept/_index.md
new file mode 100644
index 0000000..956724a
--- /dev/null
+++ b/content/know/concept/_index.md
@@ -0,0 +1,8 @@
+---
+title: "List of concepts"
+date: 2021-02-22T20:38:58+01:00
+draft: false
+layout: "know-list"
+---
+
+This is an alphabetical list of the concepts in this knowledge base.
diff --git a/content/know/concept/blochs-theorem/index.pdc b/content/know/concept/blochs-theorem/index.pdc
new file mode 100644
index 0000000..1828d8a
--- /dev/null
+++ b/content/know/concept/blochs-theorem/index.pdc
@@ -0,0 +1,115 @@
+---
+title: "Bloch's theorem"
+firstLetter: "B"
+publishDate: 2021-02-22
+categories:
+- Quantum mechanics
+
+date: 2021-02-22T20:02:14+01:00
+draft: false
+markup: pandoc
+---
+
+# Bloch's theorem
+In quantum mechanics, **Bloch's theorem** states that,
+given a potential $V(\vec{r})$ which is periodic on a lattice,
+i.e. $V(\vec{r}) = V(\vec{r} + \vec{a})$
+for a primitive lattice vector $\vec{a}$,
+then it follows that the solutions $\psi(\vec{r})$
+to the time-independent Schrödinger equation
+take the following form,
+where the function $u(\vec{r})$ is periodic on the same lattice,
+i.e. $u(\vec{r}) = u(\vec{r} + \vec{a})$:
+
+$$
+\begin{aligned}
+ \boxed{
+ \psi(\vec{r}) = u(\vec{r}) e^{i \vec{k} \cdot \vec{r}}
+ }
+\end{aligned}
+$$
+
+In other words, in a periodic potential,
+the solutions are simply plane waves with a periodic modulation,
+known as **Bloch functions** or **Bloch states**.
+
+This is suprisingly easy to prove:
+if the Hamiltonian $\hat{H}$ is lattice-periodic,
+then both $\psi(\vec{r})$ and $\psi(\vec{r} + \vec{a})$
+are eigenstates with the same energy:
+
+$$
+\begin{aligned}
+ \hat{H} \psi(\vec{r}) = E \psi(\vec{r})
+ \qquad
+ \hat{H} \psi(\vec{r} + \vec{a}) = E \psi(\vec{r} + \vec{a})
+\end{aligned}
+$$
+
+Now define the unitary translation operator $\hat{T}(\vec{a})$ such that
+$\psi(\vec{r} + \vec{a}) = \hat{T}(\vec{a}) \psi(\vec{r})$.
+From the previous equation, we then know that:
+
+$$
+\begin{aligned}
+ \hat{H} \hat{T}(\vec{a}) \psi(\vec{r})
+ = E \hat{T}(\vec{a}) \psi(\vec{r})
+ = \hat{T}(\vec{a}) \big(E \psi(\vec{r})\big)
+ = \hat{T}(\vec{a}) \hat{H} \psi(\vec{r})
+\end{aligned}
+$$
+
+In other words, if $\hat{H}$ is lattice-periodic,
+then it will commute with $\hat{T}(\vec{a})$,
+i.e. $[\hat{H}, \hat{T}(\vec{a})] = 0$.
+Consequently, $\hat{H}$ and $\hat{T}(\vec{a})$ must share eigenstates $\psi(\vec{r})$:
+
+$$
+\begin{aligned}
+ \hat{H} \:\psi(\vec{r}) = E \:\psi(\vec{r})
+ \qquad
+ \hat{T}(\vec{a}) \:\psi(\vec{r}) = \tau \:\psi(\vec{r})
+\end{aligned}
+$$
+
+Since $\hat{T}$ is unitary,
+its eigenvalues $\tau$ must have the form $e^{i \theta}$, with $\theta$ real.
+Therefore a translation by $\vec{a}$ causes a phase shift,
+for some vector $\vec{k}$:
+
+$$
+\begin{aligned}
+ \psi(\vec{r} + \vec{a})
+ = \hat{T}(\vec{a}) \:\psi(\vec{r})
+ = e^{i \theta} \:\psi(\vec{r})
+ = e^{i \vec{k} \cdot \vec{a}} \:\psi(\vec{r})
+\end{aligned}
+$$
+
+Let us now define the following function,
+keeping our arbitrary choice of $\vec{k}$:
+
+$$
+\begin{aligned}
+ u(\vec{r})
+ = e^{- i \vec{k} \cdot \vec{r}} \:\psi(\vec{r})
+\end{aligned}
+$$
+
+As it turns out, this function is guaranteed to be lattice-periodic for any $\vec{k}$:
+
+$$
+\begin{aligned}
+ u(\vec{r} + \vec{a})
+ &= e^{- i \vec{k} \cdot (\vec{r} + \vec{a})} \:\psi(\vec{r} + \vec{a})
+ \\
+ &= e^{- i \vec{k} \cdot \vec{r}} e^{- i \vec{k} \cdot \vec{a}} e^{i \vec{k} \cdot \vec{a}} \:\psi(\vec{r})
+ \\
+ &= e^{- i \vec{k} \cdot \vec{r}} \:\psi(\vec{r})
+ \\
+ &= u(\vec{r})
+\end{aligned}
+$$
+
+Then Bloch's theorem follows from
+isolating the definition of $u(\vec{r})$ for $\psi(\vec{r})$.
diff --git a/content/know/concept/convolution-theorem/index.pdc b/content/know/concept/convolution-theorem/index.pdc
new file mode 100644
index 0000000..fc96f30
--- /dev/null
+++ b/content/know/concept/convolution-theorem/index.pdc
@@ -0,0 +1,100 @@
+---
+title: "Convolution theorem"
+firstLetter: "C"
+publishDate: 2021-02-22
+categories:
+- Mathematics
+
+date: 2021-02-22T21:35:23+01:00
+draft: false
+markup: pandoc
+---
+
+# Convolution theorem
+
+The **convolution theorem** states that a convolution in the direct domain
+is equal to a product in the frequency domain. This is especially useful
+for computation, replacing an $\mathcal{O}(n^2)$ convolution with an
+$\mathcal{O}(n \log(n))$ transform and product.
+
+## Fourier transform
+
+The convolution theorem is usually expressed as follows, where
+$\hat{\mathcal{F}}$ is the [Fourier transform](/know/concept/fourier-transform/),
+and $A$ and $B$ are constants from its definition:
+
+$$\begin{aligned}
+ \boxed{
+ \begin{aligned}
+ A \cdot (f * g)(x) &= \hat{\mathcal{F}}^{-1}\{\tilde{f}(k) \: \tilde{g}(k)\} \\
+ B \cdot (\tilde{f} * \tilde{g})(k) &= \hat{\mathcal{F}}\{f(x) \: g(x)\}
+ \end{aligned}
+ }
+\end{aligned}$$
+
+To prove this, we expand the right-hand side of the theorem and
+rearrange the integrals:
+
+$$\begin{aligned}
+ \hat{\mathcal{F}}^{-1}\{\tilde{f}(k) \: \tilde{g}(k)\}
+ &= B \int_{-\infty}^\infty \tilde{f}(k) \Big( A \int_{-\infty}^\infty g(x') \exp(i s k x') \dd{x'} \Big) \exp(-i s k x) \dd{k}
+ \\
+ &= A \int_{-\infty}^\infty g(x') \Big( B \int_{-\infty}^\infty \tilde{f}(k) \exp(- i s k (x - x')) \dd{k} \Big) \dd{x'}
+ \\
+ &= A \int_{-\infty}^\infty g(x') f(x - x') \dd{x'}
+ = A \cdot (f * g)(x)
+\end{aligned}$$
+
+Then we do the same thing again, this time starting from a product in
+the $x$-domain:
+
+$$\begin{aligned}
+ \hat{\mathcal{F}}\{f(x) \: g(x)\}
+ &= A \int_{-\infty}^\infty f(x) \Big( B \int_{-\infty}^\infty \tilde{g}(k') \exp(- i s x k') \dd{k'} \Big) \exp(i s k x) \dd{x}
+ \\
+ &= B \int_{-\infty}^\infty \tilde{g}(k') \Big( A \int_{-\infty}^\infty f(x) \exp(i s x (k - k')) \dd{x} \Big) \dd{k'}
+ \\
+ &= B \int_{-\infty}^\infty \tilde{g}(k') \tilde{f}(k - k') \dd{k'}
+ = B \cdot (\tilde{f} * \tilde{g})(k)
+\end{aligned}$$
+
+
+## Laplace transform
+
+For functions $f(t)$ and $g(t)$ which are only defined for $t \ge 0$,
+the convolution theorem can also be stated using the Laplace transform:
+
+$$\begin{aligned}
+ \boxed{(f * g)(t) = \hat{\mathcal{L}}^{-1}\{\tilde{f}(s) \: \tilde{g}(s)\}}
+\end{aligned}$$
+
+Because the inverse Laplace transform $\hat{\mathcal{L}}^{-1}$ is quite
+unpleasant, the theorem is often stated using the forward transform
+instead:
+
+$$\begin{aligned}
+ \boxed{\hat{\mathcal{L}}\{(f * g)(t)\} = \tilde{f}(s) \: \tilde{g}(s)}
+\end{aligned}$$
+
+We prove this by expanding the left-hand side. Note that the lower
+integration limit is 0 instead of $-\infty$, because we set both $f(t)$
+and $g(t)$ to zero for $t < 0$:
+
+$$\begin{aligned}
+ \hat{\mathcal{L}}\{(f * g)(t)\}
+ &= \int_0^\infty \Big( \int_0^\infty g(t') f(t - t') \dd{t'} \Big) \exp(- s t) \dd{t}
+ \\
+ &= \int_0^\infty \Big( \int_0^\infty f(t - t') \exp(- s t) \dd{t} \Big) g(t') \dd{t'}
+\end{aligned}$$
+
+Then we define a new integration variable $\tau = t - t'$, yielding:
+
+$$\begin{aligned}
+ \hat{\mathcal{L}}\{(f * g)(t)\}
+ &= \int_0^\infty \Big( \int_0^\infty f(\tau) \exp(- s (\tau + t')) \dd{\tau} \Big) g(t') \dd{t'}
+ \\
+ &= \int_0^\infty \Big( \int_0^\infty f(\tau) \exp(- s \tau) \dd{\tau} \Big) g(t') \exp(- s t') \dd{t'}
+ \\
+ &= \int_0^\infty \tilde{f}(s) g(t') \exp(- s t') \dd{t'}
+ = \tilde{f}(s) \: \tilde{g}(s)
+\end{aligned}$$
diff --git a/content/know/concept/dirac-delta-function/index.pdc b/content/know/concept/dirac-delta-function/index.pdc
new file mode 100644
index 0000000..3982afc
--- /dev/null
+++ b/content/know/concept/dirac-delta-function/index.pdc
@@ -0,0 +1,109 @@
+---
+title: "Dirac delta function"
+firstLetter: "D"
+publishDate: 2021-02-22
+categories:
+- Mathematics
+- Physics
+
+date: 2021-02-22T21:35:38+01:00
+draft: false
+markup: pandoc
+---
+
+# Dirac delta function
+
+The **Dirac delta function** $\delta(x)$, often just called the **delta function**,
+is an infinitely narrow discontinuous "spike" at $x = 0$ whose area is
+defined to be 1:
+
+$$\begin{aligned}
+ \boxed{
+ \delta(x) =
+ \begin{cases}
+ +\infty & \mathrm{if}\: x = 0 \\
+ 0 & \mathrm{if}\: x \neq 0
+ \end{cases}
+ \quad \mathrm{and} \quad
+ \int_{-\varepsilon}^\varepsilon \delta(x) \dd{x} = 1
+ }
+\end{aligned}$$
+
+It is sometimes also called the **sampling function**, due to its most
+important property: the so-called **sampling property**:
+
+$$\begin{aligned}
+ \boxed{
+ \int f(x) \: \delta(x - x_0) \: dx = \int f(x) \: \delta(x_0 - x) \: dx = f(x_0)
+ }
+\end{aligned}$$
+
+$\delta(x)$ is thus an effective weapon against integrals. This may not seem very
+useful due to its "unnatural" definition, but in fact it appears as the
+limit of several reasonable functions:
+
+$$\begin{aligned}
+ \delta(x)
+ = \lim_{n \to +\infty} \!\Big\{ \frac{n}{\sqrt{\pi}} \exp(- n^2 x^2) \Big\}
+ = \lim_{n \to +\infty} \!\Big\{ \frac{n}{\pi} \frac{1}{1 + n^2 x^2} \Big\}
+ = \lim_{n \to +\infty} \!\Big\{ \frac{\sin(n x)}{\pi x} \Big\}
+\end{aligned}$$
+
+The last one is especially important, since it is equivalent to the
+following integral, which appears very often in the context of
+[Fourier transforms](/know/concept/fourier-transform/):
+
+$$\begin{aligned}
+ \boxed{
+ \delta(x)
+ %= \lim_{n \to +\infty} \!\Big\{\frac{\sin(n x)}{\pi x}\Big\}
+ = \frac{1}{2\pi} \int_{-\infty}^\infty \exp(i k x) \dd{k}
+ \:\:\propto\:\: \hat{\mathcal{F}}\{1\}
+ }
+\end{aligned}$$
+
+When the argument of $\delta(x)$ is scaled, the delta function is itself scaled:
+
+$$\begin{aligned}
+ \boxed{
+ \delta(s x) = \frac{1}{|s|} \delta(x)
+ }
+\end{aligned}$$
+
+*__Proof.__ Because it is symmetric, $\delta(s x) = \delta(|s| x)$. Then by
+substituting $\sigma = |s| x$:*
+
+$$\begin{aligned}
+ \int \delta(|s| x) \dd{x}
+ &= \frac{1}{|s|} \int \delta(\sigma) \dd{\sigma} = \frac{1}{|s|}
+\end{aligned}$$
+
+*__Q.E.D.__*
+
+An even more impressive property is the behaviour of the derivative of
+$\delta(x)$:
+
+$$\begin{aligned}
+ \boxed{
+ \int f(\xi) \: \delta'(x - \xi) \dd{\xi} = f'(x)
+ }
+\end{aligned}$$
+
+*__Proof.__ Note which variable is used for the
+differentiation, and that $\delta'(x - \xi) = - \delta'(\xi - x)$:*
+
+$$\begin{aligned}
+ \int f(\xi) \: \dv{\delta(x - \xi)}{x} \dd{\xi}
+ &= \dv{x} \int f(\xi) \: \delta(x - \xi) \dd{x}
+ = f'(x)
+\end{aligned}$$
+
+*__Q.E.D.__*
+
+This property also generalizes nicely for the higher-order derivatives:
+
+$$\begin{aligned}
+ \boxed{
+ \int f(\xi) \: \dv[n]{\delta(x - \xi)}{x} \dd{\xi} = \dv[n]{f(x)}{x}
+ }
+\end{aligned}$$
diff --git a/content/know/concept/dirac-notation/index.pdc b/content/know/concept/dirac-notation/index.pdc
new file mode 100644
index 0000000..f624574
--- /dev/null
+++ b/content/know/concept/dirac-notation/index.pdc
@@ -0,0 +1,129 @@
+---
+title: "Dirac notation"
+firstLetter: "D"
+publishDate: 2021-02-22
+categories:
+- Quantum mechanics
+- Physics
+
+date: 2021-02-22T21:35:46+01:00
+draft: false
+markup: pandoc
+---
+
+# Dirac notation
+
+**Dirac notation** is a notation to do calculations in a Hilbert space
+without needing to worry about the space's representation. It is
+basically the *lingua franca* of quantum mechanics.
+
+In Dirac notation there are **kets** $\ket{V}$ from the Hilbert space
+$\mathbb{H}$ and **bras** $\bra{V}$ from a dual $\mathbb{H}'$ of the
+former. Crucially, the bras and kets are from different Hilbert spaces
+and therefore cannot be added, but every bra has a corresponding ket and
+vice versa.
+
+Bras and kets can be combined in two ways: the **inner product**
+$\braket{V}{W}$, which returns a scalar, and the **outer product**
+$\ket{V} \bra{W}$, which returns a mapping $\hat{L}$ from kets $\ket{V}$
+to other kets $\ket{V'}$, i.e. a linear operator. Recall that the
+Hilbert inner product must satisfy:
+
+$$\begin{aligned}
+ \braket{V}{W} = \braket{W}{V}^*
+\end{aligned}$$
+
+So far, nothing has been said about the actual representation of bras or
+kets. If we represent kets as $N$-dimensional columns vectors, the
+corresponding bras are given by the kets' adjoints, i.e. their transpose
+conjugates:
+
+$$\begin{aligned}
+ \ket{V} =
+ \begin{bmatrix}
+ v_1 \\ \vdots \\ v_N
+ \end{bmatrix}
+ \quad \implies \quad
+ \bra{V} =
+ \begin{bmatrix}
+ v_1^* & \cdots & v_N^*
+ \end{bmatrix}
+\end{aligned}$$
+
+The inner product $\braket{V}{W}$ is then just the familiar dot product $V \cdot W$:
+
+$$\begin{gathered}
+ \braket{V}{W}
+ =
+ \begin{bmatrix}
+ v_1^* & \cdots & v_N^*
+ \end{bmatrix}
+ \cdot
+ \begin{bmatrix}
+ w_1 \\ \vdots \\ w_N
+ \end{bmatrix}
+ = v_1^* w_1 + ... + v_N^* w_N
+\end{gathered}$$
+
+Meanwhile, the outer product $\ket{V} \bra{W}$ creates an $N \cross N$ matrix:
+
+$$\begin{gathered}
+ \ket{V} \bra{W}
+ =
+ \begin{bmatrix}
+ v_1 \\ \vdots \\ v_N
+ \end{bmatrix}
+ \cdot
+ \begin{bmatrix}
+ w_1^* & \cdots & w_N^*
+ \end{bmatrix}
+ =
+ \begin{bmatrix}
+ v_1 w_1^* & \cdots & v_1 w_N^* \\
+ \vdots & \ddots & \vdots \\
+ v_N w_1^* & \cdots & v_N w_N^*
+ \end{bmatrix}
+\end{gathered}$$
+
+If the kets are instead represented by functions $f(x)$ of
+$x \in [a, b]$, then the bras represent *functionals* $F[u(x)]$ which
+take an unknown function $u(x)$ as an argument and turn it into a scalar
+using integration:
+
+$$\begin{aligned}
+ \ket{f} = f(x)
+ \quad \implies \quad
+ \bra{f}
+ = F[u(x)]
+ = \int_a^b f^*(x) \: u(x) \dd{x}
+\end{aligned}$$
+
+Consequently, the inner product is simply the following familiar integral:
+
+$$\begin{gathered}
+ \braket{f}{g}
+ = F[g(x)]
+ = \int_a^b f^*(x) \: g(x) \dd{x}
+\end{gathered}$$
+
+However, the outer product becomes something rather abstract:
+
+$$\begin{gathered}
+ \ket{f} \bra{g}
+ = f(x) \: G[u(x)]
+ = f(x) \int_a^b g^*(\xi) \: u(\xi) \dd{\xi}
+\end{gathered}$$
+
+This result makes more sense if we surround it by a bra and a ket:
+
+$$\begin{aligned}
+ \bra{u} \!\Big(\!\ket{f} \bra{g}\!\Big)\! \ket{w}
+ &= U\big[f(x) \: G[w(x)]\big]
+ = U\Big[ f(x) \int_a^b g^*(\xi) \: w(\xi) \dd{\xi} \Big]
+ \\
+ &= \int_a^b u^*(x) \: f(x) \: \Big(\int_a^b g^*(\xi) \: w(\xi) \dd{\xi} \Big) \dd{x}
+ \\
+ &= \Big( \int_a^b u^*(x) \: f(x) \dd{x} \Big) \Big( \int_a^b g^*(\xi) \: w(\xi) \dd{\xi} \Big)
+ \\
+ &= \braket{u}{f} \braket{g}{w}
+\end{aligned}$$
diff --git a/content/know/concept/fourier-transform/index.pdc b/content/know/concept/fourier-transform/index.pdc
new file mode 100644
index 0000000..6d8901a
--- /dev/null
+++ b/content/know/concept/fourier-transform/index.pdc
@@ -0,0 +1,117 @@
+---
+title: "Fourier transform"
+firstLetter: "F"
+publishDate: 2021-02-22
+categories:
+- Mathematics
+- Physics
+
+date: 2021-02-22T21:35:54+01:00
+draft: false
+markup: pandoc
+---
+
+# Fourier transform
+
+The **Fourier transform** (FT) is an integral transform which converts a
+function $f(x)$ into its frequency representation $\tilde{f}(k)$.
+Great volumes have already been written about this subject,
+so let us focus on the aspects that are useful to physicists.
+
+The **forward** FT is defined as follows, where $A$, $B$, and $s$ are unspecified constants
+(for now):
+
+$$\begin{aligned}
+ \boxed{
+ \tilde{f}(k)
+ = \hat{\mathcal{F}}\{f(x)\}
+ = A \int_{-\infty}^\infty f(x) \exp(i s k x) \dd{x}
+ }
+\end{aligned}$$
+
+The **inverse Fourier transform** (iFT) undoes the forward FT operation:
+
+$$\begin{aligned}
+ \boxed{
+ f(x)
+ = \hat{\mathcal{F}}^{-1}\{\tilde{f}(k)\}
+ = B \int_{-\infty}^\infty \tilde{f}(k) \exp(- i s k x) \dd{k}
+ }
+\end{aligned}$$
+
+Clearly, the inverse FT of the forward FT of $f(x)$ must equal $f(x)$
+again. Let us verify this, by rearranging the integrals to get the
+[Dirac delta function](/know/concept/dirac-delta-function/) $\delta(x)$:
+
+$$\begin{aligned}
+ \hat{\mathcal{F}}^{-1}\{\hat{\mathcal{F}}\{f(x)\}\}
+ &= A B \int_{-\infty}^\infty \exp(-i s k x) \int_{-\infty}^\infty f(x') \exp(i s k x') \dd{x'} \dd{k}
+ \\
+ &= 2 \pi A B \int_{-\infty}^\infty f(x') \Big(\frac{1}{2\pi} \int_{-\infty}^\infty \exp(i s k (x' - x)) \dd{k} \Big) \dd{x'}
+ \\
+ &= 2 \pi A B \int_{-\infty}^\infty f(x') \: \delta(s(x' - x)) \dd{x'}
+ = \frac{2 \pi A B}{|s|} f(x)
+\end{aligned}$$
+
+Therefore, the constants $A$, $B$, and $s$ are subject to the following
+constraint:
+
+$$\begin{aligned}
+ \boxed{\frac{2\pi A B}{|s|} = 1}
+\end{aligned}$$
+
+But that still gives a lot of freedom. The exact choices of $A$ and $B$
+are generally motivated by the [convolution theorem](/know/concept/convolution-theorem/)
+and [Parseval's theorem](/know/concept/parsevals-theorem/).
+
+The choice of $|s|$ depends on whether the frequency variable $k$
+represents the angular ($|s| = 1$) or the physical ($|s| = 2\pi$)
+frequency. The sign of $s$ is not so important, but is generally based
+on whether the analysis is for forward ($s > 0$) or backward-propagating
+($s < 0$) waves.
+
+
+## Derivatives
+
+The FT of a derivative has a very interesting property.
+Below, after integrating by parts, we remove the boundary term by
+assuming that $f(x)$ is localized, i.e. $f(x) \to 0$ for $x \to \pm \infty$:
+
+$$\begin{aligned}
+ \hat{\mathcal{F}}\{f'(x)\}
+ &= A \int_{-\infty}^\infty f'(x) \exp(i s k x) \dd{x}
+ \\
+ &= A \big[ f(x) \exp(i s k x) \big]_{-\infty}^\infty - i s k A \int_{-\infty}^\infty f(x) \exp(i s k x) \dd{x}
+ \\
+ &= (- i s k) \tilde{f}(k)
+\end{aligned}$$
+
+Therefore, as long as $f(x)$ is localized, the FT eliminates derivatives
+of the transformed variable, which makes it useful against PDEs:
+
+$$\begin{aligned}
+ \boxed{
+ \hat{\mathcal{F}}\{f'(x)\} = (- i s k) \tilde{f}(k)
+ }
+\end{aligned}$$
+
+This generalizes to higher-order derivatives, as long as these
+derivatives are also localized in the $x$-domain, which is practically
+guaranteed if $f(x)$ itself is localized:
+
+$$\begin{aligned}
+ \boxed{
+ \hat{\mathcal{F}} \Big\{ \dv[n]{f}{x} \Big\}
+ = (- i s k)^n \tilde{f}(k)
+ }
+\end{aligned}$$
+
+Derivatives in the frequency domain have an analogous property:
+
+$$\begin{aligned}
+ \boxed{
+ \dv[n]{\tilde{f}}{k}
+ = A \int_{-\infty}^\infty (i s x)^n f(x) \exp(i s k x) \dd{x}
+ = \hat{\mathcal{F}}\{ (i s x)^n f(x) \}
+ }
+\end{aligned}$$
diff --git a/content/know/concept/gram-schmidt-method/index.pdc b/content/know/concept/gram-schmidt-method/index.pdc
new file mode 100644
index 0000000..88488dd
--- /dev/null
+++ b/content/know/concept/gram-schmidt-method/index.pdc
@@ -0,0 +1,47 @@
+---
+title: "Gram-Schmidt method"
+firstLetter: "G"
+publishDate: 2021-02-22
+categories:
+- Mathematics
+
+date: 2021-02-22T21:36:08+01:00
+draft: false
+markup: pandoc
+---
+
+# Gram-Schmidt method
+
+Given a set of linearly independent non-orthonormal vectors
+$\ket*{V_1}, \ket*{V_2}, ...$ from a [Hilbert space](/know/concept/hilbert-space/),
+the **Gram-Schmidt method**
+turns them into an orthonormal set $\ket*{n_1}, \ket*{n_2}, ...$ as follows:
+
+1. Take the first vector $\ket*{V_1}$ and normalize it to get $\ket*{n_1}$:
+
+ $$\begin{aligned}
+ \ket*{n_1} = \frac{\ket*{V_1}}{\sqrt{\braket*{V_1}{V_1}}}
+ \end{aligned}$$
+
+2. Begin loop. Take the next non-orthonormal vector $\ket*{V_j}$, and
+ subtract from it its projection onto every already-processed vector:
+
+ $$\begin{aligned}
+ \ket*{n_j'} = \ket*{V_j} - \ket*{n_1} \braket*{n_1}{V_j} - \ket*{n_2} \braket*{n_2}{V_j} - ... - \ket*{n_{j-1}} \braket*{n_{j-1}}{V_{j-1}}
+ \end{aligned}$$
+
+ This leaves only the part of $\ket*{V_j}$ which is orthogonal to
+ $\ket*{n_1}$, $\ket*{n_2}$, etc. This why the input vectors must be
+ linearly independent; otherwise $\ket{n_j'}$ may become zero at some
+ point.
+
+3. Normalize the resulting ortho*gonal* vector $\ket*{n_j'}$ to make it
+ ortho*normal*:
+
+ $$\begin{aligned}
+ \ket*{n_j} = \frac{\ket*{n_j'}}{\sqrt{\braket*{n_j'}{n_j'}}}
+ \end{aligned}$$
+
+4. Loop back to step 2, taking the next vector $\ket*{V_{j+1}}$.
+
+If you are unfamiliar with this notation, take a look at [Dirac notation](/know/concept/dirac-notation/).
diff --git a/content/know/concept/hilbert-space/index.pdc b/content/know/concept/hilbert-space/index.pdc
new file mode 100644
index 0000000..1faf08a
--- /dev/null
+++ b/content/know/concept/hilbert-space/index.pdc
@@ -0,0 +1,202 @@
+---
+title: "Hilbert space"
+firstLetter: "H"
+publishDate: 2021-02-22
+categories:
+- Mathematics
+- Quantum mechanics
+
+date: 2021-02-22T21:36:24+01:00
+draft: false
+markup: pandoc
+---
+
+# Hilbert space
+
+A **Hilbert space**, also known as an **inner product space**, is an
+abstract **vector space** with a notion of length and angle.
+
+
+## Vector space
+
+An abstract **vector space** $\mathbb{V}$ is a generalization of the
+traditional concept of vectors as "arrows". It consists of a set of
+objects called **vectors** which support the following (familiar)
+operations:
+
++ **Vector addition**: the sum of two vectors $V$ and $W$, denoted $V + W$.
++ **Scalar multiplication**: product of a vector $V$ with a scalar $a$, denoted $a V$.
+
+In addition, for a given $\mathbb{V}$ to qualify as a proper vector
+space, these operations must obey the following axioms:
+
++ **Addition is associative**: $U + (V + W) = (U + V) + W$
++ **Addition is commutative**: $U + V = V + U$
++ **Addition has an identity**: there exists a $\mathbf{0}$ such that $V + 0 = V$
++ **Addition has an inverse**: for every $V$ there exists $-V$ so that $V + (-V) = 0$
++ **Multiplication is associative**: $a (b V) = (a b) V$
++ **Multiplication has an identity**: There exists a $1$ such that $1 V = V$
++ **Multiplication is distributive over scalars**: $(a + b)V = aV + bV$
++ **Multiplication is distributive over vectors**: $a (U + V) = a U + a V$
+
+A set of $N$ vectors $V_1, V_2, ..., V_N$ is **linearly independent** if
+the only way to satisfy the following relation is to set all the scalar coefficients $a_n = 0$:
+
+$$\begin{aligned}
+ \mathbf{0} = \sum_{n = 1}^N a_n V_n
+\end{aligned}$$
+
+In other words, these vectors cannot be expressed in terms of each
+other. Otherwise, they would be **linearly dependent**.
+
+A vector space $\mathbb{V}$ has **dimension** $N$ if only up to $N$ of
+its vectors can be linearly indepedent. All other vectors in
+$\mathbb{V}$ can then be written as a **linear combination** of these $N$ **basis vectors**.
+
+Let $\vu{e}_1, ..., \vu{e}_N$ be the basis vectors, then any
+vector $V$ in the same space can be **expanded** in the basis according to
+the unique weights $v_n$, known as the **components** of $V$
+in that basis:
+
+$$\begin{aligned}
+ V = \sum_{n = 1}^N v_n \vu{e}_n
+\end{aligned}$$
+
+Using these, the vector space operations can then be implemented as follows:
+
+$$\begin{gathered}
+ V = \sum_{n = 1} v_n \vu{e}_n
+ \quad
+ W = \sum_{n = 1} w_n \vu{e}_n
+ \\
+ \quad \implies \quad
+ V + W = \sum_{n = 1}^N (v_n + w_n) \vu{e}_n
+ \qquad
+ a V = \sum_{n = 1}^N a v_n \vu{e}_n
+\end{gathered}$$
+
+
+## Inner product
+
+A given vector space $\mathbb{V}$ can be promoted to a **Hilbert space**
+or **inner product space** if it supports an operation $\braket{U}{V}$
+called the **inner product**, which takes two vectors and returns a
+scalar, and has the following properties:
+
++ **Skew symmetry**: $\braket{U}{V} = (\braket{V}{U})^*$, where ${}^*$ is the complex conjugate.
++ **Positive semidefiniteness**: $\braket{V}{V} \ge 0$, and $\braket{V}{V} = 0$ if $V = \mathbf{0}$.
++ **Linearity in second operand**: $\braket{U}{(a V + b W)} = a \braket{U}{V} + b \braket{U}{W}$.
+
+The inner product describes the lengths and angles of vectors, and in
+Euclidean space it is implemented by the dot product.
+
+The **magnitude** or **norm** $|V|$ of a vector $V$ is given by
+$|V| = \sqrt{\braket{V}{V}}$ and represents the real positive length of $V$.
+A **unit vector** has a norm of 1.
+
+Two vectors $U$ and $V$ are **orthogonal** if their inner product
+$\braket{U}{V} = 0$. If in addition to being orthogonal, $|U| = 1$ and
+$|V| = 1$, then $U$ and $V$ are known as **orthonormal** vectors.
+
+Orthonormality is desirable for basis vectors, so if they are
+not already like that, it is common to manually turn them into a new
+orthonormal basis using e.g. the [Gram-Schmidt method](/know/concept/gram-schmidt-method).
+
+As for the implementation of the inner product, it is given by:
+
+$$\begin{gathered}
+ V = \sum_{n = 1}^N v_n \vu{e}_n
+ \quad
+ W = \sum_{n = 1}^N w_n \vu{e}_n
+ \\
+ \quad \implies \quad
+ \braket{V}{W} = \sum_{n = 1}^N \sum_{m = 1}^N v_n^* w_m \braket{\vu{e}_n}{\vu{e}_j}
+\end{gathered}$$
+
+If the basis vectors $\vu{e}_1, ..., \vu{e}_N$ are already
+orthonormal, this reduces to:
+
+$$\begin{aligned}
+ \braket{V}{W} = \sum_{n = 1}^N v_n^* w_n
+\end{aligned}$$
+
+As it turns out, the components $v_n$ are given by the inner product
+with $\vu{e}_n$, where $\delta_{nm}$ is the Kronecker delta:
+
+$$\begin{aligned}
+ \braket{\vu{e}_n}{V} = \sum_{m = 1}^N \delta_{nm} v_m = v_n
+\end{aligned}$$
+
+
+## Infinite dimensions
+
+As the dimensionality $N$ tends to infinity, things may or may not
+change significantly, depending on whether $N$ is **countably** or
+**uncountably** infinite.
+
+In the former case, not much changes: the infinitely many **discrete**
+basis vectors $\vu{e}_n$ can all still be made orthonormal as usual,
+and as before:
+
+$$\begin{aligned}
+ V = \sum_{n = 1}^\infty v_n \vu{e}_n
+\end{aligned}$$
+
+A good example of such a countably-infinitely-dimensional basis are the
+solution eigenfunctions of a [Sturm-Liouville problem](/know/concept/sturm-liouville-theory/).
+
+However, if the dimensionality is uncountably infinite, the basis
+vectors are **continuous** and cannot be labeled by $n$. For example, all
+complex functions $f(x)$ defined for $x \in [a, b]$ which
+satisfy $f(a) = f(b) = 0$ form such a vector space.
+In this case $f(x)$ is expanded as follows, where $x$ is a basis vector:
+
+$$\begin{aligned}
+ f(x) = \int_a^b \braket{x}{f} \dd{x}
+\end{aligned}$$
+
+Similarly, the inner product $\braket{f}{g}$ must also be redefined as
+follows:
+
+$$\begin{aligned}
+ \braket{f}{g} = \int_a^b f^*(x) \: g(x) \dd{x}
+\end{aligned}$$
+
+The concept of orthonormality must be also weakened. A finite function
+$f(x)$ can be normalized as usual, but the basis vectors $x$ themselves
+cannot, since each represents an infinitesimal section of the real line.
+
+The rationale in this case is that action of the identity operator $\hat{I}$ must
+be preserved, which is given here in [Dirac notation](/know/concept/dirac-notation/):
+
+$$\begin{aligned}
+ \hat{I} = \int_a^b \ket{\xi} \bra{\xi} \dd{\xi}
+\end{aligned}$$
+
+Applying the identity operator to $f(x)$ should just give $f(x)$ again:
+
+$$\begin{aligned}
+ f(x) = \braket{x}{f} = \matrixel{x}{\hat{I}}{f}
+ = \int_a^b \braket{x}{\xi} \braket{\xi}{f} \dd{\xi}
+ = \int_a^b \braket{x}{\xi} f(\xi) \dd{\xi}
+\end{aligned}$$
+
+Since we want the latter integral to reduce to $f(x)$, it is plain to see that
+$\braket{x}{\xi}$ can only be a [Dirac delta function](/know/concept/dirac-delta-function/),
+i.e $\braket{x}{\xi} = \delta(x - \xi)$:
+
+$$\begin{aligned}
+ \int_a^b \braket{x}{\xi} f(\xi) \dd{\xi}
+ = \int_a^b \delta(x - \xi) f(\xi) \dd{\xi}
+ = f(x)
+\end{aligned}$$
+
+Consequently, $\braket{x}{\xi} = 0$ if $x \neq \xi$ as expected for an
+orthogonal set of basis vectors, but if $x = \xi$ the inner product
+$\braket{x}{\xi}$ is infinite, unlike earlier.
+
+Technically, because the basis vectors $x$ cannot be normalized, they
+are not members of a Hilbert space, but rather of a superset called a
+**rigged Hilbert space**. Such vectors have no finite inner product with
+themselves, but do have one with all vectors from the actual Hilbert
+space.
diff --git a/content/know/concept/legendre-transform/index.pdc b/content/know/concept/legendre-transform/index.pdc
new file mode 100644
index 0000000..8a0d3e3
--- /dev/null
+++ b/content/know/concept/legendre-transform/index.pdc
@@ -0,0 +1,89 @@
+---
+title: "Legendre transform"
+firstLetter: "L"
+publishDate: 2021-02-22
+categories:
+- Mathematics
+- Physics
+
+date: 2021-02-22T21:36:35+01:00
+draft: false
+markup: pandoc
+---
+
+# Legendre transform
+
+The **Legendre transform** of a function $f(x)$ is a new function $L(f')$,
+which depends only on the derivative $f'(x)$ of $f(x)$, and from which
+the original function $f(x)$ can be reconstructed. The point is,
+analogously to other transforms (e.g. [Fourier](/know/concept/fourier-transform/)),
+that $L(f')$ contains the same information as $f(x)$, just in a different form.
+
+Let us choose an arbitrary point $x_0 \in [a, b]$ in the domain of
+$f(x)$. Consider a line $y(x)$ tangent to $f(x)$ at $x = x_0$, which has
+a slope $f'(x_0)$ and intersects the $y$-axis at $-C$:
+
+$$\begin{aligned}
+ y(x) = f'(x_0) (x - x_0) + f(x_0) = f'(x_0) x - C
+\end{aligned}$$
+
+The Legendre transform $L(f')$ is defined such that $L(f'(x_0)) = C$ (or
+sometimes $-C$ instead) for all $x_0 \in [a, b]$, where $C$ is the
+constant corresponding to the tangent line at $x = x_0$. This yields:
+
+$$\begin{aligned}
+ L(f'(x)) = f'(x) \: x - f(x)
+\end{aligned}$$
+
+We want this function to depend only on the derivative $f'$, but
+currently $x$ still appears here as a variable. We fix that problem in
+the easiest possible way: by assuming that $f'(x)$ is invertible for all
+$x \in [a, b]$. If $x(f')$ is the inverse of $f'(x)$, then $L(f')$ is
+given by:
+
+$$\begin{aligned}
+ \boxed{
+ L(f') = f' \: x(f') - f(x(f'))
+ }
+\end{aligned}$$
+
+The only requirement for the existence of the Legendre transform is thus
+the invertibility of $f'(x)$ in the target interval $[a,b]$, which can
+only be true if $f(x)$ is either convex or concave, i.e. its derivative
+$f'(x)$ is monotonic.
+
+Crucially, the derivative of $L(f')$ with respect to $f'$ is simply
+$x(f')$. In other words, the roles of $f'$ and $x$ are switched by the
+transformation: the coordinate becomes the derivative and vice versa.
+This is demonstrated here:
+
+$$\begin{aligned}
+ \boxed{
+ \dv{L}{f'} = \dv{x}{f'} \: f' + x(f') - \dv{f}{x} \dv{x}{f'} = x(f')
+ }
+\end{aligned}$$
+
+Furthermore, Legendre transformation is an *involution*, meaning it is
+its own inverse. Let $g(L')$ be the Legendre transform of $L(f')$:
+
+$$\begin{aligned}
+ g(L') = L' \: f'(L') - L(f'(L'))
+ = x(f') \: f' - f' \: x(f') + f(x(f')) = f(x)
+\end{aligned}$$
+
+Moreover, the inverse of a (forward) transform always exists, because
+the Legendre transform of a convex function is itself convex. Convexity
+of $f(x)$ means that $f''(x) > 0$ for all $x \in [a, b]$, which yields
+the following proof:
+
+$$\begin{aligned}
+ L''(f')
+ = \dv{x(f')}{f'}
+ = \dv{x}{f'(x)}
+ = \frac{1}{f''(x)}
+ > 0
+\end{aligned}$$
+
+Legendre transformation is important in physics,
+since it connects Lagrangian and Hamiltonian mechanics to each other.
+It is also used to convert between thermodynamic potentials.
diff --git a/content/know/concept/parsevals-theorem/index.pdc b/content/know/concept/parsevals-theorem/index.pdc
new file mode 100644
index 0000000..8f653f8
--- /dev/null
+++ b/content/know/concept/parsevals-theorem/index.pdc
@@ -0,0 +1,76 @@
+---
+title: "Parseval's theorem"
+firstLetter: "P"
+publishDate: 2021-02-22
+categories:
+- Mathematics
+- Physics
+
+date: 2021-02-22T21:36:44+01:00
+draft: false
+markup: pandoc
+---
+
+# Parseval's theorem
+
+**Parseval's theorem** relates the inner product of two functions $f(x)$ and $g(x)$ to the
+inner product of their [Fourier transforms](/know/concept/fourier-transform/)
+$\tilde{f}(k)$ and $\tilde{g}(k)$.
+There are two equivalent ways of stating it,
+where $A$, $B$, and $s$ are constants from the Fourier transform's definition:
+
+$$\begin{aligned}
+ \boxed{
+ \braket{f(x)}{g(x)} = \frac{2 \pi B^2}{|s|} \braket*{\tilde{f}(k)}{\tilde{g}(k)}
+ }
+ \\
+ \boxed{
+ \braket*{\tilde{f}(k)}{\tilde{g}(k)} = \frac{2 \pi A^2}{|s|} \braket{f(x)}{g(x)}
+ }
+\end{aligned}$$
+
+For this reason, physicists like to define their Fourier transform
+with $A = B = 1 / \sqrt{2\pi}$ and $|s| = 1$, because then the FT nicely
+conserves the total probability (quantum mechanics) or the total energy
+(optics).
+
+To prove this, we insert the inverse FT into the inner product
+definition:
+
+$$\begin{aligned}
+ \braket{f}{g}
+ &= \int_{-\infty}^\infty \big( \hat{\mathcal{F}}^{-1}\{\tilde{f}(k)\}\big)^* \: \hat{\mathcal{F}}^{-1}\{\tilde{g}(k)\} \dd{x}
+ \\
+ &= B^2 \int
+ \Big( \int \tilde{f}^*(k_1) \exp(i s k_1 x) \dd{k_1} \Big)
+ \Big( \int \tilde{g}(k) \exp(- i s k x) \dd{k} \Big)
+ \dd{x}
+ \\
+ &= 2 \pi B^2 \iint \tilde{f}^*(k_1) \tilde{g}(k) \Big( \frac{1}{2 \pi} \int_{-\infty}^\infty \exp(i s x (k_1 - k)) \dd{x} \Big) \dd{k_1} \dd{k}
+ \\
+ &= 2 \pi B^2 \iint \tilde{f}^*(k_1) \: \tilde{g}(k) \: \delta(s (k_1 - k)) \dd{k_1} \dd{k}
+ \\
+ &= \frac{2 \pi B^2}{|s|} \int_{-\infty}^\infty \tilde{f}^*(k) \: \tilde{g}(k) \dd{k}
+ = \frac{2 \pi B^2}{|s|} \braket*{\tilde{f}}{\tilde{g}}
+\end{aligned}$$
+
+Where $\delta(k)$ is the [Dirac delta function](/know/concept/dirac-delta-function/).
+Note that we can just as well do it in the opposite direction,
+which yields an equivalent result:
+
+$$\begin{aligned}
+ \braket*{\tilde{f}}{\tilde{g}}
+ &= \int_{-\infty}^\infty \big( \hat{\mathcal{F}}\{f(x)\}\big)^* \: \hat{\mathcal{F}}\{g(x)\} \dd{k}
+ \\
+ &= A^2 \int
+ \Big( \int f^*(x_1) \exp(- i s k x_1) \dd{x_1} \Big)
+ \Big( \int g(x) \exp(i s k x) \dd{x} \Big)
+ \dd{k}
+ \\
+ &= 2 \pi A^2 \iint f^*(x_1) g(x) \Big( \frac{1}{2 \pi} \int_{-\infty}^\infty \exp(i s k (x_1 - x)) \dd{k} \Big) \dd{x_1} \dd{x}
+ \\
+ &= 2 \pi A^2 \iint f^*(x_1) \: g(x) \: \delta(s (x_1 - x)) \dd{x_1} \dd{x}
+ \\
+ &= \frac{2 \pi A^2}{|s|} \int_{-\infty}^\infty f^*(x) \: g(x) \dd{x}
+ = \frac{2 \pi A^2}{|s|} \braket{f}{g}
+\end{aligned}$$
diff --git a/content/know/concept/partial-fraction-decomposition/index.pdc b/content/know/concept/partial-fraction-decomposition/index.pdc
new file mode 100644
index 0000000..1f4207f
--- /dev/null
+++ b/content/know/concept/partial-fraction-decomposition/index.pdc
@@ -0,0 +1,60 @@
+---
+title: "Partial fraction decomposition"
+firstLetter: "P"
+publishDate: 2021-02-22
+categories:
+- Mathematics
+
+date: 2021-02-22T21:36:56+01:00
+draft: false
+markup: pandoc
+---
+
+# Partial fraction decomposition
+
+**Partial fraction decomposition** or **expansion** is a method to rewrite a
+quotient of two polynomials $g(x)$ and $h(x)$, where the numerator
+$g(x)$ is of lower order than $h(x)$, as a sum of fractions with $x$ in
+the denominator:
+
+$$\begin{aligned}
+ f(x) = \frac{g(x)}{h(x)} = \frac{c_1}{x - h_1} + \frac{c_2}{x - h_2} + ...
+\end{aligned}$$
+
+Where $h_n$ etc. are the roots of the denominator $h(x)$. If all $N$ of
+these roots are distinct, then it is sufficient to simply posit:
+
+$$\begin{aligned}
+ \boxed{
+ f(x) = \frac{c_1}{x - h_1} + \frac{c_2}{x - h_2} + ... + \frac{c_N}{x - h_N}
+ }
+\end{aligned}$$
+
+The constants $c_n$ can either be found the hard way,
+by multiplying the denominators around and solving a system of $N$
+equations, or the easy way by using this trick:
+
+$$\begin{aligned}
+ \boxed{
+ c_n = \lim_{x \to h_n} \big( f(x) (x - h_n) \big)
+ }
+\end{aligned}$$
+
+If $h_1$ is a root with multiplicity $m > 1$, then the sum takes the form of:
+
+$$\begin{aligned}
+ \boxed{
+ f(x)
+ = \frac{c_{1,1}}{x - h_1} + \frac{c_{1,2}}{(x - h_1)^2} + ...
+ }
+\end{aligned}$$
+
+Where $c_{1,j}$ are found by putting the terms on a common denominator, e.g.
+
+$$\begin{aligned}
+ \frac{c_{1,1}}{x - h_1} + \frac{c_{1,2}}{(x - h_1)^2}
+ = \frac{c_{1,1} (x - h_1) + c_{1,2}}{(x - h_1)^2}
+\end{aligned}$$
+
+And then, using the linear independence of $x^0, x^1, x^2, ...$, solving
+a system of $m$ equations to find all $c_{1,1}, ..., c_{1,m}$.
diff --git a/content/know/concept/pauli-exclusion-principle/index.pdc b/content/know/concept/pauli-exclusion-principle/index.pdc
new file mode 100644
index 0000000..aa9609b
--- /dev/null
+++ b/content/know/concept/pauli-exclusion-principle/index.pdc
@@ -0,0 +1,125 @@
+---
+title: "Pauli exclusion principle"
+firstLetter: "P"
+publishDate: 2021-02-22
+categories:
+- Quantum mechanics
+- Physics
+
+date: 2021-02-22T21:37:14+01:00
+draft: false
+markup: pandoc
+---
+
+# Pauli exclusion principle
+
+In quantum mechanics, the **Pauli exclusion principle** is a theorem with
+profound consequences for how the world works.
+
+Suppose we have a composite state
+$\ket*{x_1}\ket*{x_2} = \ket*{x_1} \otimes \ket*{x_2}$, where the two
+identical particles $x_1$ and $x_2$ each can occupy the same two allowed
+states $a$ and $b$. We then define the permutation operator $\hat{P}$ as
+follows:
+
+$$\begin{aligned}
+ \hat{P} \ket{a}\ket{b} = \ket{b}\ket{a}
+\end{aligned}$$
+
+That is, it swaps the states of the particles. Obviously, swapping the
+states twice simply gives the original configuration again, so:
+
+$$\begin{aligned}
+ \hat{P}^2 \ket{a}\ket{b} = \ket{a}\ket{b}
+\end{aligned}$$
+
+Therefore, $\ket{a}\ket{b}$ is an eigenvector of $\hat{P}^2$ with
+eigenvalue $1$. Since $[\hat{P}, \hat{P}^2] = 0$, $\ket{a}\ket{b}$
+must also be an eigenket of $\hat{P}$ with eigenvalue $\lambda$,
+satisfying $\lambda^2 = 1$, so we know that $\lambda = 1$ or $\lambda = -1$:
+
+$$\begin{aligned}
+ \hat{P} \ket{a}\ket{b} = \lambda \ket{a}\ket{b}
+\end{aligned}$$
+
+As it turns out, in nature, each class of particle has a single
+associated permutation eigenvalue $\lambda$, or in other words: whether
+$\lambda$ is $-1$ or $1$ depends on the type of particle that $x_1$
+and $x_2$ are. Particles with $\lambda = -1$ are called
+**fermions**, and those with $\lambda = 1$ are known as **bosons**. We
+define $\hat{P}_f$ with $\lambda = -1$ and $\hat{P}_b$ with
+$\lambda = 1$, such that:
+
+$$\begin{aligned}
+ \hat{P}_f \ket{a}\ket{b} = \ket{b}\ket{a} = - \ket{a}\ket{b}
+ \qquad
+ \hat{P}_b \ket{a}\ket{b} = \ket{b}\ket{a} = \ket{a}\ket{b}
+\end{aligned}$$
+
+Another fundamental fact of nature is that identical particles cannot be
+distinguished by any observation. Therefore it is impossible to tell
+apart $\ket{a}\ket{b}$ and the permuted state $\ket{b}\ket{a}$,
+regardless of the eigenvalue $\lambda$. There is no physical difference!
+
+But this does not mean that $\hat{P}$ is useless: despite not having any
+observable effect, the resulting difference between fermions and bosons
+is absolutely fundamental. Consider the following superposition state,
+where $\alpha$ and $\beta$ are unknown:
+
+$$\begin{aligned}
+ \ket{\Psi(a, b)}
+ = \alpha \ket{a}\ket{b} + \beta \ket{b}\ket{a}
+\end{aligned}$$
+
+When we apply $\hat{P}$, we can "choose" between two "intepretations" of
+its action, both shown below. Obviously, since the left-hand sides are
+equal, the right-hand sides must be equal too:
+
+$$\begin{aligned}
+ \hat{P} \ket{\Psi(a, b)}
+ &= \lambda \alpha \ket{a}\ket{b} + \lambda \beta \ket{b}\ket{a}
+ \\
+ \hat{P} \ket{\Psi(a, b)}
+ &= \alpha \ket{b}\ket{a} + \beta \ket{a}\ket{b}
+\end{aligned}$$
+
+This gives us the equations $\lambda \alpha = \beta$ and
+$\lambda \beta = \alpha$. In fact, just from this we could have deduced
+that $\lambda$ can be either $-1$ or $1$. In any case, for bosons
+($\lambda = 1$), we thus find that $\alpha = \beta$:
+
+$$\begin{aligned}
+ \ket{\Psi(a, b)}_b = C \big( \ket{a}\ket{b} + \ket{b}\ket{a} \big)
+\end{aligned}$$
+
+Where $C$ is a normalization constant. As expected, this state is
+**symmetric**: switching $a$ and $b$ gives the same result. Meanwhile, for
+fermions ($\lambda = -1$), we find that $\alpha = -\beta$:
+
+$$\begin{aligned}
+ \ket{\Psi(a, b)}_f = C \big( \ket{a}\ket{b} - \ket{b}\ket{a} \big)
+\end{aligned}$$
+
+This state is called **antisymmetric** under exchange: switching $a$ and $b$
+causes a sign change, as we would expect for fermions.
+
+Now, what if the particles $x_1$ and $x_2$ are in the same state $a$?
+For bosons, we just need to update the normalization constant $C$:
+
+$$\begin{aligned}
+ \ket{\Psi(a, a)}_b
+ = C \ket{a}\ket{a}
+\end{aligned}$$
+
+However, for fermions, the state is unnormalizable and thus unphysical:
+
+$$\begin{aligned}
+ \ket{\Psi(a, a)}_f
+ = C \big( \ket{a}\ket{a} - \ket{a}\ket{a} \big)
+ = 0
+\end{aligned}$$
+
+And this is the Pauli exclusion principle: **fermions may never
+occupy the same quantum state**. One of the many notable consequences of
+this is that the shells of atoms only fit a limited number of
+electrons (which are fermions), since each must have a different quantum number.
diff --git a/content/know/concept/probability-current/index.pdc b/content/know/concept/probability-current/index.pdc
new file mode 100644
index 0000000..c67956a
--- /dev/null
+++ b/content/know/concept/probability-current/index.pdc
@@ -0,0 +1,98 @@
+---
+title: "Probability current"
+firstLetter: "P"
+publishDate: 2021-02-22
+categories:
+- Quantum mechanics
+- Physics
+
+date: 2021-02-22T21:37:26+01:00
+draft: false
+markup: pandoc
+---
+
+# Probability current
+
+In quantum mechanics, the **probability current** describes the movement
+of the probability of finding a particle at given point in space.
+In other words, it treats the particle as a heterogeneous fluid with density $|\psi|^2$.
+Now, the probability of finding the particle within a volume $V$ is:
+
+$$\begin{aligned}
+ P = \int_{V} | \psi |^2 \dd[3]{\vec{r}}
+\end{aligned}$$
+
+As the system evolves in time, this probability may change, so we take
+its derivative with respect to time $t$, and when necessary substitute
+in the other side of the Schrödinger equation to get:
+
+$$\begin{aligned}
+ \pdv{P}{t}
+ &= \int_{V} \psi \pdv{\psi^*}{t} + \psi^* \pdv{\psi}{t} \dd[3]{\vec{r}}
+ = \frac{i}{\hbar} \int_{V} \psi (\hat{H} \psi^*) - \psi^* (\hat{H} \psi) \dd[3]{\vec{r}}
+ \\
+ &= \frac{i}{\hbar} \int_{V} \psi \Big( \!-\! \frac{\hbar^2}{2 m} \nabla^2 \psi^* + V(\vec{r}) \psi^* \Big)
+ - \psi^* \Big( \!-\! \frac{\hbar^2}{2 m} \nabla^2 \psi + V(\vec{r}) \psi \Big) \dd[3]{\vec{r}}
+ \\
+ &= \frac{i \hbar}{2 m} \int_{V} - \psi \nabla^2 \psi^* + \psi^* \nabla^2 \psi \dd[3]{\vec{r}}
+ = - \int_{V} \nabla \cdot \vec{J} \dd[3]{\vec{r}}
+\end{aligned}$$
+
+Where we have defined the probability current $\vec{J}$ as follows in
+the $\vec{r}$-basis:
+
+$$\begin{aligned}
+ \vec{J}
+ = \frac{i \hbar}{2 m} (\psi \nabla \psi^* - \psi^* \nabla \psi)
+ = \mathrm{Re} \Big\{ \psi \frac{i \hbar}{m} \psi^* \Big\}
+\end{aligned}$$
+
+Let us rewrite this using the momentum operator
+$\hat{p} = -i \hbar \nabla$ as follows, noting that $\hat{p} / m$ is
+simply the velocity operator $\hat{v}$:
+
+$$\begin{aligned}
+ \boxed{
+ \vec{J}
+ = \frac{1}{2 m} ( \psi^* \hat{p} \psi - \psi \hat{p} \psi^*)
+ = \mathrm{Re} \Big\{ \psi^* \frac{\hat{p}}{m} \psi \Big\}
+ = \mathrm{Re} \{ \psi^* \hat{v} \psi \}
+ }
+\end{aligned}$$
+
+Returning to the derivation of $\vec{J}$, we now have the following
+equation:
+
+$$\begin{aligned}
+ \pdv{P}{t}
+ = \int_{V} \pdv{|\psi|^2}{t} \dd[3]{\vec{r}}
+ = - \int_{V} \nabla \cdot \vec{J} \dd[3]{\vec{r}}
+\end{aligned}$$
+
+By removing the integrals, we thus arrive at the **continuity equation**
+for $\vec{J}$:
+
+$$\begin{aligned}
+ \boxed{
+ \nabla \cdot \vec{J}
+ = - \pdv{|\psi|^2}{t}
+ }
+\end{aligned}$$
+
+This states that the total probability is conserved, and is reminiscent of charge
+conservation in electromagnetism. In other words, the probability at a
+point can only change by letting it "flow" towards or away from it. Thus
+$\vec{J}$ represents the flow of probability, which is analogous to the
+motion of a particle.
+
+As a bonus, this still holds for a particle in an electromagnetic vector
+potential $\vec{A}$, thanks to the gauge invariance of the Schrödinger
+equation. We can thus extend the definition to a particle with charge
+$q$ in an SI-unit field, neglecting spin:
+
+$$\begin{aligned}
+ \boxed{
+ \vec{J}
+ = \mathrm{Re} \Big\{ \psi^* \frac{\hat{p} - q \vec{A}}{m} \psi \Big\}
+ }
+\end{aligned}$$
diff --git a/content/know/concept/slater-determinant/index.pdc b/content/know/concept/slater-determinant/index.pdc
new file mode 100644
index 0000000..8bc4291
--- /dev/null
+++ b/content/know/concept/slater-determinant/index.pdc
@@ -0,0 +1,54 @@
+---
+title: "Slater determinant"
+firstLetter: "S"
+publishDate: 2021-02-22
+categories:
+- Quantum mechanics
+- Physics
+
+date: 2021-02-22T21:38:03+01:00
+draft: false
+markup: pandoc
+---
+
+# Slater determinant
+
+In quantum mechanics, the **Slater determinant** is a trick
+to create a many-particle wave function for a system of $N$ fermions,
+with the necessary antisymmetry.
+
+Given an orthogonal set of individual states $\psi_n(x)$, we write
+$\psi_n(x_n)$ to say that particle $x_n$ is in state $\psi_n$. Now the
+goal is to find an expression for an overall many-particle wave
+function $\Psi(x_1, ..., x_N)$ that satisfies the
+[Pauli exclusion principle](/know/concept/pauli-exclusion-principle/).
+Enter the Slater determinant:
+
+$$\begin{aligned}
+ \boxed{
+ \Psi(x_1, ..., x_N)
+ = \frac{1}{\sqrt{N!}} \det\!
+ \begin{bmatrix}
+ \psi_1(x_1) & \cdots & \psi_N(x_1) \\
+ \vdots & \ddots & \vdots \\
+ \psi_1(x_N) & \cdots & \psi_N(x_N)
+ \end{bmatrix}
+ }\end{aligned}$$
+
+Swapping the state of two particles corresponds to exchanging two rows,
+which flips the sign of the determinant.
+Similarly, switching two columns means swapping two states,
+which also results in a sign change.
+Finally, putting two particles into the same state makes $\Psi$ vanish.
+
+Not all valid many-fermion wave functions can be
+written as a single Slater determinant; a linear combination of multiple
+may be needed. Nevertheless, an appropriate choice of the input set
+$\psi_n(x)$ can optimize how well a single determinant approximates a
+given $\Psi$.
+
+In fact, there exists a similar trick for bosons, where the goal is to
+create a symmetric wave function which allows multiple particles to
+occupy the same state. In this case, one needs to take the **Slater
+permanent** of the same matrix, which is simply the determinant, but with
+all minuses replaced by pluses.
diff --git a/content/know/concept/sturm-liouville-theory/index.pdc b/content/know/concept/sturm-liouville-theory/index.pdc
new file mode 100644
index 0000000..7ccd625
--- /dev/null
+++ b/content/know/concept/sturm-liouville-theory/index.pdc
@@ -0,0 +1,346 @@
+---
+title: "Sturm-Liouville theory"
+firstLetter: "S"
+publishDate: 2021-02-23
+categories:
+- Mathematics
+- Physics
+
+date: 2021-02-23T08:52:28+01:00
+draft: false
+markup: pandoc
+---
+
+# Sturm-Liouville theory
+
+**Sturm-Liouville theory** defines the analogue of Hermitian matrix
+eigenvalue problems for linear second-order ODEs.
+
+It states that, given suitable boundary conditions, any linear
+second-order ODE can be rewritten using the **Sturm-Liouville operator**,
+and that the corresponding eigenvalue problem, known as a
+**Sturm-Liouville problem**, will give real eigenvalues and a complete set
+of eigenfunctions.
+
+
+## General operator
+
+Consider the most general form of a second-order linear
+differential operator $\hat{L}$, where $p_0(x)$, $p_1(x)$, and $p_2(x)$
+are real functions of $x \in [a,b]$ which are non-zero for all $x \in ]a, b[$:
+
+$$\begin{aligned}
+ \hat{L} \{u(x)\} = p_0(x) u''(x) + p_1(x) u'(x) + p_2(x) u(x)
+\end{aligned}$$
+
+We now define the **adjoint** or **Hermitian** operator
+$\hat{L}^\dagger$ analogously to matrices:
+
+$$\begin{aligned}
+ \braket*{f}{\hat{L} g}
+ = \braket*{\hat{L}^\dagger f}{g}
+\end{aligned}$$
+
+What is $\hat{L}^\dagger$, given the above definition of $\hat{L}$?
+We start from the inner product $\braket*{f}{\hat{L} g}$:
+
+$$\begin{aligned}
+ \braket*{f}{\hat{L} g}
+ &= \int_a^b f^*(x) \hat{L}\{g(x)\} \dd{x}
+ = \int_a^b (f^* p_0) g'' + (f^* p_1) g' + (f^* p_2) g \dd{x}
+ \\
+ &= \big[ (f^* p_0) g' + (f^* p_1) g \big]_a^b - \int_a^b (f^* p_0)' g' + (f^* p_1)' g - (f^* p_2) g \dd{x}
+ \\
+ &= \big[ f^* \big( p_0 g' \!+\! p_1 g \big) \!-\! (f^* p_0)' g \big]_a^b + \int_a^b \! \big( (f p_0)'' - (f p_1)' + (f p_2) \big)^* g \dd{x}
+ \\
+ &= \big[ f^* \big( p_0 g' + (p_1 - p_0') g \big) - (f^*)' p_0 g \big]_a^b + \int_a^b \big( \hat{L}^\dagger\{f\} \big)^* g \dd{x}
+\end{aligned}$$
+
+We now have an expression for $\hat{L}^\dagger$, but are left with an
+annoying boundary term:
+
+$$\begin{aligned}
+ \braket*{f}{\hat{L} g}
+ &= \big[ f^* \big( p_0 g' + (p_1 - p_0') g \big) - (f^*)' p_0 g \big]_a^b + \braket*{\hat{L}^\dagger f}{g}
+\end{aligned}$$
+
+To fix this,
+let us demand that $p_1(x) = p_0'(x)$ and that
+$[p_0(f^* g' - (f^*)' g)]_a^b = 0$, leaving:
+
+$$\begin{aligned}
+ \braket*{f}{\hat{L} g}
+ &= \big[ p_0 \big( f^* g' - (f^*)' g \big) \big]_a^b + \braket{\hat{L}^\dagger f}{g}
+ = \braket*{\hat{L}^\dagger f}{g}
+\end{aligned}$$
+
+Using the aforementioned restriction $p_1(x) = p_0'(x)$,
+we then take a look at the definition of $\hat{L}^\dagger$:
+
+$$\begin{aligned}
+ \hat{L}^\dagger \{f\}
+ &= (p_0 f)'' - (p_1 f)' + (p_2 f)
+ \\
+ &= p_0 f'' + (2 p_0' - p_1) f' + (p_0'' - p_1' + p_2) f
+ \\
+ &= p_0 f'' + p_0' f' + p_2 f
+ \\
+ &= (p_0 f')' + p_2 f
+\end{aligned}$$
+
+The original operator $\hat{L}$ reduces to the same form,
+so it is **self-adjoint**:
+
+$$\begin{aligned}
+ \hat{L} \{f\}
+ &= p_0 f'' + p_0' f' + p_2 f
+ = (p_0 f')' + p_2 f
+ = \hat{L}^\dagger \{f\}
+\end{aligned}$$
+
+Consequently, every such second-order linear operator $\hat{L}$ is self-adjoint,
+as long as it satisfies the constraints $p_1(x) = p_0'(x)$ and $[p_0 (f^* g' - (f^*)' g)]_a^b = 0$.
+
+Let us ignore the latter constraint for now (it will return later),
+and focus on the former: what if $\hat{L}$ does not satisfy $p_0' \neq p_1$?
+We multiply it by an unknown $p(x) \neq 0$, and divide by $p_0(x) \neq 0$:
+
+$$\begin{aligned}
+ \frac{p(x)}{p_0(x)} \hat{L} \{u\} = p(x) u'' + p(x) \frac{p_1(x)}{p_0(x)} u' + p(x) \frac{p_2(x)}{p_0(x)} u
+\end{aligned}$$
+
+We now define $q(x)$,
+and demand that the derivative $p'(x)$ of the unknown $p(x)$ satisfies:
+
+$$\begin{aligned}
+ q(x) = p(x) \frac{p_2(x)}{p_0(x)}
+ \qquad
+ p'(x) = p(x) \frac{p_1(x)}{p_0(x)}
+\end{aligned}$$
+
+The latter is a differential equation for $p(x)$, which we solve by integration:
+
+$$\begin{gathered}
+ \frac{p_1(x)}{p_0(x)} = \frac{1}{p(x)} \dv{p}{x}
+ \quad \implies \quad
+ \frac{p_1(x)}{p_0(x)} \dd{x} = \frac{1}{p(x)} \dd{p}
+ \\
+ \implies \quad
+ \int_a^x \frac{p_1(\xi)}{p_0(\xi)} \dd{\xi} = \int_{p(a)}^{p(x)} \frac{1}{f} \dd{f}
+ = \ln\Big( \frac{p(x)}{p(a)} \Big)
+ \\
+ \implies \quad
+ p(x) = p(a) \exp\!\Big( \int_a^x \frac{p_1(\xi)}{p_0(\xi)} \dd{\xi} \Big)
+\end{gathered}$$
+
+Now that we have $p(x)$ and $q(x)$, we can define a new operator $\hat{L}_p$ as follows:
+
+$$\begin{aligned}
+ \hat{L}_p \{u\}
+ = \frac{p}{p_0} \hat{L} \{u\}
+ = p u'' + p' u' + q u
+ = (p u')' + q u
+\end{aligned}$$
+
+This is the self-adjoint form from earlier!
+So even if $p_0' \neq p_1$, any second-order linear operator with $p_0(x) \neq 0$
+can easily be put in self-adjoint form.
+
+This general form is known as the **Sturm-Liouville operator** $\hat{L}_{SL}$,
+where $p(x)$ and $q(x)$ are non-zero real functions of the variable $x \in [a,b]$:
+
+$$\begin{aligned}
+ \boxed{
+ \hat{L}_{SL} \{u(x)\}
+ = \frac{d}{dx}\Big( p(x) \frac{du}{dx} \Big) + q(x) u(x)
+ = \hat{L}_{SL}^\dagger \{u(x)\}
+ }
+\end{aligned}$$
+
+
+## Eigenvalue problem
+
+A **Sturm-Liouville problem** (SLP) is analogous to a matrix eigenvalue problem,
+where $w(x)$ is a real weight function, $\lambda$ is the **eigenvalue**,
+and $u(x)$ is the corresponding **eigenfunction**:
+
+$$\begin{aligned}
+ \boxed{
+ \hat{L}_{SL}\{u(x)\} = - \lambda w(x) u(x)
+ }
+\end{aligned}$$
+
+Necessarily, $w(x) > 0$ except in isolated points, where $w(x) = 0$ is allowed;
+the point is that any inner product $\braket{f}{w g}$ may never be zero due to $w$'s fault.
+Furthermore, the convention is that $u(x)$ cannot be trivially zero.
+
+In our derivation of $\hat{L}_{SL}$,
+we removed a boundary term to get self-adjointness.
+Consequently, to have a valid SLP, the boundary conditions for
+$u(x)$ must be as follows, otherwise the operator cannot be self-adjoint:
+
+$$\begin{aligned}
+ \Big[ p(x) \big( u^*(x) u'(x) - (u'(x))^* u(x) \big) \Big]_a^b = 0
+\end{aligned}$$
+
+There are many boundary conditions (BCs) which satisfy this requirement.
+Some notable ones are listed here non-exhaustively:
+
++ **Dirichlet BCs**: $u(a) = u(b) = 0$
++ **Neumann BCs**: $u'(a) = u'(b) = 0$
++ **Robin BCs**: $\alpha_1 u(a) + \beta_1 u'(a) = \alpha_2 u(b) + \beta_2 u'(b) = 0$ with $\alpha_{1,2}, \beta_{1,2} \in \mathbb{R}$
++ **Periodic BCs**: $p(a) = p(b)$, $u(a) = u(b)$, and $u'(a) = u'(b)$
++ **Legendre "BCs"**: $p(a) = p(b) = 0$
+
+Once this requirement is satisfied, Sturm-Liouville theory gives us
+some very useful information about $\lambda$ and $u(x)$.
+From the definition of an SLP, we know that, given two arbitrary (and possibly identical)
+eigenfunctions $u_n$ and $u_m$, the following must be satisfied:
+
+$$\begin{aligned}
+ 0 = \hat{L}_{SL}\{u_n\} + \lambda_n w u_n = \hat{L}_{SL}\{u_m^*\} + \lambda_m^* w u_m^*
+\end{aligned}$$
+
+We subtract these expressions, multiply by the eigenfunctions, and integrate:
+
+$$\begin{aligned}
+ 0
+ &= \int_a^b u_m^* \big(\hat{L}_{SL}\{u_n\} + \lambda_n w u_n\big) - u_n \big(\hat{L}_{SL}\{u_m^*\} + \lambda_m^* w u_m^*\big) \:dx
+ \\
+ &= \int_a^b u_m^* \hat{L}_{SL}\{u_n\} - u_n \hat{L}_{SL}\{u_m^*\} + u_n u_m^* w (\lambda_n - \lambda_m^*) \:dx
+\end{aligned}$$
+
+Rearranging this a bit reveals that these are in fact three inner products:
+
+$$\begin{aligned}
+ \int_a^b u_m^* \hat{L}_{SL}\{u_n\} - u_n \hat{L}_{SL}\{u_m^*\} \:dx
+ &= (\lambda_m^* - \lambda_n) \int_a^b u_n u_m^* w \:dx
+ \\
+ \braket*{u_m}{\hat{L}_{SL} u_n} - \braket*{\hat{L}_{SL} u_m}{u_n}
+ &= (\lambda_m^* - \lambda_n) \braket{u_m}{w u_n}
+\end{aligned}$$
+
+The operator $\hat{L}_{SL}$ is self-adjoint by definition,
+so the left-hand side vanishes, leaving us with:
+
+$$\begin{aligned}
+ 0
+ &= (\lambda_m^* - \lambda_n) \braket{u_m}{w u_n}
+\end{aligned}$$
+
+When $m = n$, the inner product $\braket{u_n}{w u_n}$ is real and positive
+(assuming $u_n$ is not trivially zero, in which case it would be disqualified anyway).
+In this case we thus know that $\lambda_n^* = \lambda_n$,
+i.e. the eigenvalue $\lambda_n$ is real for any $n$.
+
+When $m \neq n$, then $\lambda_m^* - \lambda_n$ may or may not be zero,
+depending on the degeneracy. If there is no degeneracy, we
+see that $\braket{u_m}{w u_n} = 0$, i.e. the eigenfunctions are orthogonal.
+
+In case of degeneracy, manual orthogonalization is needed, but as it turns out,
+this is guaranteed to be doable, using e.g. the [Gram-Schmidt method](/know/concept/gram-schmidt-method/).
+
+In conclusion, **a Sturm-Liouville problem has real eigenvalues $\lambda$,
+and all the corresponding eigenfunctions $u(x)$ are mutually orthogonal**:
+
+$$\begin{aligned}
+ \boxed{
+ \braket{u_m(x)}{w(x) u_n(x)}
+ = \braket{u_n}{w u_n} \delta_{nm}
+ = A_n \delta_{nm}
+ }
+\end{aligned}$$
+
+When you're solving a differential eigenvalue problem,
+knowing that all eigenvalues are real is a *huge* simplification,
+so it is always worth checking whether you're dealing with an SLP.
+
+Another useful fact of SLPs is that they always
+have an infinite number of discrete eigenvalues.
+Furthermore, the eigenvalues always ascend to $+\infty$;
+in other words, there always exists a *lowest* eigenvalue $\lambda_0 > -\infty$,
+known as the **ground state**.
+
+
+## Completeness
+
+Not only are the eigenfunctions $u_n(x)$ of an SLP orthogonal, they
+also form a **complete basis**, meaning that any well-behaved function $f(x)$ can be
+expanded as a **generalized Fourier series** with coefficients $a_n$:
+
+$$\begin{aligned}
+ \boxed{
+ f(x)
+ = \sum_{n = 0}^\infty a_n u_n(x)
+ \quad \mathrm{for}\: x \in ]a, b[
+ }
+\end{aligned}$$
+
+This series will converge significantly faster if $f(x)$
+satisfies the same BCs as $u_n(x)$. In that case the
+expansion will even be valid for the inclusive interval $x \in [a, b]$.
+
+To find an expression for the coefficients $a_n$,
+we multiply the above generalized Fourier series by $w(x) u_m^*(x)$ for an arbitrary $m$:
+
+$$\begin{aligned}
+ f(x) w(x) u_m^*(x)
+ &= \sum_{n = 0}^\infty a_n u_n(x) w(x) u_m^*(x)
+\end{aligned}$$
+
+By integrating we get inner products on both the left and the right:
+
+$$\begin{aligned}
+ \int_a^b f(x) w(x) u_m^*(x) \dd{x}
+ &= \int_a^b \Big(\sum_{n = 0}^\infty a_n u_n(x) w(x) u_m^*(x)\Big) \dd{x}
+ \\
+ \braket{u_m}{w f}
+ &= \sum_{n = 0}^\infty a_n \braket{u_m}{w u_n}
+\end{aligned}$$
+
+Because the eigenfunctions of an SLP are mutually orthogonal,
+the summation disappears:
+
+$$\begin{aligned}
+ \braket{u_m}{w f}
+ &= \sum_{n = 0}^\infty a_n \braket{u_m}{w u_n}
+ = \sum_{n = 0}^\infty a_n A_n \delta_{nm}
+ = a_m A_m
+\end{aligned}$$
+
+After isolating this for $a_n$, we see that
+the coefficients are given by the projection of the target
+function $f(x)$ onto the normalized eigenfunctions $u_n(x) / A_n$:
+
+$$\begin{aligned}
+ \boxed{
+ a_n
+ = \frac{\braket{u_n}{w f}}{A_n}
+ = \frac{\braket{u_n}{w f}}{\braket{u_n}{w u_n}}
+ }
+\end{aligned}$$
+
+As a final remark, we can see something interesting
+by rearranging the generalized Fourier series
+after inserting the expression for $a_n$:
+
+$$\begin{aligned}
+ f(x)
+ &= \sum_{n = 0}^\infty \frac{1}{A_n} \braket{u_n}{w f} u_n(x)
+ = \int_a^b \Big(\sum_{n = 0}^\infty \frac{1}{A_n} u_n^*(\xi) w(\xi) f(\xi) u_n(x) \Big) \dd{\xi}
+ \\
+ &= \int_a^b f(\xi) \Big(\sum_{n = 0}^\infty \frac{1}{A_n} u_n^*(\xi) w(\xi) u_n(x) \Big) \dd{\xi}
+ %= \int_a^b f(\xi) \delta(x - \xi) \dd{\xi}
+\end{aligned}$$
+
+Upon closer inspection, the parenthesized summation
+must be the [Dirac delta function](/know/concept/dirac-delta-function/) $\delta(x)$
+for the integral to work out.
+This is in fact the underlying requirement for completeness:
+
+$$\begin{aligned}
+ \boxed{
+ \sum_{n = 0}^\infty \frac{1}{A_n} u_n^*(\xi) w(\xi) u_n(x) = \delta(x - \xi)
+ }
+\end{aligned}$$
+
diff --git a/content/know/concept/time-independent-perturbation-theory/index.pdc b/content/know/concept/time-independent-perturbation-theory/index.pdc
new file mode 100644
index 0000000..4f30ae8
--- /dev/null
+++ b/content/know/concept/time-independent-perturbation-theory/index.pdc
@@ -0,0 +1,329 @@
+---
+title: "Time-independent perturbation theory"
+firstLetter: "T"
+publishDate: 2021-02-22
+categories:
+- Quantum mechanics
+- Physics
+
+date: 2021-02-22T21:38:18+01:00
+draft: false
+markup: pandoc
+---
+
+# Time-independent perturbation theory
+
+**Time-independent perturbation theory**, sometimes also called
+**stationary state perturbation theory**, is a specific application of
+perturbation theory to the time-independent Schrödinger
+equation in quantum physics, for
+Hamiltonians of the following form:
+
+$$\begin{aligned}
+ \hat{H} = \hat{H}_0 + \lambda \hat{H}_1
+\end{aligned}$$
+
+Where $\hat{H}_0$ is a Hamiltonian for which the time-independent
+Schrödinger equation has a known solution, and $\hat{H}_1$ is a small
+perturbing Hamiltonian. The eigenenergies $E_n$ and eigenstates
+$\ket{\psi_n}$ of the composite problem are expanded in the
+perturbation "bookkeeping" parameter $\lambda$:
+
+$$\begin{aligned}
+ \ket{\psi_n}
+ &= \ket*{\psi_n^{(0)}} + \lambda \ket*{\psi_n^{(1)}} + \lambda^2 \ket*{\psi_n^{(2)}} + ...
+ \\
+ E_n
+ &= E_n^{(0)} + \lambda E_n^{(1)} + \lambda^2 E_n^{(2)} + ...
+\end{aligned}$$
+
+Where $E_n^{(1)}$ and $\ket*{\psi_n^{(1)}}$ are called the **first-order
+corrections**, and so on for higher orders. We insert this into the
+Schrödinger equation:
+
+$$\begin{aligned}
+ \hat{H} \ket{\psi_n}
+ &= \hat{H}_0 \ket*{\psi_n^{(0)}}
+ + \lambda \big( \hat{H}_1 \ket*{\psi_n^{(0)}} + \hat{H}_0 \ket*{\psi_n^{(1)}} \big) \\
+ &\qquad + \lambda^2 \big( \hat{H}_1 \ket*{\psi_n^{(1)}} + \hat{H}_0 \ket*{\psi_n^{(2)}} \big) + ...
+ \\
+ E_n \ket{\psi_n}
+ &= E_n^{(0)} \ket*{\psi_n^{(0)}}
+ + \lambda \big( E_n^{(1)} \ket*{\psi_n^{(0)}} + E_n^{(0)} \ket*{\psi_n^{(1)}} \big) \\
+ &\qquad + \lambda^2 \big( E_n^{(2)} \ket*{\psi_n^{(0)}} + E_n^{(1)} \ket*{\psi_n^{(1)}} + E_n^{(0)} \ket*{\psi_n^{(2)}} \big) + ...
+\end{aligned}$$
+
+If we collect the terms according to the order of $\lambda$, we arrive
+at the following endless series of equations, of which in practice only
+the first three are typically used:
+
+$$\begin{aligned}
+ \hat{H}_0 \ket*{\psi_n^{(0)}}
+ &= E_n^{(0)} \ket*{\psi_n^{(0)}}
+ \\
+ \hat{H}_1 \ket*{\psi_n^{(0)}} + \hat{H}_0 \ket*{\psi_n^{(1)}}
+ &= E_n^{(1)} \ket*{\psi_n^{(0)}} + E_n^{(0)} \ket*{\psi_n^{(1)}}
+ \\
+ \hat{H}_1 \ket*{\psi_n^{(1)}} + \hat{H}_0 \ket*{\psi_n^{(2)}}
+ &= E_n^{(2)} \ket*{\psi_n^{(0)}} + E_n^{(1)} \ket*{\psi_n^{(1)}} + E_n^{(0)} \ket*{\psi_n^{(2)}}
+ \\
+ ...
+ &= ...
+\end{aligned}$$
+
+The first equation is the unperturbed problem, which we assume has
+already been solved, with eigenvalues $E_n^{(0)} = \varepsilon_n$ and
+eigenvectors $\ket*{\psi_n^{(0)}} = \ket{n}$:
+
+$$\begin{aligned}
+ \hat{H}_0 \ket{n} = \varepsilon_n \ket{n}
+\end{aligned}$$
+
+The approach to solving the other two equations varies depending on
+whether this $\hat{H}_0$ has a degenerate spectrum or not.
+
+
+## Without degeneracy
+
+We start by assuming that there is no degeneracy, in other words, each
+$\varepsilon_n$ corresponds to one $\ket{n}$. At order $\lambda^1$, we
+rewrite the equation as follows:
+
+$$\begin{aligned}
+ (\hat{H}_1 - E_n^{(1)}) \ket{n} + (\hat{H}_0 - \varepsilon_n) \ket*{\psi_n^{(1)}} = 0
+\end{aligned}$$
+
+Since $\ket{n}$ form a complete basis, we can express
+$\ket*{\psi_n^{(1)}}$ in terms of them:
+
+$$\begin{aligned}
+ \ket*{\psi_n^{(1)}} = \sum_{m \neq n} c_m \ket{m}
+\end{aligned}$$
+
+Importantly, $n$ has been removed from the summation to prevent dividing
+by zero later. We are allowed to do this, because
+$\ket*{\psi_n^{(1)}} - c_n \ket{n}$ also satisfies the order-$\lambda^1$
+equation for any value of $c_n$, as demonstrated here:
+
+$$\begin{aligned}
+ (\hat{H}_1 - E_n^{(1)}) \ket{n} + (\hat{H}_0 - \varepsilon_n) \ket*{\psi_n^{(1)}} - (\varepsilon_n - \varepsilon_n) c_n \ket{n} = 0
+\end{aligned}$$
+
+Where we used $\hat{H}_0 \ket{n} = \varepsilon_n \ket{n}$.
+We insert the series form of $\ket*{\psi_n^{(1)}}$ into the $\lambda^1$-equation:
+
+$$\begin{aligned}
+ (\hat{H}_1 - E_n^{(1)}) \ket{n} + \sum_{m \neq n} c_m (\varepsilon_m - \varepsilon_n) \ket{m} = 0
+\end{aligned}$$
+
+We then put an arbitrary basis vector $\bra{k}$ in front of this
+equation to get:
+
+$$\begin{aligned}
+ \matrixel{k}{\hat{H}_1}{n} - E_n^{(1)} \braket{k}{n} + \sum_{m \neq n} c_m (\varepsilon_m - \varepsilon_n) \braket{k}{m} = 0
+\end{aligned}$$
+
+Suppose that $k = n$. Since $\ket{n}$ form an orthonormal basis, we end
+up with:
+
+$$\begin{aligned}
+ \boxed{
+ E_n^{(1)} = \matrixel{n}{\hat{H}_1}{n}
+ }
+\end{aligned}$$
+
+In other words, the first-order energy correction $E_n^{(1)}$ is the
+expectation value of the perturbation $\hat{H}_1$ for the unperturbed
+state $\ket{n}$.
+
+Suppose now that $k \neq n$, then only one term of the summation
+survives, and we are left with the following equation, which tells us
+$c_l$:
+
+$$\begin{aligned}
+ \matrixel{k}{\hat{H}_1}{n} + c_k (\varepsilon_k - \varepsilon_n) = 0
+\end{aligned}$$
+
+We isolate this result for $c_k$ and insert it into the series form of
+$\ket*{\psi_n^{(1)}}$ to get the full first-order correction to the wave
+function:
+
+$$\begin{aligned}
+ \boxed{
+ \ket*{\psi_n^{(1)}}
+ = \sum_{m \neq n} \frac{\matrixel{m}{\hat{H}_1}{n}}{\varepsilon_n - \varepsilon_m} \ket{m}
+ }
+\end{aligned}$$
+
+Here it is clear why this is only valid in the non-degenerate case:
+otherwise we would divide by zero in the denominator.
+
+Next, to find the second-order correction to the energy $E_n^{(2)}$, we
+take the corresponding equation and put $\bra{n}$ in front of it:
+
+$$\begin{aligned}
+ \matrixel{n}{\hat{H}_1}{\psi_n^{(1)}} + \matrixel{n}{\hat{H}_0}{\psi_n^{(2)}}
+ &= E_n^{(2)} \braket{n}{n} + E_n^{(1)} \braket{n}{\psi_n^{(1)}} + \varepsilon_n \braket{n}{\psi_n^{(2)}}
+\end{aligned}$$
+
+Because $\hat{H}_0$ is Hermitian, we know that
+$\matrixel{n}{\hat{H}_0}{\psi_n^{(2)}} = \varepsilon_n \braket{n}{\psi_n^{(2)}}$,
+i.e. we apply it to the bra, which lets us eliminate two terms. Also,
+since $\ket{n}$ is normalized, we find:
+
+$$\begin{aligned}
+ E_n^{(2)}
+ = \matrixel{n}{\hat{H}_1}{\psi_n^{(1)}} - E_n^{(1)} \braket{n}{\psi_n^{(1)}}
+\end{aligned}$$
+
+We explicitly removed the $\ket{n}$-dependence of $\ket*{\psi_n^{(1)}}$,
+so the last term is zero. By simply inserting our result for
+$\ket*{\psi_n^{(1)}}$, we thus arrive at:
+
+$$\begin{aligned}
+ \boxed{
+ E_n^{(2)}
+ = \sum_{m \neq n} \frac{\big| \matrixel{m}{\hat{H}_1}{n} \big|^2}{\varepsilon_n - \varepsilon_m}
+ }
+\end{aligned}$$
+
+In practice, it is not particulary useful to calculate more corrections.
+
+
+## With degeneracy
+
+If $\varepsilon_n$ is $D$-fold degenerate, then its eigenstate could be
+any vector $\ket{n, d}$ from the corresponding $D$-dimensional
+eigenspace:
+
+$$\begin{aligned}
+ \hat{H}_0 \ket{n} = \varepsilon_n \ket{n}
+ \quad \mathrm{where} \quad
+ \ket{n}
+ = \sum_{d = 1}^{D} c_{d} \ket{n, d}
+\end{aligned}$$
+
+In general, adding the perturbation $\hat{H}_1$ will *lift* the
+degeneracy, meaning the perturbed states will be non-degenerate. In the
+limit $\lambda \to 0$, these $D$ perturbed states change into $D$
+orthogonal states which are all valid $\ket{n}$.
+
+However, the $\ket{n}$ that they converge to are not arbitrary: only
+certain unperturbed eigenstates are "good" states. Without $\hat{H}_1$,
+this distinction is irrelevant, but in the perturbed case it will turn
+out to be important.
+
+For now, we write $\ket{n, d}$ to refer to any orthonormal set of
+vectors in the eigenspace of $\varepsilon_n$ (not necessarily the "good"
+ones), and $\ket{n}$ to denote any linear combination of these. We then
+take the equation at order $\lambda^1$ and prepend an arbitrary
+eigenspace basis vector $\bra{n, \delta}$:
+
+$$\begin{aligned}
+ \matrixel{n, \delta}{\hat{H}_1}{n} + \matrixel{n, \delta}{\hat{H}_0}{\psi_n^{(1)}}
+ &= E_n^{(1)} \braket{n, \delta}{n} + \varepsilon_n \braket{n, \delta}{\psi_n^{(1)}}
+\end{aligned}$$
+
+Since $\hat{H}_0$ is Hermitian, we use the same trick as before to
+reduce the problem to:
+
+$$\begin{aligned}
+ \matrixel{n, \delta}{\hat{H}_1}{n}
+ &= E_n^{(1)} \braket{n, \delta}{n}
+\end{aligned}$$
+
+We express $\ket{n}$ as a linear combination of the eigenbasis vectors
+$\ket{n, d}$ to get:
+
+$$\begin{aligned}
+ \sum_{d = 1}^{D} c_d \matrixel{n, \delta}{\hat{H}_1}{n, d}
+ = E_n^{(1)} \sum_{d = 1}^{D} c_d \braket{n, \delta}{n, d}
+ = c_{\delta} E_n^{(1)}
+\end{aligned}$$
+
+Let us now interpret the summation terms as matrix elements
+$M_{\delta, d}$:
+
+$$\begin{aligned}
+ M_{\delta, d} = \matrixel{n, \delta}{\hat{H}_1}{n, d}
+\end{aligned}$$
+
+By varying the value of $\delta$ from $1$ to $D$, we end up with
+equations of the form:
+
+$$\begin{aligned}
+ \begin{bmatrix}
+ M_{1, 1} & \cdots & M_{1, D} \\
+ \vdots & \ddots & \vdots \\
+ M_{D, 1} & \cdots & M_{D, D}
+ \end{bmatrix}
+ \begin{bmatrix}
+ c_1 \\ \vdots \\ c_D
+ \end{bmatrix}
+ = E_n^{(1)}
+ \begin{bmatrix}
+ c_1 \\ \vdots \\ c_D
+ \end{bmatrix}
+\end{aligned}$$
+
+This is an eigenvalue problem for $E_n^{(1)}$, where $c_d$ are the
+components of the eigenvectors which represent the "good" states.
+After solving this, let $\ket{n, g}$ be the resulting "good" states.
+Then, as long as $E_n^{(1)}$ is a non-degenerate eigenvalue of $M$:
+
+$$\begin{aligned}
+ \boxed{
+ E_{n, g}^{(1)} = \matrixel{n, g}{\hat{H}_1}{n, g}
+ }
+\end{aligned}$$
+
+Which is the same as in the non-degenerate case! Even better, the
+first-order wave function correction is also unchanged:
+
+$$\begin{aligned}
+ \boxed{
+ \ket*{\psi_{n,g}^{(1)}}
+ = \sum_{m \neq (n, g)} \frac{\matrixel{m}{\hat{H}_1}{n, g}}{\varepsilon_n - \varepsilon_m} \ket{m}
+ }
+\end{aligned}$$
+
+This works because the matrix $M$ is diagonal in the $\ket{n, g}$-basis,
+such that when $\ket{m}$ is any vector $\ket{n, \gamma}$ in the
+$\ket{n}$-eigenspace (except for $\ket{n,g}$, which is
+explicitly excluded), then the corresponding numerator
+$\matrixel{n, \gamma}{\hat{H}_1}{n, g} = M_{\gamma, g} = 0$, so the term
+does not contribute.
+
+If any of the eigenvalues $E_n^{(1)}$ of $M$ are degenerate, then there
+is still information missing about the components $c_d$ of the
+"good" states, in which case we must find them some other way.
+
+Such an alternative way of determining these "good" states is also of
+interest even if there is no degeneracy in $M$, since such a shortcut would
+allow us to use the formulae from non-degenerate perturbation theory
+straight away.
+
+The trick is to find a Hermitian operator $\hat{L}$ (usually using
+symmetries of the system) which commutes with both $\hat{H}_0$ and $\hat{H}_1$:
+
+$$\begin{aligned}
+ \comm*{\hat{L}}{\hat{H}_0} = \comm*{\hat{L}}{\hat{H}_1} = 0
+\end{aligned}$$
+
+So that it shares its eigenstates with $\hat{H}_0$ (and $\hat{H}_1$),
+meaning all the vectors of the $D$-dimensional
+$\ket{n}$-eigenspace are also eigenvectors of $\hat{L}$.
+
+The crucial part, however, is that $\hat{L}$ must be chosen such that
+$\ket{n, d_1}$ and $\ket{n, d_2}$ have distinct eigenvalues
+$\ell_1 \neq \ell_2$ for $d_1 \neq d_2$:
+
+$$\begin{aligned}
+ \hat{L} \ket{n, b_1} = \ell_1 \ket{n, b_1}
+ \qquad
+ \hat{L} \ket{n, b_2} = \ell_2 \ket{n, b_2}
+\end{aligned}$$
+
+When this holds for any orthogonal choice of $\ket{n, d_1}$ and
+$\ket{n, d_2}$, then these specific eigenvectors of $\hat{L}$ are the
+"good states", for any valid choice of $\hat{L}$.
diff --git a/content/know/concept/wentzel-kramers-brillouin-approximation/index.pdc b/content/know/concept/wentzel-kramers-brillouin-approximation/index.pdc
new file mode 100644
index 0000000..482650e
--- /dev/null
+++ b/content/know/concept/wentzel-kramers-brillouin-approximation/index.pdc
@@ -0,0 +1,198 @@
+---
+title: "Wentzel-Kramers-Brillouin approximation"
+firstLetter: "W"
+publishDate: 2021-02-22
+categories:
+- Quantum mechanics
+- Physics
+
+date: 2021-02-22T21:38:35+01:00
+draft: false
+markup: pandoc
+---
+
+# Wentzel-Kramers-Brillouin approximation
+
+In quantum mechanics, the **Wentzel-Kramers-Brillouin** or simply the **WKB
+approximation** is a method to approximate the wave function $\psi(x)$ of
+the one-dimensional time-independent Schrödinger equation. It is an example
+of a **semiclassical approximation**, because it tries to find a
+balance between classical and quantum physics.
+
+In classical mechanics, a particle travelling in a potential $V(x)$
+along a path $x(t)$ has a total energy $E$ as follows, which we
+rearrange:
+
+$$\begin{aligned}
+ E = \frac{1}{2} m \dot{x}^2 + V(x)
+ \quad \implies \quad
+ m^2 (x')^2 = 2 m (E - V(x))
+\end{aligned}$$
+
+The left-hand side of the rearrangement is simply the momentum squared,
+so we define the magnitude of the momentum $p(x)$ accordingly:
+
+$$\begin{aligned}
+ p(x) = \sqrt{2 m (E - V(x))}
+\end{aligned}$$
+
+Note that this is under the assumption that $E > V$, which is always the
+case in classical mechanics, but not necessarily so in quantum
+mechanics, but we stick with it for now. We rewrite the Schrödinger
+equation:
+
+$$\begin{aligned}
+ 0
+ = \dv[2]{\psi}{x} + \frac{2 m}{\hbar^2} (E - V) \psi
+ = \dv[2]{\psi}{x} + \frac{p^2}{\hbar^2} \psi
+\end{aligned}$$
+
+If $V(x)$ were constant, and by extension $p(x)$ too, then the solution
+is easy:
+
+$$\begin{aligned}
+ \psi(x)
+ = \psi(0) \exp(\pm i p x / \hbar)
+\end{aligned}$$
+
+This form is reminiscent of the generator of translations. In practice,
+$V(x)$ and $p(x)$ vary with $x$, but we can still salvage this solution
+by assuming that $V(x)$ varies slowly compared to the wavelength
+$\lambda(x) = 2 \pi / k(x)$, where $k(x) = p(x) / \hbar$ is the
+wavenumber. The solution then takes the following form:
+
+$$\begin{aligned}
+ \psi(x)
+ = \psi(0) \exp\!\Big(\!\pm\! \frac{i}{\hbar} \int_0^x \chi(\xi) \dd{\xi} \Big)
+\end{aligned}$$
+
+$\chi(\xi)$ is an unknown function, which intuitively should be related
+to $p(x)$. The purpose of the integral is to accumulate the change of
+$\chi$ from the initial point $0$ to the current position $x$.
+Let us write this as an indefinite integral for convenience:
+
+$$\begin{aligned}
+ \psi(x)
+ = \psi(0) \exp\!\bigg( \!\pm\! \frac{i}{\hbar} \Big( \int \chi(x) \dd{x} - C \Big) \bigg)
+\end{aligned}$$
+
+Where $C = \int \chi(x) \dd{x} |_{x = 0}$ is the initial point of the definite integral.
+For simplicity, we absorb the constant $C$ into $\psi(0)$.
+We can now clearly see that:
+
+$$\begin{aligned}
+ \psi'(x) = \pm \frac{i}{\hbar} \chi(x) \psi(x)
+ \quad \implies \quad
+ \chi(x) = \pm \frac{\hbar}{i} \frac{\psi'(x)}{\psi(x)}
+\end{aligned}$$
+
+Next, we insert this ansatz for $\psi(x)$ into the Schrödinger equation
+to get:
+
+$$\begin{aligned}
+ 0
+ &= \pm \frac{i}{\hbar} \dv{(\chi \psi)}{x} + \frac{p^2}{\hbar^2} \psi
+ = \pm \frac{i}{\hbar} \chi' \psi \pm \frac{i}{\hbar} \chi \psi' + \frac{p^2}{\hbar^2} \psi
+ = \pm \frac{i}{\hbar} \chi' \psi - \frac{1}{\hbar^2} \chi^2 \psi + \frac{p^2}{\hbar^2} \psi
+\end{aligned}$$
+
+Dividing out $\psi$ and rearranging gives us the following, which is
+still exact:
+
+$$\begin{aligned}
+ \pm \frac{\hbar}{i} \chi'
+ = p^2 - \chi^2
+\end{aligned}$$
+
+Next, we expand this as a power series of $\hbar$. This is why it is
+called *semiclassical*: so far we have been using full quantum mechanics,
+but now we are treating $\hbar$ as a parameter which controls the
+strength of quantum effects:
+
+$$\begin{aligned}
+ \chi(x) = \chi_0(x) + \frac{\hbar}{i} \chi_1(x) + \frac{\hbar^2}{i^2} \chi_2(x) + ...
+\end{aligned}$$
+
+The heart of the WKB approximation is its assumption that quantum effects are
+sufficiently weak (i.e. $\hbar$ is small enough) that we only need to
+consider the first two terms, or, more specifically, that we only go up to
+$\hbar$, not $\hbar^2$ or higher. Inserting the first two terms of this
+expansion into the equation:
+
+$$\begin{aligned}
+ \pm \frac{\hbar}{i} \chi_0'
+ &= p^2 - \chi_0^2 - 2 \frac{\hbar}{i} \chi_0 \chi_1
+\end{aligned}$$
+
+Where we have discarded all terms containing $\hbar^2$. At order
+$\hbar^0$, we then get the expected classical result for $\chi_0(x)$:
+
+$$\begin{aligned}
+ 0 = p^2 - \chi_0^2
+ \quad \implies \quad
+ \chi_0(x) = p(x)
+\end{aligned}$$
+
+While at order $\hbar$, we get the following quantum-mechanical
+correction:
+
+$$\begin{aligned}
+ \pm \frac{\hbar}{i} \chi_0'
+ = - 2 \frac{\hbar}{i} \chi_0 \chi_1
+ \quad \implies \quad
+ \chi_1(x) = \mp \frac{1}{2} \frac{\chi_0'(x)}{\chi_0(x)}
+\end{aligned}$$
+
+Therefore, our approximated wave function $\psi(x)$ currently looks like
+this:
+
+$$\begin{aligned}
+ \psi(x)
+ &\approx \psi(0) \exp\!\Big( \!\pm\! \frac{i}{\hbar} \int \chi_0(x) \dd{x} \Big) \exp\!\Big( \!\pm\! \int \chi_1(x) \dd{x} \Big)
+\end{aligned}$$
+
+We can reduce the latter exponential using integration by substitution:
+
+$$\begin{aligned}
+ \exp\!\Big( \!\pm\! \int \chi_1(x) \dd{x} \Big)
+ &= \exp\!\Big( \!-\! \frac{1}{2} \int \frac{\chi_0'(x)}{\chi_0(x)} \dd{x} \Big)
+ = \exp\!\Big( \!-\! \frac{1}{2} \int \frac{1}{\chi_0}\:d\chi_0 \Big)
+ \\
+ &= \exp\!\Big( \!-\! \frac{1}{2} \ln\!\big(\chi_0(x)\big) \Big)
+ = \frac{1}{\sqrt{\chi_0(x)}}
+ = \frac{1}{\sqrt{p(x)}}
+\end{aligned}$$
+
+In the WKB approximation for $E > V$, the solution $\psi(x)$ is thus
+given by:
+
+$$\begin{aligned}
+ \boxed{
+ \psi(x) \approx \frac{A}{\sqrt{p(x)}} \exp\!\Big( \!\pm\! \frac{i}{\hbar} \int p(x) \dd{x} \Big)
+ }
+\end{aligned}$$
+
+What if $E < V$? In classical mechanics, this is not allowed; a ball
+cannot simply go through a potential bump without the necessary energy.
+However, in quantum mechanics, particles can **tunnel** through barriers.
+
+Conveniently, all we need to change for the WKB approximation is to let
+the momentum take imaginary values:
+
+$$\begin{aligned}
+ p(x) = \sqrt{2 m (E - V(x))} = i \sqrt{2 m (V(x) - E)}
+\end{aligned}$$
+
+And then take the absolute value in the appropriate place in front of
+$\psi(x)$:
+
+$$\begin{aligned}
+ \boxed{
+ \psi(x) \approx \frac{A}{\sqrt{|p(x)|}} \exp\!\Big( \!\pm\! \frac{i}{\hbar} \int p(x) \dd{x} \Big)
+ }
+\end{aligned}$$
+
+In the classical region ($E > V$), the wave function oscillates, and
+in the quantum-mechanical region ($E < V$) it is exponential. Note that for
+$E \approx V$ the approximation breaks down, due to the appearance of
+$p(x)$ in the denominator.
diff --git a/content/uses.md b/content/uses.md
new file mode 100644
index 0000000..fec4977
--- /dev/null
+++ b/content/uses.md
@@ -0,0 +1,110 @@
+---
+title: "Things I use"
+date: 2021-02-23T16:16:18+01:00
+draft: false
+---
+
+# Things I use
+
+## Server
+* [Alpine Linux](https://alpinelinux.org/):
+ Minimalist distribution powered by
+ [BusyBox](https://www.busybox.net/) and [musl](https://musl.libc.org/).
+ It has a large-enough selection of both cutting-edge
+ and stable packages to be practical.
+* [nginx](https://nginx.org/):
+ Fast, secure and popular HTTP server,
+ and a breeze to set up.
+* [OpenSMTPD](https://opensmtpd.org/):
+ Email SMTP server by the venerable [OpenBSD](https://www.openbsd.org/) project,
+ and the only one of its kind that nails the setup experience.
+* [Dovecot](https://dovecot.org/):
+ One of the, if not *the* most popular email IMAP server.
+ And for good reason: it's fast, secure, and a pleasure to set up.
+* [Rspamd](https://www.rspamd.com/):
+ Spam filter for email.
+ To be honest, I haven't looked into this one much.
+ It has lots of advanced features that I barely understand,
+ but still seems to be the most modern and usable spam filter out there.
+* [Zola](https://www.getzola.org/):
+ Straightforward static site generator written in Rust.
+ The only thing it's missing is some kind of LaTeX formula support,
+ which is why I migrated to Hugo.
+* [Hugo](https://gohugo.io/):
+ Another good static site generator, although not as good as Zola in my opinion.
+* [cgit](https://git.zx2c4.com/cgit/about/):
+ JavaScript-free online Git frontend,
+ perfect for private setups.
+ If you need something more advanced like user accounts,
+ [Gitea](https://gitea.io) is a good choice too.
+* [acme.sh](https://github.com/acmesh-official/acme.sh):
+ Straightforward tool to manage TLS certificates
+ issued by [Let's Encrypt](https://letsencrypt.org/).
+
+
+## Desktop
+* [Arch Linux](https://www.archlinux.org/):
+ The distribution that, for me, delivers the best cost-benefit ratio.
+ I'm not a big fan of [systemd](https://freedesktop.org/wiki/Software/systemd/)
+ or [glibc](https://www.gnu.org/software/libc/),
+ but the fantastic package manager and the huge repositories
+ make Arch Linux unbeatable for working techies' day-to-day computing.
+* [i3](https://i3wm.org/) and [Sway](https://swaywm.org/):
+ Lightweight window managers.
+ Once you go tiling, you can never go back.
+* [Firefox](https://www.mozilla.org/en-US/firefox/):
+ Web browsers suck.
+ This ones sucks the least, and is developed by Mozilla,
+ who still seem to care about privacy and security, and
+ who created the [Rust](https://www.rust-lang.org/) language.
+ Firefox has all the necessary modern features,
+ and provides an excellent curated set of add-ons.
+* [Thunderbird](https://www.thunderbird.net/):
+ Email clients suck, just like email itself.
+ This one just sucks less, since it's also made by Mozilla.
+* [Alacritty](https://github.com/alacritty/alacritty):
+ Simple, lightning-fast terminal emulator with
+ extra goodies like 24-bit colours
+ and live configuration reloading.
+* [Neovim](https://neovim.io/):
+ A modernized fork of the venerable [Vim](https://www.vim.org/) text editor.
+* [pass](https://www.passwordstore.org/):
+ Password manager for techies.
+ It's simple, secure, transparent, and extensible.
+* [Anki](https://ankiweb.net/about):
+ Flashcard studying software,
+ with a big [library](https://ankiweb.net/shared/decks/) of community-made decks.
+ Frankly it's not very user-friendly, but it does the job.
+* [Veusz](https://veusz.github.io/):
+ Fanstastic plotting software,
+ and one of the most underrated open-source tools that I know of.
+ It gives beautiful plots, can handle *huge* data files, and,
+ because its files are just plain Python,
+ you can automatically generate plots with a bit of scripting.
+
+
+## Browser add-ons
+* [uBlock Origin](https://addons.mozilla.org/en-US/firefox/addon/ublock-origin/):
+ The best adblocker out there. It's free *and* open-source!
+
+
+## Android
+* [Aegis](https://getaegis.app/):
+ Secure open-source 2FA authenticator app.
+* [Shelter](https://f-droid.org/en/packages/net.typeblog.shelter/):
+ Isolates untrusted apps in an Android Work Profile.
+* [AnkiDroid](https://f-droid.org/en/packages/com.ichi2.anki/):
+ Good mobile frontend for [Anki](https://ankiweb.net/about).
+
+
+## Online services
+* [Gandi](https://www.gandi.net/):
+ European domain registrar with the motto
+ "No bullshit since 1999". They provide an honest,
+ high-quality service at a competitive price.
+ This statement is not sponsored.
+* [Let's Encrypt](https://letsencrypt.org/):
+ Provides free TLS encryption certificates
+ to anybody who asks politely, thereby making
+ online security more accessible for small sites like this one.
+