% 02/20/94
% $Id: tutorial.tex,v 1.18 2002/04/22 16:32:22 ellard Exp $
%

\chapter{An {\sc Ant-8} Tutorial}

This section is a tutorial for {\sc Ant-8} assembly language
programming and the {\sc Ant-8} environment.
This chapter covers the basics of {\sc Ant-8} assembly language,
including arithmetic operations, simple I/O, conditionals, loops,
and accessing memory.

\section{What is Assembly Language?}
\index{assembly}

Computer instructions are represented, in a computer, as sequences of
bits.  Generally, this is the lowest possible level of representation
for a program-- each instruction is equivalent to a single,
indivisible action of the CPU.  This representation is called {\em
machine language}, and it is the only form that can be ``understood''
directly by the computer.

A slightly higher-level representation (and one that
is much easier for humans to use) is called {\em assembly language}.
Assembly language is very closely related to machine language,
and there is usually a straightforward way to translate
programs written in assembly language into machine language.
(This translation is usually implemented by a program called
an {\em assembler}.)
Assembly language is usually a direct translation of the
machine language; one instruction in assembly language
corresponds to one instruction in the machine language.

Because of the close relationship between machine and assembly
languages, each different machine architecture usually has its own assembly
language (in fact, a particular architecture may have several),
and each is unique.

\section{Getting Started with {\sc Ant-8} Assembly: {\tt add.asm}}
\index{add.asm}

To get our feet wet, we'll write an assembly language program named
{\tt add.asm} that computes the sum of 1 and 2.  Although this task is
simple, in order to accomplish it we will need to explore several key
concepts in {\sc Ant-8} assembly language programming.

\subsection{Registers}

Like many modern CPU architectures, the {\sc Ant-8} CPU can only operate
directly on data that is stored in special locations called {\em
registers}.  The {\sc Ant-8} architecture has 16 registers, named {\tt r0}
through {\tt r15}.  Each of these registers can hold a single value.
Two of these registers have special purposes:
register zero ({\tt r0}) always contains the value zero, and register
one ({\tt r1}) is used to hold useful values computed as part of the
most recently executed instruction.

While most modern computers have many megabytes of memory, it is
unusual for a computer to have more than a few dozen registers.  Since
most computer programs use much more data than can fit into these
registers, it is usually necessary to juggle the data back and forth
between memory and the registers, where it can be operated upon by the
CPU.  (The first few programs that we write will only use registers,
but in section \ref{load-store-sec} the use of memory is introduced.)

\subsection{Commenting}
\index{commenting}

Before we start to write the executable statements of
our program, however, we'll need to write a comment that describes
what the program is supposed to do.  In the {\sc Ant-8} assembly language,
any text between a pound sign ({\tt \#}) and the subsequent newline
is considered to be a comment, and is ignored by the assembler.
Good comments are absolutely essential!
Assembly language programs are notoriously difficult to read
unless they are well organized and properly documented.

Therefore, we start by writing the following:

{\codesize
\begin{verbatim}
# Dan Ellard -- 11/2/96
# add.asm-- A program that computes the sum of 1 and 2,
#       leaving the result in register r2.
# Registers used:
# r2 - used to hold the result.

# end of add.asm
\end{verbatim}}

Even though this program doesn't actually do anything yet, at least
anyone reading our program will know what this program is supposed to do,
and who to blame if it doesn't work\footnote{
You should put your own name on your own programs, of course;
Dan Ellard shouldn't take all the blame.}.

Unlike programs written in higher level languages, it is usually
appropriate to comment every line of an assembly language program,
often with seemingly redundant comments.  Uncommented code that seems
obvious when you write it will be baffling a few hours later.  While a
well-written but uncommented program in a high level language might be
relatively easy to read and understand, even the most well-written
assembly code is unreadable without appropriate comments.  Some
programmers prefer to add comments that paraphrase the steps performed
by the assembly instructions in a higher-level language.

We are not finished commenting this program,
but we've done all that we can do until we know a little more about
how the program will actually work.

\subsection{Finding the Right Instructions}

Next, we need to figure out what instructions the computer will need
to execute in order to add two numbers.  Since the {\sc Ant-8} architecture
has very few instructions, it won't be long before you have memorized
all of the instructions that you'll need, but as you are getting
started you'll need to spend some time browsing through the list of
instructions, looking for ones that you can use to do what you want.
A table of all of the instructions is given in figure
\ref{mnemonic-table}, on page \pageref{mnemonic-table}.

Luckily, as we look through the list of instructions, the very first
instruction we come across is the {\tt add} instruction, which adds
two numbers together.

The {\tt add} instruction takes three operands, which must appear
in the following order:

\begin{enumerate}

\item A register that will be used to hold the result of the addition.
	For our program, this will be {\tt r2}.

\item A register that contains the first number to be added.
	Therefore, we're going to have to place the value 1 into a
	register before we can use it as an operand of {\tt add}.
	Checking the list of registers used by this program (which is
	an essential part of the commenting) we select {\tt r3}, and
	make note of this in the comments.

\item A register that holds the second number to be added.  We're also
	going to have to place the value 2 into a register before we
	can use it as an operand of {\tt add}.  Checking the list of
	registers used by this program we select {\tt r4}, and make
	note of this in the comments.

\end{enumerate}

We now know how we can add the numbers, but we have to figure out how
to place 1 and 2 into the appropriate registers.  To do this, we can
use the {\tt lc} (load constant value) instruction, which places an
8-bit constant into a register.  Therefore, we arrive at the following
sequence of instructions:

{\codesize
\begin{verbatim}
# Dan Ellard -- 11/2/96
# add.asm-- A program that computes the sum of 1 and 2,
#       leaving the result in register r2.
# Registers used:
# r2 - used to hold the result.
# r3 - used to hold the constant 1.
# r4 - used to hold the constant 2.

        lc      r3, 1           # r3 = 1
        lc      r4, 2           # r4 = 2
        add     r2, r3, r4      # r2 = r3 + r4.

# end of add.asm
\end{verbatim}}

\subsection{Completing the Program}

These three instructions perform the calculation that we want, but
they do not really form a complete program.  We have told the
processor what we want it to do, but we have not told it to stop
after it has done it!

{\sc Ant-8} programs always begin executing at the first instruction in
the program.  There is no rule for where the program ends, however,
and if not told otherwise the {\sc Ant-8} processor will read past the
end of the program, interpreting whatever it finds as instructions and
trying to execute them.  It might seem sensible (or obvious) that the
processor should stop executing when it reaches the ``end'' of the
program (in this case, the {\tt add} instruction on the last line), but
there are some situations where we might want the program to continue
past the ``end'' of the program, or stop before it reaches the end.
Therefore, the {\sc Ant-8} architecture contains an instruction named
{\tt hlt} that {\em halts} the processor.

The {\tt hlt} instruction does not take any operands.
(For more information about {\tt hlt}, consult Figure
\ref{mnemonic-table} on page \pageref{mnemonic-table}.)

\index{add.asm (complete listing)}
\input{Tutorial/add}

\subsection{The Format of {\sc Ant-8} Assembly Programs}

As you read {\tt add.asm}, you may notice several formatting
conventions-- every instruction is indented,
and each line contains at most one instruction.  These conventions are
{\em not} simply a matter of style, but are actually part of the
definition of the {\sc Ant-8} assembly language.

The first rule of {\sc Ant-8} assembly formatting is that instructions {\em
must} be indented.  Comments do not need to be indented, but all of
the code itself must be.  The second rule of {\sc Ant-8} assembly formatting
is that only one instruction can appear on each line.  (There are a
few additional rules, but these will not be important until section
\ref{Labels-subsec}.)

Unlike many programming languages, where the use of whitespace and
formatting is largely a matter of style, in {\sc Ant-8} assembly language some
use of whitespace is required.

\subsection{Running {\sc Ant-8} Assembly Language Programs}

At this point, we should have a working program.  Now, it's time to
run it and see what happens.

There are two principal ways of running an {\sc Ant-8} program-- using
the commandline tools ({\tt aa8}, {\tt ad8} and {\tt ant8}), or using
{\sc AIDE8} (the {\sc Ant-8} Integrated Development Environment).

\subsubsection{Using the Commandline Tools}

Before the commandline tools can run on a program, the program
must be written in a file.  This file must be plain text, and by
convention {\sc Ant-8} assembly language files have a suffix of {\tt .asm}.
In this example, we will assume that the file {\tt add.asm} contains
a copy of the {\tt add} program listed earlier.

Before we can run the program, we must {\em assemble} it.  The
assembler translates the program from the assembly language
representation to the machine language representation.  The assembler
for {\sc Ant-8} is called {\tt aa8}, so the appropriate command would be:

\begin{verbatim}
        aa8 add.asm
\end{verbatim}

This will create a file named {\tt add.ant} that contains
the {\sc Ant-8} machine-language representation of the program in
{\tt add.asm}.

Now that we have the assembled version of the program,
we can test it by loading it into the {\sc Ant-8} debugger in
order to execute it.
The name of the {\sc Ant-8} debugger is {\tt ad8}, so to run the debugger,
use the {\tt ad8} command followed
by the name of the machine language file to load.
For example, to run the program that we just wrote
and assembled:

\begin{verbatim}
        ad8 add.ant
\end{verbatim}

After starting, the debugger will display the following
prompt: {\tt >>}.
Whenever you see the {\tt >>} prompt, you know that the debugger
is waiting for you to specify a command for it to execute.

Once the program is loaded, you can use the {\tt r} (for {\em run})
command to run it:
\begin{verbatim}
        >> r
\end{verbatim}

The program runs, and then the debugger indicates that it is ready to
execute another command.  Since our program is supposed to
leave its result in register {\tt r2}, we can verify that the
program is working by asking the debugger to print out the contents of
the registers using the {\tt p} (for {\em print}) command,
to see if it contains the result we expect:

{\codesize
\begin{verbatim}
>> p
 r01  r02  r03  r04  r05  r06  r07  r08  r09  r10  r11  r12  r13  r14  r15
  00   03   01   02   00   00   00   00   00   00   00   00   00   00   00
   0    3    1    2    0    0    0    0    0    0    0    0    0    0    0
\end{verbatim}}

The {\tt p} command displays the contents of each register.
The first line lists the register names.  The following line
lists the value of each register in hexadecimal, and the
last line lists the same number in decimal.

The {\tt q} command exits the debugger.

{\tt ad8} includes a number of features that will make debugging your
{\sc Ant-8} assembly language programs much easier.  Type {\tt h} (for {\em help})
at the
{\tt >>} prompt for a full list of the {\tt ad8} commands, or consult the
{\tt ad8} documentation for more information.

\subsubsection{Using {\sc AIDE8}}

{\sc AIDE8} provides a more tightly integrated way of creating,
debugging, and running {\sc Ant-8} programs.  Although it is less
flexible than running each of the tools individually, for most users
it is more than sufficient.

When {\sc AIDE8} starts, only the editor window is shown.  This window
can be used to create or edit an {\sc Ant-8} program.  After the program
is written, it can be assembled by pressing the {\bf Assemble} button.
If the assembly process is successful, no error messages will be
displayed; otherwise, the cause of the error is printed at the bottom
of the screen and the offending line of the program is highlighted.

Once the program has been written and assembled, pressing the {\bf
Debug} button brings up the debugger window.  The debugger window
displays the complete state of the {\sc Ant-8} machine.  (The debug
window can be displayed at any time, even if there isn't a program
loaded into the {\sc Ant-8} machine, but without a program to display
there isn't much to see.)

To simply run the program, click on the {\bf Run} button in the
upper-left corner of the debugger window.  The execution of the
program, instruction by instruction, will be displayed in the debugger
window as the state of the processor is updated.

The {\sc AIDE8} contains many other features.  Consult the {\bf Help}
menu of {\sc AIDE8} for more information.

\section{Reading and Printing: {\tt add2.asm}}
\index{add2.asm}
\label{add2-sec}

Our program to compute $1 + 2$ is not particularly useful, although
it does demonstrate a number of important details about programming
in {\sc Ant-8} assembly language and the {\sc Ant-8} environment.  For our next
example, we'll write a program named {\tt add2.asm} that computes
the sum of two numbers specified by the user at runtime,
and displays the result on the screen.

The algorithm this program will use is:
\begin{enumerate}

\item   Read the two numbers from the user.

        We'll need two registers to hold these two numbers.  We will use
        {\tt r3} and {\tt r4} for this.

\item   Compute their sum.

        We'll need a register to hold the result of this addition.  We
        can use {\tt r2} for this.

\item   Print the sum, followed by a newline.

\item   Halt.

	We already know how to do this, using {\tt hlt}.

\end{enumerate}

The only parts of the algorithm that we don't know how to do yet are
to read the numbers from the user, and print out the sum.

{\sc Ant-8} does its I/O (or ``input/output'') using the {\tt in}
instruction to read values from the user into the computer, and
the {\tt out} instruction to display values to the user.

The {\tt in} instruction allows the user to specify values in
one of three different formats:  hexadecimal, binary, or
{\sc ASCII}.  Similarly, the {\tt out} instruction can display a
value in hexadecimal, binary, or {\sc ASCII}.  Note that there is no
way to directly input or output a decimal value!

This gives the following program:

\index{add2.asm (complete listing)}
\input{Tutorial/add2}

\section{Branches, Jumps, and Conditional Execution: {\tt larger.asm}}
\index{branching}
\index{larger.asm}

The next program that we will write will read two numbers from the
user, and print out the larger of the two.  The basic structure of
this program is similar to the one used by {\tt add2.asm}, except
that we're computing the maximum rather than the sum of two numbers.
The difference is that the behavior of this program depends upon the
input, which is unknown when the program is written.
The program must be able to
decide whether to execute instructions to print out the first number
or execute the instructions to print out the second number at runtime.
This is known as {\em conditional execution}-- whether or not certain
parts of program are executed depends on a condition that is not known
when the program is written.

Browsing through the instruction set again, we find a description of
the {\sc Ant-8} branching instructions.  These allow the programmer to specify
that execution should {\em branch} (or {\em jump}) to a location other
than the next instruction.  These instructions allow conditional
execution to be implemented in assembly language (although in not
nearly as clean a manner as higher-level languages provide).

In {\sc Ant-8} assembler, there are three branching instructions:  {\tt
bgt}, {\tt beq} and {\tt jmp}.  {\tt bgt} and {\tt beq} are called
{\em conditional} branches, because they cause the program to branch
when a specific condition holds.  In contrast, the {\tt jmp}
instruction is an {\em unconditional} branch, which is always taken.

The {\tt bgt} instruction takes three registers as arguments.  If the
number in the second register is larger than the number in the third,
then execution will jump to the location specified by the first;
otherwise it continues at the next instruction.

The {\tt beq} instruction is similar in form to the {\tt bgt}
instruction, except that the branch occurs if the second and third
registers contain the same value.

The {\tt jmp} instruction takes a single argument, which is an
unsigned 8-bit constant.  Execution jumps to the location specified by
the constant.

\subsection{Labels}
\label{Labels-subsec}
\index{labels}

Keeping track of the numeric addresses in memory of the instructions
to which we want to branch is troublesome and tedious at best-- a small
error can make our program misbehave in strange ways, and if we change
the program at all by inserting or removing instructions, we will have
have to carefully recompute all of these addresses and then change all
of the instructions that use these addresses.  This is much more than
most humans can possibly keep track of.  Luckily, the computer is very
good at keeping track of details like this, so the {\sc Ant-8} assembler
provides {\em labels}, a human-readable shorthand for addresses.

A {\em label} is a symbolic name for an address in memory.  In {\sc Ant-8}
assembler, a {\em label definition} is an identifier followed by a colon.
{\sc Ant-8} identifiers use the same conventions as Python, Java, C, C++, and
many other contemporary languages:

\begin{itemize}

\item {\sc Ant-8} identifiers must begin with an underscore, an uppercase
	character (A-Z) or a lowercase character (a-z).

\item Following the first character there may be zero or more
	underscores, or uppercase, lowercase, or numeric (0-9)
	characters.  No other characters can appear in an identifier.

\item Although there is no intrinsic limit on the length of {\sc Ant-8}
	identifiers, some {\sc Ant-8} tools may reject identifiers longer than
	100 characters.

\end{itemize}

Labels must be the first item on a line, and must begin in the ``zero
column'' (immediately after the left margin).  Label definitions {\em
cannot} be indented, but all other non-comment lines {\em must} be.

Since labels must begin in column zero, only one label definition is
permitted on each line of assembly language, but a location in memory
may have more than one label.  Giving the same location in memory more
than one label can be very useful.  For example, the same location in
your program may represent the end of several nested ``if''
statements, so you may find it useful to give this instruction several
labels corresponding to each of the nested ``if'' statements.

When a label appears alone on a line, it refers to the following
memory location.  This is often good style, since it allows the use of
long, descriptive labels without disrupting the indentation of the
program.  It also leaves plenty of space on the line for the
programmer to write a comment describing what the label is used for,
which is very important since even relatively short assembly language
programs may have a large number of labels.

\subsection{Branching Using Labels}
\index{branch with labels }

Using the branching instructions and labels we can do what we want in
the {\tt larger.asm} program.  Since the branching instructions take a
register containing an address as their first argument, we need to
somehow load the address represented by the label into a register.  We
do this by using the {\tt lc} ({\em load constant}) command.  The {\tt
larger.asm} program illustrates how this is done.

\input{Tutorial/larger}

Note that since {\sc Ant-8} does not have an instruction to {\em copy} or {\em
move} the contents of one register to another, in order to copy the
value of one register to another register we've added 0 to one
register and put the sum in the destination register in order to
achieve the desired result.  (Recall that register {\tt r0} always
contains the constant zero.)

\section{Looping: {\tt loop.asm}}
\index{looping}
\index{loop.asm}
\label{loop-sec}

In the previous example program, we used the jump and branch
instructions to implement conditional execution, which meant that we
could skip over some instructions depending on the values that the
user typed.  We can also use these instructions to implement {\em
loops}, which allow the program to repeatedly execute a sequence of
instructions an arbitrary number of times.

The next program that we will write will read a character $A$ (as
{\sc ASCII}) and then a number $B$ (as hexadecimal) from the user, and then
print $B$ copies of the character $A$.  This algorithm translates
easily into {\sc Ant-8} assembler; the only thing that is new is that the
execution might jump ``backwards'' in the program to repeat some
instructions more than once.  The {\tt loop.asm} programs shows how
this is done.

\input{Tutorial/loop}

\section{Strings: {\tt hello.asm}}
\index{hello.asm}
\label{hello-sec}
\label{load-store-sec}

The next program that we will write is the ``Hello World'' program,
a program that simply prints the message ``Hello World'' to the screen
and then halts.

There is no way in {\sc Ant-8} to print out more than one character at a
time, so we must use a loop to print out each character of the string,
starting at the beginning and continuing until we reach the end of the
string.

The string ``{\tt Hello World}'' is not part of the instructions of
the program, but it is part of the memory used by the program.  The
assembler places all data values (not instructions) after all of the
instructions in memory.

The value of the data memory is loaded into memory at assembly time.
You will have to be careful to not accidently overwrite your data
during run-time!

The way that the initial contents of data memory are defined is via
the {\tt .byte} directive.  {\tt .byte} looks like an instruction
which takes as many as eight 8-bit constants, but it is not an
instruction at all.  Instead, it is a directive to the assembler to
fill in the next available locations in memory with the given
values.

All of the {\tt .byte} items in an {\sc Ant-8} program must appear at
the end of the program, after the special label {\tt \_data\_}.  The
{\tt \_data\_} label indicates to the assembler that all subsequent
items are data.  No instructions are permitted after the {\tt \_data\_}
label.

In our programs, we will use the following convention for {\sc ASCII}
strings:  a {\em string} is a sequence of characters terminated by a 0
byte.  For example, the string ``hi'' would be represented by the
three characters `h', `i', and 0.  Using a 0 byte to mark the end
of the string is a convenient method, used by several contemporary
languages.

The program {\tt hello.asm} is an example of how to use labels and
treat characters in memory as strings:

\index{hello.asm (complete listing)}
\input{Tutorial/hello}

The label {\tt str\_data} is the symbolic representation of the
memory location where the string begins in data memory.

\section{Character I/O: {\tt echo.asm}}
\index{echo.asm}
\label{echo-sec}
\index{character I/O}

Now that we have mastered loops and reading and printing integers,
we'll turn our attention to reading and printing single characters.
(We've already seen how to read and write numbers, and the process is
similar, except that we use the {\sc ASCII} device instead of {\tt
Hex}.)

The program we'll write in this section simply echos whatever you type
to it, until EOI ({\em end of input}) is reached.

The way that EOI is detected in {\sc Ant-8} is that when the EOI is
reached, any attempt to use {\tt in} to read more input will
immediately fail, and a non-zero value will be placed in register {\tt
r1} to indicate that there was an error.  If the {\tt in} succeeds,
then {\tt r1} is set to zero.

Therefore, our program will loop, continually using {\tt in} to read
characters, and checking {\tt r1} after each {\tt in} to see whether
or not the EOI has been reached.

\input{Tutorial/echo}

{\bf Note:} because of the difference between the user interface of
the debugger in {\sc AIDE8} and the ordinary runtime {\sc Ant-8}
environment, {\tt echo.asm} behaves differently when run under {\sc
AIDE8} than when run via {\tt ant8} or {\tt ad8}.  This is because in
{\sc AIDE8}, every input, including {\sc ASCII} input, must be followed
by a newline, while in ordinary operation {\sc ASCII} input does not.
This should be considered a shortcoming of {\sc AIDE8}, not a problem
with {\tt echo.asm}.

\section{Bit Operations: {\tt shout.asm}}

The next program we shall write is very similar to {\tt echo.asm},
except that instead of simply echoing its input, it converts all of
the lowercase characters in the input to uppercase in the output.

There are several ways that this could be accomplished.  The easiest
way, and one that does not require learning about any new {\sc Ant-8}
instructions, would be to note that all of the lowercase characters in
{\sc ASCII} are arranged consecutively, starting with {\tt 'a'} (with
a value of {\tt 0x61}) and continuing through {\tt 'z'} (with a value
of {\tt 0x7A}).  The uppercase characters are arranged in the same
manner, ranging from {\tt 'A'} = {\tt 0x41} to {\tt 'Z'} = {\tt 0x5A}.
Therefore, in order to convert from uppercase to lowercase all we need
to do is take any characters that have {\sc ASCII} codes in the range
{\tt 0x61} to {\tt 0x7A} and subtract {\tt 0x20} from them before
printing them.

However, our goal in this section is to learn about {\sc Ant-8}'s
bitwise instructions, and so we use a different observation-- the {\tt
ASCII} code for the lowercase characters and the corresponding
uppercase characters differ only in a single bit.  All the lowercase
characters have the bit corresponding to {\tt 0x20} set to 1, while
all the uppercase characters do not.  Therefore, if we have a
lowercase character, in order to convert it to uppercase all we need to
do is set this bit to 0.  The bit we are interested in is the fifth
bit (counting from the right and starting at zero).

To change the fifth bit from 1 to 0, we can use the {\tt and}
instruction.  If the 8-bit value is in register {\tt r2}, then
computing the bitwise {\sc And} of the value of {\tt r2} and the 8-bit
value value consisting of all 1 bits {\em except} the fifth bit, the
result will be identical to the original value of {\tt r2} except that
the fifth bit will be 0.

We could explicitly compute the value of the 8-bit value that has all
1-bits except for the fifth bit, or we can let the computer do this
work for us.  We choose the latter approach, because this also means
that we can introduce two more instructions, {\tt shf} and {\tt nor}.

Our first task is to initialize {\tt r8} with the 8-bit value
consisting of all zero bits, except for the fifth bit.  (We know this
value is {\tt 0x20}, and so we could simply use this value, but we'll
use {\tt shf} instead:

\begin{verbatim}
        lc      r8, 1           # r8 has all 0 bits, except
                                # bit zero which is 1.
        lc      r9, 5
        shf     r8, r8, r9      # shift the 1 bit over 5 spaces.
                                # r8 is now 0x20.

        nor     r8, r8, r8      # NOR r8 with itself, which changes
                                # all the 1 bits to 0 and vice versa.
                                # r8 is now 0xDF.
\end{verbatim}

The complete program is implemented in {\tt shout.asm}.

\input{Tutorial/shout}

%%% end of tutorial.tex


\documentclass{ximera}
\input{../preamble}
\title{Taylor Series}
%%%%%\author{Philip T. Gressman}

\begin{document}
\begin{abstract}
We introduce the notion of a Taylor Series.
\end{abstract}
\maketitle

\section*{(Video) Calculus: Single Variable}

\youtube{CU1f2cnOfok}

\section*{Online Texts}
\begin{itemize}
\item \link[OpenStax II 6.3: Taylor Series]{https://openstax.org/books/calculus-volume-2/pages/6-3-taylor-and-maclaurin-series}
\item \link[Ximera OSU: Taylor Series]{https://ximera.osu.edu/mooculus/calculus2/introductionToTaylorSeries/titlePage}
\item \link[Community Calculus 11.10: Taylor Series]{https://www.whitman.edu/mathematics/calculus_online/section11.10.html}
\end{itemize}

\section*{Examples}

\begin{example}

\end{example}

\begin{example}

\end{example}

\end{document}


\documentclass[]{article}
% Author: Jonah Miller (jonah.maxwell.miller@gmail.com)
% Time-stamp: <2013-12-14 21:18:33 (jonah)>

% packages
\usepackage{fullpage}
\usepackage{amsmath}
\usepackage{amssymb}
\usepackage{latexsym}
\usepackage{graphicx}
\usepackage{mathrsfs}
\usepackage{verbatim}
\usepackage{braket}
\usepackage{listings}
\usepackage{pdfpages}
\usepackage{listings}
\usepackage{color}
\usepackage{hyperref}

% for the picture environment
\setlength{\unitlength}{1cm}

%preamble
\title{Numerical Explorations of FLRW Cosmologies}

\author{Jonah Miller\\
  \textit{jonah.maxwell.miller@gmail.com}}

\date{General Relativity for Cosmology\\Achim Kempf\\ Fall 2013}

% Macros
\newcommand{\R}{\mathbb{R}} % Real number line
\newcommand{\N}{\mathbb{N}} % Integers
\newcommand{\eval}{\biggr\rvert} %evaluated at
\newcommand{\myvec}[1]{\vec{#1}} % vectors for me
% total derivatives
\newcommand{\diff}[2]{\frac{d #1}{d #2}}
\newcommand{\dd}[1]{\frac{d}{d #1}}
% partial derivatives
\newcommand{\pd}[2]{\frac{\partial #1}{\partial #2}}
\newcommand{\pdd}[1]{\frac{\partial}{\partial #1}}
% t derivatives
\newcommand{\ddt}{\dd{t}}
\newcommand{\dt}[1]{\diff{#1}{t}}
% A 2-vector
\newcommand{\twovector}[2]{\left[\begin{matrix}#1\\#2\end{matrix}\right]}
% A 3 vector.
\newcommand{\threevector}[3]{\left[\begin{matrix} #1\\ #2\\ #3 \end{matrix}\right]}
% Error function
\newcommand{\erf}{\text{erf}}

\begin{document}

\maketitle

% \begin{abstract}
%   In this paper, we numerically investigate the past and future of the
%   night sky. We briefly discuss the origin of the so-called
%   Friedmann-Lemaitre-Robertson-Walker metric, the homogenous,
%   isotropic matter-filled universe. We numerically explore the
%   evolution of the metric given various equations of state of the
%   fluid filling spacetime.
% \end{abstract}

\section{Introduction}
\label{sec:intro}

To attain a picture of the universe as a whole, we must look at it on
the largest possible scales. Since the universe is almost certainly
much larger than the observable universe, or indeed the universe we
will ever observe
\cite{MapOfUniverse,Carroll,MisnerThorneWheeler,Wald}, some guesswork
is necessary \cite{Wald}. The most popular---assumption
used to study the universe as a whole is the \textit{Copernican
  principle} \cite{BonesOfCopernicus}, the notion that, on the larges
scales, the universe looks the same everywhere and in every direction
\cite{Carroll,Wald}.

In modern language, we assume that the universe is homogeneous and
isotropic. That is, we assume that the energy-momentum tensor that
feeds Einstein's equations is the same everywhere and in space and has
no preferred direction
\cite{Carroll,MisnerThorneWheeler,Wald}. Obviously, this isn't the
only approach one can take. Roughly speaking one can generate a
spacetime with an arbitrary amount of symmetry between no symmetry and
maximal symmetry. The homogeneous isotropic universe is almost as
symmetric as one can get. One can add time-like symmetry to attain de
Sitter, anti de Sitter, or Minkowski spacetimes, but that's as
symmetric as you can get
\cite{Carroll,MisnerThorneWheeler,Wald}. Relaxing the symmetry
conditions on the energy-momentum tensor results in, for example, the
mixmaster universe \cite{MisnerThorneWheeler}. However, observational
evidence, most strongly the cosmic microwave background, suggests that
the universe is homogeneous and isotropic to a very high degree
\cite{Planck}.

In this work, we derive the equations governing the evolution of a
homogeneous isotropic universe and numerically explore how such a
universe could evolve. In section \ref{sec:the:metric} we briefly
derive the so-called Friedmann equations, the equations governing such
spacetimes. In section \ref{sec:numerical:approach}, we briefly
discuss the numerical tools we use to evolve these equations. In
section \ref{sec:results}, we present our results. Finally, in section
\ref{sec:conclusion}, we offer some concluding remarks.

\section{The Friedmann-Lemaitre-Robertson-Walker Metric}
\label{sec:the:metric}

First, we derive the metric of a homogenous, isotropic spacetime. Then
we derive the analytic formulae for its evolution. Because we derived
the Friedmann equations using tetrads in class \cite{Kempf}, we
decided to work in coordinates for another perspective.

\subsection{Deriving the Metric}
\label{subsec:metric:derivation}

% The following discussion borrows from \cite{Carroll} and
% \cite{MisnerThorneWheeler}, but mostly from \cite{Wald}. We start by
% putting the words ``homogeneous'' and ``isotropic'' into precise
% language.
% \begin{itemize}
% \item We define a spacetime as \textit{homogeneous} if we can foliate
%   the spacetime by a one-parameter family of spacelike hypersurfaces
%   $\Sigma_t$ such that, for a given hypersurface $\Sigma_{t_0}$ at
%   time $t_0$ and points $p,q\in\Sigma_{t_0}$, there exists an isometry of
%   the four-metric $g_{\mu\nu}$ that maps $p$ into $q$ \cite{Wald}.
% \item We define a spacetime as \textit{isotropic} if at each point
%   there exits a congruence of timelike curves $\alpha$ with tangent vectors
%   $u^\mu$ such that, for any point $p$ in the spacetime and any two
%   space-like vectors $s_1^\mu$ and $s_2^\mu$ orthogonal to $u^\mu$ at
%   $p$, there exists an isometry of $g_{\mu\nu}$ which leaves $p$ and
%   $u^\mu$ at $p$ fixed but changes $s_1^\mu$ and $s_2^\mu$
%   \cite{Wald}.
% \end{itemize}
% Note that if a universe is \textit{both} homogeneous \textit{and}
% isotropic, the foliating hypersurfaces $\Sigma_t$ must be orthogonal
% to the timelike tangent vector field $u^\mu$ \cite{Wald}. Otherwise,
% it is possible to use proof by contradiction to show that the isometry
% guaranteed by isotropy cannot exist \cite{Wald}. This gives us a piece
% of a canonical coordinate system to use. We define the parameter
% indexing our hypersurfaces as time $t$.
%
% On each spacelike hypersurface in our foliation, we can restrict the
% full Lorentzian four-metric $g_{\mu\nu}$ to a Riemannian three-metric
% $h_{ij}$. Because of homogeneity, there must exist a sufficient number
% of isometries of $h_{ij}$ to map every point in the hypersurface into
% every other point \cite{Wald}. Because of isotropy, it must be impo

The following discussion borrows from \cite{Carroll},
\cite{MisnerThorneWheeler}, and \cite{Wald}. However, we mostly follow
\cite{Carroll}. It is possible to rigorously and precisely define the
notions of homogeneous and isotropic \cite{Wald}. However, one can
prove that homogenous and isotropic spacetimes are foliated by
maximally symmetric spacelike hypersurfaces
\cite{Carroll}. Intuitively, at least, it's not hard to convince
oneself that homogeneity and isotropy are sufficient to enforce
maximal symmetry. There are three classes of such hypersurfaces all of
constant scalar curvature: spherical spaces, hyperbolic spaces, and
flat spaces. Spherical spaces have constant positive
curvature. Hyperbolic spaces have constant negative curvature, and
flat spaces have zero curvature \cite{Carroll}.

% \begin{figure}[htb]
%   \begin{center}
%     \leavevmode
%     \includegraphics[width=\textwidth]{figures/comparison_of_curvatures.png}
%     \caption{A two-dimensional spacelike hypersurface with positive
%       curvature (left), negative curvature (middle) and no curvature
%       (right).}
%     \label{fig:spacelike:curvatures}
%   \end{center}
% \end{figure}
Let us consider a homogenous, isotropic, four-dimensional Lorentzian
spacetime. We can write the metric as \cite{Carroll}
\begin{equation}
  \label{eq:hom:iso:most:general}
  ds^2 = -dt^2 + a^2(t) d\sigma^2,
\end{equation}
where $t$ is the time coordinate, $a(t)$ is a scalar function known as
the \textit{scale factor}, and $d\sigma^2$ is the metric of the
maximally symmetric spacelike hypersurface. Up to some overall scaling
(which we can hide in $a(t)$, we have \cite{Wald}
\begin{equation}
  \label{eq:3-metric}
  d\sigma^2 = \begin{cases}
    d\chi^2 + \sin^2(\chi)(d\theta^2 + \sin^2(\theta)d\phi^2)&\text{for positive curvature}\\
    d\chi^2 + \chi^2(d\theta^2 + \sin^2d\phi^2)&\text{for no curvature}\\
    d\chi^2 + \sinh^2(\chi)(d\theta^2 + \sin^2(\theta)d\phi^2)&\text{for negative curvature}
    \end{cases},
\end{equation}
where $\chi$, $\theta$, and $\phi$ are the usual spherical
coordinates. However, if we choose $r$ such that
\begin{equation}
  \label{eq:def:rho}
  d\chi = \frac{dr}{\sqrt{1 - k r^2}},
\end{equation}
where
\begin{equation}
  \label{eq:k:range}
  k\in\{-1,0,1\}
\end{equation}
is the normalized scalar curvature of the hypersurface, we can
renormalize our equation to put it in a nicer form
\cite{Carroll,MisnerThorneWheeler},
\begin{equation}
  \label{eq:friedmann:equation}
  ds^2 = -dt^2 + a^2(t)\left[\frac{dr^2}{1 - k r^2} + r^2 d\Omega^2\right],
\end{equation}
where
\begin{equation}
  \label{eq:def:domega}
  d\Omega = d\theta^2 + \sin^2(\theta) d\phi^2
\end{equation}
is the angular piece of the metric. This is known as the
\textit{Friedmann-Lemaitre-Roberston-Walker} (FRLW) metric.

\subsection{Evolution and the Friedmann Equation}
\label{subsec:metric:evolution}

The following discussion draws primarily from the lecture notes
\cite{Kempf}, specifically lecture 16. If we calculate the Einstein
tensor
\begin{equation}
  \label{eq:def:einstein:tensor}
  G_{\mu\nu} = R_{\mu\nu} - \frac{1}{2} R g_{\mu\nu}
\end{equation}
(using, e.g., a tool like Maple's differential geometry package
\cite{Maple}) in the frame induced by our choice of coordinates, we
find that it is diagonal \cite{Kempf}:\footnote{We write the tensor as
  a linear operator with one raised index because this produces the
  nicest form of the equations.}
\begin{eqnarray}
  \label{eq:einstein:tensor:calculated:tt}
  G^t_{\ t} &=& -3 \frac{k + \dot{a}^2}{a^2}\\
  \label{eq:einstein:tensor:calculated:space}
  G^i_{\ i} &=& - \frac{k + 2a\ddot{a} + \dot{a}^2}{a^2} \ \forall\ i\in\{1,2,3\},\\
  \label{eq:einstein:tensor:off:diagonal}
  G^{\mu}_{\ \nu} &=& 0\  \forall\ \mu\neq\nu
\end{eqnarray}
where we have suppressed the $t$-dependence of $a$ and where $\dot{a}$
is a time-derivative of $a$ in the usual way.

If we feed the Einstein tensor into Einstein's equation in geometric units,
\begin{equation}
  \label{eq:einsteins:equation:1}
  G_{\mu \nu} = 8\pi \tilde{T}_{\mu\nu} - \Lambda g_{\mu\nu},
\end{equation}
since $g_{\mu\nu}$ is diagonal, we see that $T^\mu_{\ \nu}$ must be
diagonal too. Indeed, with one index raised, it looks like the
energy-momentum tensor for a perfect fluid in its rest frame:
\begin{eqnarray}
  T^{\mu}_{\ \nu} &=& \tilde{T}^{\mu}_{\ \nu} - \frac{\Lambda}{8\pi}\mathcal{I}\nonumber\\
  \label{eq:T:mu:nu}
  &=& \left[\begin{array}{cccc}-\rho&0&0&0\\0&p&0&0\\0&0&p&0\\0&0&0&p\end{array}\right] - \frac{\Lambda}{8\pi} \left[\begin{array}{cccc}1&0&0&0\\0&1&0&0\\0&0&1&0\\0&0&0&1\end{array}\right],
\end{eqnarray}
where $\mathcal{I}$ is the identity operator, $\rho$ is the density of
the fluid, and $p$ is the pressure of the fluid. $\tilde{T}^0_{\ 0}$
is negative because we've raised one index. Obviously, this is just a
mathematical coincidence, and we've even manipulated our definition of
pressure to hide our choice of coordinates. However, one can make weak
physical arguments to justify it \cite{Carroll,MisnerThorneWheeler}.

The time-time component of Einstein's equation
\eqref{eq:einsteins:equation:1} then gives the first Friedmann equation \cite{Carroll,MisnerThorneWheeler,Kempf}:
\begin{equation}
  \label{eq:Friedmann:1:orig}
  \frac{\dot{a}^2 + k}{a^2} = \frac{8\pi \rho + \Lambda}{3}.
\end{equation}
Any space-space diagonal component gives a second equation
\cite{Carroll,MisnerThorneWheeler,Kempf}:
\begin{equation}
  \label{eq:einstein:2}
  - \frac{k + 2a\ddot{a} + \dot{a}^2}{a^2} = 8\pi p + \Lambda.
\end{equation}
Now we take
\begin{equation}
  \label{eq:trace:condition}
  -\frac{1}{2} a \left[\left(\text{equation \eqref{eq:Friedmann:1:orig}}\right) + \frac{1}{3}\left(\text{equation \eqref{eq:einstein:2}}\right)\right],
\end{equation}
which yields
\begin{equation}
  \label{eq:Friedmann:2:orig}
  \frac{\ddot{a}}{a} = -\frac{4\pi}{3} \left(\rho + 3 p\right) + \frac{\Lambda}{3},
\end{equation}
which is the second Friedmann equation \cite{Kempf}. To use these
equations to describe an FLRW universe, we need one more piece of
information: the relationship between density and pressure, called an
equation of state \cite{Carroll,MisnerThorneWheeler,Kempf}. We
parametrize our ignorance of the equation of state as
\begin{equation}
  \label{eq:def:eos}
  p = \omega(\rho) \rho,
\end{equation}
where $\omega(\rho)$ is some scalar function.

Finally, we hide the cosmological constant as a type of matter, which
we call dark matter. This corresponds to resetting
\begin{equation}
  \label{eq:rho:transformation}
  \rho\to\rho - \frac{\Lambda}{8\pi}.
\end{equation}
In this case, the Friedmann equations are
\begin{eqnarray}
  \label{eq:Friedmann:1}
  \frac{\dot{a}^2 + k}{a^2} &=& \frac{8\pi}{3}\rho\\
  \label{eq:Friedmann:2}
  \frac{\ddot{a}}{a} &=& -\frac{4\pi}{3} \left(\rho + 3 p\right).
\end{eqnarray}
Then a cosmological constant corresponds to an energy density that
does not dilute with time... and one with negative pressure. Unless
otherwise stated, we will make this choice.

In the simple case when $\omega$ is a constant, we get several
different regimes. In the case of $\omega \geq 0$, as for a
radiation-dominated or matter-dominated universe
\cite{MisnerThorneWheeler,Carroll,Kempf},\footnote{If $\omega=0$, we
  have a matter-dominated universe where the density scales as one
  over the scale factor cubed, in other words, one over volume. If
  $\omega=1/3$, we have a radiation-dominated universe, where the
  density scales as one over the scale factor to the fourth. The extra
  scaling of the scale factor is due to cosmological redshift
  \cite{Carroll,Kempf}.} the scale factor increases monotonically and
at a decelerating rate \cite{MisnerThorneWheeler,Carroll,Kempf}. In
the case of $\omega = -1$, one gets a dark-energy dominated universe
with accelerating expansion
\cite{MisnerThorneWheeler,Carroll,Kempf}. And if $\omega$ is simply
very close to $-1$, one gets an inflationary universe
\cite{MisnerThorneWheeler,Carroll,Kempf}. As a test, will numerically
explore the cases when $\omega$ is constant and we have a known
regime. We will also numerically explore the cases when $\omega$ is a
more sophisticated object.

\section{Numerical Approach}
\label{sec:numerical:approach}

In any numerical problem, there are two steps. The first is two frame
the problem in a way compatible with numerical methods. The second
step is to actually design and implement a method. To limit our
problem domain, from here on out, we assume that
\begin{equation}
  \label{eq:def:k}
  k = 0.
\end{equation}

\subsection{Framing the Problem}
\label{subsec:framing:the:problem}

We will use a numerical algorithm to solve initial value
problems. These algorithms are usually formulated as first order ODE
solvers. The ode is written in the form
\begin{equation}
  \label{eq:ode:formulation}
  \diff{\myvec{y}}{t} = \myvec{f}(y,t)\text{ with }\myvec{y}(0) = \myvec{y}_0,
\end{equation}
where $\myvec{y}$ is a vector containing all the functions of $t$ one
wishes to solve for. Let's see if we can't write the Friedmann
equations in such a form.

Our first step is to reduce the second-order ODE system to a
first-order system. We will do this by eliminating $\ddot{a}$ in favor
of some other variable. If we differentiate equation
\eqref{eq:Friedmann:1}, we get
\begin{equation}
  \label{eq:dF1}
  -2 \frac{\dot{a}^2}{a^3} + \frac{\ddot{a}}{a^2} = \frac{8\pi}{3}\dot{\rho}.
\end{equation}
We can substitute $\ddot{a}$ in from \eqref{eq:Friedmann:2} to obtain
an equation for the time evolution of $\rho$:
\begin{equation}
  \label{eq:Friedmann:rho}
  \dot{\rho} = - 3 \left(\frac{\dot{a}}{a}\right)\left(\rho + p\right),
\end{equation}
which expresses conservation of mass energy. As a last step, we use
equation \eqref{eq:Friedmann:1} and equation \eqref{eq:def:eos} to
eliminate $\dot{a}$ and $p$ from equation \eqref{eq:Friedmann:rho} to
attain an evolution equation for $\rho$:
\begin{equation}
  \label{eq:rho:evolution}
  \dot{\rho} = \mp 3\left[\rho + \omega(\rho)\rho\right]\sqrt{\frac{8\pi}{3}\rho-k}.
\end{equation}

So, putting it all together, if we define the two-vector
\begin{equation}
  \label{eq:def:y}
  \myvec{y}(t) = \twovector{a(t)}{\rho(t)},
\end{equation}
then we can write the equations governing the evolution of the
universe as
\begin{equation}
  \label{eq:y:prime:orig}
  \ddt \myvec{y}(t) = \myvec{f}(y)
  = \pm\twovector{\sqrt{8\pi a^2\rho/3}}{-3\left(\rho + \omega(\rho)\rho\right)\sqrt{\frac{8\pi}{3}\rho-k}}.
\end{equation}
Since our universe is expanding and we're interested in an expanding
universe, we choose $\dot{a}>0$. This gives us
\begin{equation}
  \label{eq:y:prime}
  \myvec{f}(y) = \twovector{\sqrt{8\pi a^2\rho/3}}{-3\left(\rho + \omega(\rho)\rho\right)\sqrt{\frac{8\pi}{3}\rho-k}}.
\end{equation}

\subsection{Initial Data}
\label{subsec:initial:data}

Even with evolution equations, we're still missing some critical
information. A first-order ODE system needs one initial value for each
unknown function.

Obviously, equation \eqref{eq:y:prime} breaks down when the scale
factor is zero. Therefore we must be careful to avoid starting a
simulation too close to the big bang singularity. For this reason, we
will never assume that $a(0) = 0$. If convenient, we will choose
$a(0)$ to be close to zero. There is one exception, which is the case
of a dark-energy dominated universe, where we will choose $a(0)=1$,
since such a universe is exponentially growing.

We still need to choose a value for $\rho(0)$, however, so long as
$\rho(0) > 0$, we should expect it to not matter much. General
relativity is invariant under an overall re-scaling of energy
\cite{MisnerThorneWheeler,Wald}. However, to get a better idea of
qualitative behavior, we will chose a number of values of $\rho(0)$ in
each case.

\subsection{Numerical Method}
\label{subsec:numerical:method}

For a given $\omega(\rho)$ and set of initial data, we solve the ODE
system using a ``Runge-Kutta'' algorithm. Before we define
Runge-Kutta, let's first describe a simpler, similar, method. The
definition of a derivative is
\begin{equation}
  \label{eq:derivative:definition}
  \ddt\myvec{y}(t) = \lim_{h\to 0}\left[\frac{\myvec{y}(t+h) - \myvec{y}(t)}{h}\right].
\end{equation}
Or, alternatively, if $h$ is sufficiently small,
\begin{equation}
  \label{eq:forward:euler}
  \myvec{y}(t+h) = \myvec{y}(t) + h \dt{\myvec{y}}(t).
\end{equation}
If we know $\myvec{y}(t_0)$ and $\ddt\myvec{y}(t_0)$, then we can use
equation \eqref{eq:forward:euler} to solve for $\myvec{y}(t+h)$. Then,
let $t_1 = t_0 + h$ and use equation \eqref{eq:forward:euler} to solve
for $\myvec{y}(t_1 + h)$. In this way, we can solve for $\myvec{y}(t)$
for all $t > t_0$. This method is called the ``forward Euler'' method
\cite{Heath}.

Runge-Kutta methods are more sophisticated. One can use a Taylor
series expansion to define a more accurate iterative scheme that
relies on higher-order derivatives, not just first
derivatives. However, since we only have first derivative information,
we simulate higher-order derivatives by evaluating the first
derivative at a number of different values of $t$. Then, of course,
the higher-order derivatives are finite differences of these
evaluations \cite{Heath,NumericalRecipes}.

We use a fourth-order Runge-Kutta method---which means the method
effectively incorporates the first four derivatives of a
function---with adaptive step sizes: the 4(5) Runge-Kutta-Fehlberg
method \cite{Fehlberg}. We use our own implementation, written in
C++. The Runge-Kutta solver by itself can be found here:
\cite{RKF45}.\footnote{It is good coding practice to make one's code as
  flexible as possible. By separating the initial-value solver from a
  specific application, we make it possible to reuse our code.} In the
context of FLRW metrics, our implementation can be found here:
\cite{FLRWCode}. Both pieces of code are open-sourced, and the reader
should feel free to download and explore either program.

\section{Results}
\label{sec:results}

Before we delve into unknown territory, it's a good idea to explore
known physically interesting FLRW solutions. This is what we do
now.

\subsection{Known Solutions}
\label{subsec:known:solutions}

If the universe is dominated by radiation, as in the case in the early
universe, just after reheating \cite{Kempf}, we should expect the
scale factor to grow as $a(t) = \left(t/t_0\right)^{1/2}$
\cite{Kempf}. To account for not quite starting at $a=0$, we fit our
numerical solutions to
\begin{equation}
  \label{eq:radiation:dominated:fit}
  a(t) = a_0 t^{1/2} + b,
\end{equation}
where $a_0$ and be are constants. Figure \ref{fig:radiation:dominated}
shows scale factors for several different choices of $\rho(0)$ and a
fit to an analytic scale factor solution using equation
\eqref{eq:radiation:dominated:fit}, which matches the data extremely
well.\footnote{In all plots showing a fit, we've removed most of the
  data points. There are a minimum of 100 data points generated per
  simulation. However these are hidden to demonstrate the accuracy of
  the fit.}

\begin{figure}[htb]
  \begin{center}
    \leavevmode
    \hspace{-.2cm}
     \includegraphics[width=8.2cm]{figures/radiation_dominated_all_scale_factors.png}
     \hspace{-0.3cm}
     \includegraphics[width=8.3cm]{figures/radiation_dominated_fit_rho0256.png}
     \caption[Radiation Dominated Universe]{The Radiation-Dominated
       Universe. Left: Scale factor as a function of time for a number
       of different values of $\rho(0)$. Right: A fit to equation
       \eqref{eq:radiation:dominated:fit} for $\rho(0)=256$.}
    \label{fig:radiation:dominated}
  \end{center}
\end{figure}

If the universe is dominated by matter, as was the case until
extremely recently \cite{Kempf}, then we expect the scale factor to
scale as $a(t) = \left(t/t_0\right)^{2/3}$ \cite{Kempf}. To account
for not quite starting at $a=0$, we fit our numerical solutions to
\begin{equation}
  \label{eq:matter:dominated:fit}
  a(t) = a_0 t^{2/3} + b.
\end{equation}
Figure \ref{fig:matter:dominated} shows the scale factors and fit.
\begin{figure}[htb]
  \begin{center}
    \leavevmode
    \hspace{-.2cm}
     \includegraphics[width=8.2cm]{figures/matter_dominated_all_scale_factors.png}
     \hspace{-0.3cm}
     \includegraphics[width=8.3cm]{figures/matter_dominated_fit_rho032.png}
     \caption[Matter Dominated Universe]{The Matter-Dominated
       Universe. Left: Scale factor as a function of time for a number
       of different values of $\rho(0)$. Right: A fit to equation
       \eqref{eq:matter:dominated:fit} for $\rho(0)=32$.}
    \label{fig:matter:dominated}
  \end{center}
\end{figure}

If the universe is dominated by dark energy, as will be the case very
soon \cite{Kempf}, then we expect the scale factor to scale as
$a(t)=a_0 e^{t_0t}$. For convenience, we fit to
\begin{equation}
  \label{eq:dark:energy:dominated:fit}
  a(t) = e^{t_0t + b},
\end{equation}
where $t_0$ and $a_0$ are constants. Figure
\ref{fig:dark:energy:dominated} shows the scale factors and fit.
\begin{figure}[htb]
  \begin{center}
    \leavevmode
    \hspace{-.2cm}
     \includegraphics[width=8.2cm]{figures/dark_energy_dominated_universe_scale_factors.png}
     \hspace{-0.3cm}
     \includegraphics[width=8.3cm]{figures/dark_energy_dominated_fit_rho012.png}
     \caption[Matter Dominated Universe]{The Dark Energy-Dominated
       Universe. Left: Scale factor as a function of time for a number
       of different values of $\rho(0)$. Right: A fit to equation
       \eqref{eq:matter:dominated:fit} for $\rho(0)=1.2$.}
    \label{fig:dark:energy:dominated}
  \end{center}
\end{figure}

\subsection{A Multi-Regime Universe}
\label{subsec:multi-regime}

Now that we've confirmed appropriate behavior in each of the
analytically explored regimes, it's time to move into unknown
territory! We will attempt to construct a history of the universe by
splicing together the known solutions to the Friedmann equations in a
smooth way.

To this end, we let $\omega$ vary smoothly with $\rho$. We want the
radiation, matter, and dark energy dominated regimes of the universe
to emerge naturally, separated by transition regions. Furthermore, we
want $\omega(\rho)$ to be monotonically increasing, since we know that
we first had a radiation dominated universe---radiation scales as
$a^{1/4}$---then a matter dominated universe---matter scales as
$a^{1/3}$---and finally a dark energy dominated universe---dark energy
does not scale with $a$ at all
\cite{Carroll,MisnerThorneWheeler,Kempf}. The dark energy regime
should take over when $\rho$ is very small and the normal matter and
radiation has diluted away \cite{Carroll,MisnerThorneWheeler,Kempf}.

One function that smoothly, asymptotically, and monotonically
interpolates between two constant values is the error function,
\begin{equation}
  \label{eq:def:error:function}
  \erf(x) = \frac{2}{\sqrt{\pi}}\int_0^x e^{-t^2}dt.
\end{equation}
$\erf(-\infty)=-1$ and $\erf(+\infty)=+1$. However, the transition
region is very sharp and the error function is effectively $-1$ for
$x<-2$ and effectively $+1$ for $x>2$. We can therefore create a
smoothly varying $\omega(\rho)$ with the desired properties by taking
a linear combination of error functions:
\begin{equation}
  \label{eq:interpolating:function}
  \omega(\rho) = -1 + \left(\frac{1}{2}\right) \left(1+\frac{1}{3}\right) + \frac{1}{2}\erf\left(\frac{\rho - \rho_{DE}}{\Delta_{DE}}\right) + \left(\frac{1}{2}\right)\left(\frac{1}{3}\right)\erf\left(\frac{\rho - \rho_{RM}}{\Delta_{RM}}\right),
\end{equation}
where $\rho_{DE}$ is the value of $\rho$ marking the change of regimes
from a matter-dominated to a dark energy dominated universe and
$\Delta_{DE}$ is the width of the transition region. $\rho_{RM}$ and
$\Delta_{RM}$ fill analogous roles for the transition from a radiation
to a matter dominated universe.

By varying $\rho_{DE}$, $\rho_{RM}$, $\Delta_{DE}$, and $\Delta_{RM}$,
we can select a function where the transition between regimes is very
abrupt or where the transition is very gradual. We chose four such
functions, as shown in figure \ref{fig:omega:of:rho}: an equation of
state with abrupt transitions
($\rho_{DE}=10,\Delta_{DE}=\Delta_{RM}=1,\rho_{RM}=20$), one with
moderate transitions
($\rho_{DE}=20,\Delta_{DE}=\Delta_{RM}=5,\rho_{RM}=40$), one with
gradual transitions
($\rho_{DE}=25,\Delta_{DE}=\Delta_{RM}=12,\rho_{RM}=80$). And,
finally, as a check, we chose a function with no well defined epochs
at all ($\rho_{DE}=37,\Delta_{DE}=\Delta_{RM}=20,\rho_{RM}=92$).

\begin{figure}[tbh]
  \begin{center}
    \leavevmode
    \includegraphics[width=12cm]{figures/multi_regime_eos_1.png}
    \caption[EOS]{The equation of state variable $\omega$ (see
      equation \eqref{eq:def:eos}) as a function of energy density
      $\rho$, as defined in equation
      \eqref{eq:interpolating:function}. We choose four possible
      scenarios: an equation of state with abrupt transitions
      ($\rho_{DE}=10,\Delta_{DE}=\Delta_{RM}=1,\rho_{RM}=20$), one
      with moderate transitions
      ($\rho_{DE}=20,\Delta_{DE}=\Delta_{RM}=5,\rho_{RM}=40$), one
      with gradual transitions
      ($\rho_{DE}=25,\Delta_{DE}=\Delta_{RM}=12,\rho_{RM}=80$), and
      one with almost no transitions at all
      ($\rho_{DE}=37,\Delta_{DE}=\Delta_{RM}=20,\rho_{RM}=92$)}
    \label{fig:omega:of:rho}
  \end{center}
\end{figure}

The evolution of $a(t)$ for these four choices of $\omega(\rho)$ is
shown in figure \ref{fig:a:varying:omega}, where we also show the
evolution of $\rho$ and $p$ on the same plots. (We have rescaled
$a(t)$ so that it fits nicely with the other variables.) In these
plots, we can see hints of each of the three analytically predicted
epochs of growth. Initially $\ddot{a} < 0$, but it transitions to
$\ddot{a}>0$.

Surprisingly, so long as we allow $\omega(\rho)$ to
vary from $+1/3$ to $0$ to $-1$, $a(t)$ seems remarkably resilient to
the details such as the abruptness of the transition or the precise
location of the transition region. Indeed, when we plotted all four
scale factor functions on the same scale, they overlapped completely.

We postulate that his unexpected resilience is due to the $a^{-2}$
term in the formula for $\dot{\rho}$. Although different fixed values
of $\omega$ drive $a(t)$ at different rates, $a(t)$ in turn drives
$\rho(t)$ into a regime that balances out this change. This stability
is a boon to cosmologists, since it means that, for the purpose of
predictions a piecewise function composed of the analytic solutions is
sufficient---we don't need to look for a more detailed or accurate
equation of state.

\begin{figure}[htb]
  \begin{center}
    \leavevmode
    \hspace{-.2cm}
     \includegraphics[width=8.35cm]{figures/multi_regime_abrupt_transition.png}
     \hspace{-0.3cm}
     \includegraphics[width=8.35cm]{figures/multi_regime_moderate_transition.png}\\
     \vspace{0.2cm}
     \hspace{-.2cm}
     \includegraphics[width=8.35cm]{figures/multi_regime_mild_transition.png}
     \hspace{-0.3cm}
     \includegraphics[width=8.35cm]{figures/multi_regime_no_transition.png}
     \caption[$a(t)$ with a variable $\omega(\rho)$]{$a(t)$ with a
       variable $\omega(\rho)$. We plot the scale factor for the four
       equations of state show in figure \ref{fig:omega:of:rho}.}
     \label{fig:a:varying:omega}
  \end{center}
\end{figure}

\subsection{$\omega \approx -1.2$}
\label{subsec:label:omega:1.2}

The Pan-STARRS1 survey \cite{Pan-STARRS1} predicts that $\omega
\approx -1.2$, which is a very strange type of matter indeed. When
$\omega=-1$, it emerges from the cosmological constant term and the
energy density $\rho$ stays constant as the scale factor changes. If
$\omega<-1$, then the energy density must \textit{increase} with the
scale factor! Since we expect energy density to \textit{dilute} with
increased scale factor \cite{Carroll,Kempf}, this is decidedly odd!

We can test this hypothesis with our FLRW simulation code. And,
indeed, the energy density slowly grows with scale factor, as shown in
figure \ref{fig:omega:1.2}. The result is that the scale factor grows
with time more quickly than an exponential. We fit $\ln(a(t))$ to a
polynomial and found a cubic to fit well. Figure \ref{fig:omega:1.2}
shows the results of one such fit.
\begin{figure}[htb]
  \begin{center}
    \leavevmode
    \hspace{-.2cm}
     \includegraphics[width=8.2cm]{figures/our_future_universe_all_variables_rho035.png}
     \hspace{-0.3cm}
     \includegraphics[width=8.3cm]{figures/our_future_universe_fit_rho035.png}
     \caption[Our Future Universe?]{Our future universe? We solve for
       the universe when $\omega \approx -1.2$. Left: Scale factor,
       density, and pressure as a function of time. Right: A fit to
       equation $a(t) = \exp(a_0 t^3 + b t^2 + c t + d)$. In both
       cases, $\rho(0) = 0.35$.}
    \label{fig:omega:1.2}
  \end{center}
\end{figure}

\section{Conclusion}
\label{sec:conclusion}

In summary, given that the universe is foliated by homogeneous and
isotropic hypersurfaces, we have re-derived how to solve for the
evolution of space as a function of time
\cite{Carroll,MisnerThorneWheeler,Wald,Kempf}. We have also used a
fourth-order Runge-Kutta-Fehlberg method \cite{Fehlberg,RKF45} to
numerically solve for the universe given these evolution equations. We
have reproduced the analytically known epochs of evolution and solved
for the universe as it transitions between analytically known
radiation-dominated, matter-dominated, and dark energy-dominated
regimes. Finally, we have solved for a universe dominated by an
equation of state where $\omega<-1$ and the energy density increases
slowly with scale factor. In this case, we discovered faster than
exponential growth, which agrees qualitatively with expectations.

It is a pleasant surprise to find that the evolution of the universe
extremely resilient to a choice of equation of state,
$p=\omega(\rho)\rho$, so long as $\omega(\rho)$ varies smoothly and
monotonically from $\omega=-1$ to $\omega=+1/3$. This means that it is
sufficient for cosmologists to study the evolution of the universe
epoch by epoch, and not worry too much about the transitional periods.

We would have liked to study the big bounce scenario wherein the scale
factor shrinks to some minimum value and then grows
monotonically. This is certainly analytically feasible. In the case of
a positively curved spacelike foliation dominated by dark energy, for
example, we analytically attain de Sitter space, where $a(t)\approx
\cosh(t)$. Unfortunately, $\dot{a}$ must equal zero in this scenario,
and this condition makes the first-order version of the Friedmann
equations singular. A numerical treatment of the big bounce seems
difficult if we continue to treat it as an initial value problem. A
better approach might be to treat the big bounce scenario as a
boundary value problem with initial and final values of $a(t)$ and a
negative value for $\dot{a}(t)$. In general, the numerical methods to
treat initial value problems are very different from those used to
treat boundary value problems \cite{Heath}. Thus it would be necessary
to implement another approach (e.g., finite elements) anew. This would
be an interesting future project.

%Bibliography
\bibliography{frlw_project}
\bibliographystyle{hunsrt}

\end{document}