Summary

Code

Executable on S2

Videos


What is a function?

A function \(f \) is like a machine. It takes an input \(x\) and produces one and only one output \(y\). We write:

\(f(x) = y\)
Function is like a machine.

The input can be anything. It can be a number, a text (software engineers call a text “string”), a blob, a picture, or a video. The output can also be anything. For example, you can have a function that produces/outputs/returns/maps the superheroes to their real names.

f(superhero) = real_name

Or, a function that maps students into their houses.

f(student) = house

One simplest function is the identity function. It always gives (software engineers say “returns”) the same output as the input. For example, if the input is “apple”, the function returns “apple”. If the input is “orange”, the function returns “orange”. If the input is “kiwi”, the function returns “kiwi”. We can use symbols (mathematicians call them notations) to easily represent the identity function.

\(f(x) = x\)

This notation says whatever \(x\) we put into the function \(f\), the output is always \(x\).

Computer scientists say: given an argument \(x\), return \(x\).

Mathematicians say: \(f\) of \(x\) equals \(x\).

They all mean the same thing.

To write a function in Kotlin, we first open the S2 IDE on a browser:

https://s21.nm.dev

Type:

// define the identity function
fun same(x : String) : String {
    return x;
}

We can try a few different \(x\) and see.

same("apple")
apple
same("hello")
hello

The last function takes a string as an input. We can write the same function but takes a number. A number in Kotlin is represented as a “Double”.

// define the identity function
fun identity(x : Double) : Double {
    return x;
}

We can try a few different inputs and see.

identity(1.0)
1.0

A chain of functions

The output of a function can be an input to another (or the same) function. In fact, this is how the mathematician Peano constructs the set of counting numbers, 0, 1, 2, 3, so on and so forth.

First, we define the special number that has this property (yes, mathematics is all about definitions and properties): adding anything to this special number equals to that anything. Using notation, we can write:

a + special number = a

We call this special number “0”.

We can then give the definition or meaning to define the number “1” as the next number after 0. That is, we call the next number after “0” as “1”. Using the function notation, we can write:

\(\text{next}(0) = 1\)

Alternatively, we call this function “add1”. So

\(\text{add1}(0) = 1\)

Likewise, we can define the number “2” as the next number after “1”. Using the function notation, we have:

\(\text{add1}(1) = 2\)

Instead of making “1” the input to the function, we can equivalently replace it by add1(0) because the output of which is “1”. That is,

\(\text{add1(0)}(1) = 2\)

Likewise, we can call the number “3” as the next number after “2”. Using the function notation, we have:

\(\text{add1}(2) = 3\)

Again, we can replace the input “2” with add1(1), which has the output “2”. That is
\(\text{add1}(\text{add1}(1)) = 3\)

We can then further replace the “1” by add1(0).

\(\text{add1}(\text{add1}(\text{add1}(0))) = 3\)

We have chained up 3 functions together in this example.

In coding, we can chain up functions in a similar fashion.

add1(add1(add1(0.0)))
3

Linear Functions

For a math function that takes a number and return a number, we use this notation:

\(y = f(x)\)

It means that we pass a number \(x\) to the function \(f\), it will output a number \(y\). Any such function is a curve or a line on a piece of paper.

A very important class of functions is linear function. They are straight lines. For example, all these are linear functions or lines.

\(y = 0\)

When \(x = 0\), \(y = 0\).

When \(x = 1\), \(y = 0\).

When \(x = 2\), \(y = 0\).

When \(x = 3\), \(y = 0\).

We can code it up and try it out.

fun y(x : Double): Double {
    return 0;
}

We run:

y(0)

We can use the pair notation to denote the output as \((0, 0)\).

y(1)

Using the pair notation, we write the output as \((0, 1)\).

y(2)

The output as \((0, 2)\).

y(3)

The output as \((0, 3)\).

We can try a slightly more complicated function.

\(y = x + 1\)

When \(x = 0\), \(y = 1\).

When \(x = 1\), \(y = 2\).

When \(x = 2\), \(y = 3\).

When \(x = 3\), \(y = 4\).

We can code it up and try it out.

fun y(x : Double): Double {
    return x + 1.0;
}

The outputs are: \((0, 1)\), \((1, 2)\), \((2, 3)\), \((3, 4)\).

Plotting

These pairs of inputs and outputs are called coordinates. Each one represents a dot on a piece of paper. For example, \((1, 2)\) means from home 1 step to the East and 2 steps to the North. We can put this dot.

To put this dot up on computer (instead of real paper), we code:

Plotly.plot {
    scatter {
        x(1
        y(2)
    }
}

Running the code, we get:

one point

We can put all the four pairs we got from the function on the same plot.

Plotly.plot {
    scatter {
        x(0, 1, 2, 3)
        y(1, 2, 3, 4)
    }
}
a line

As we can see, all of them indeed lie on a line. The function indeed represents a line.

Sometimes, it may be difficult to see what a function means given just the algebraic form of it (all those x’s and y’s). For example, suppose we have this function:

\(y = \arccos x\)

Nobody knows what arccos means! What we can do to understand a function is to draw it out on a piece of paper. The strategy is the same: we find a range of x, put them into the function that we code up, get a bunch of y output. Plot the pairs of \((x, y)\) on the coordinate plane. We can then visualize what the function looks like. Here is the code for the function.

// arccos

fun arccos(x : Double): Double {
    return acos(x);
}

“acos” in Kotlin is the the same as \(\arccos x\).

Suppose we choose x to be from -1 to 1, with 0.01 increment. That is,

val x1 = (-100..100).map{it / 100.0}
x1
[-1.0, -0.99, -0.98, -0.97, -0.96, -0.95, -0.94, -0.93, -0.92, -0.91, -0.9, -0.89, -0.88, -0.87, -0.86, -0.85, -0.84, -0.83, -0.82, -0.81, -0.8, -0.79, -0.78, -0.77, -0.76, -0.75, -0.74, -0.73, -0.72, -0.71, -0.7, -0.69, -0.68, -0.67, -0.66, -0.65, -0.64, -0.63, -0.62, -0.61, -0.6, -0.59, -0.58, -0.57, -0.56, -0.55, -0.54, -0.53, -0.52, -0.51, -0.5, -0.49, -0.48, -0.47, -0.46, -0.45, -0.44, -0.43, -0.42, -0.41, -0.4, -0.39, -0.38, -0.37, -0.36, -0.35, -0.34, -0.33, -0.32, -0.31, -0.3, -0.29, -0.28, -0.27, -0.26, -0.25, -0.24, -0.23, -0.22, -0.21, -0.2, -0.19, -0.18, -0.17, -0.16, -0.15, -0.14, -0.13, -0.12, -0.11, -0.1, -0.09, -0.08, -0.07, -0.06, -0.05, -0.04, -0.03, -0.02, -0.01, 0.0, 0.01, 0.02, 0.03, 0.04, 0.05, 0.06, 0.07, 0.08, 0.09, 0.1, 0.11, 0.12, 0.13, 0.14, 0.15, 0.16, 0.17, 0.18, 0.19, 0.2, 0.21, 0.22, 0.23, 0.24, 0.25, 0.26, 0.27, 0.28, 0.29, 0.3, 0.31, 0.32, 0.33, 0.34, 0.35, 0.36, 0.37, 0.38, 0.39, 0.4, 0.41, 0.42, 0.43, 0.44, 0.45, 0.46, 0.47, 0.48, 0.49, 0.5, 0.51, 0.52, 0.53, 0.54, 0.55, 0.56, 0.57, 0.58, 0.59, 0.6, 0.61, 0.62, 0.63, 0.64, 0.65, 0.66, 0.67, 0.68, 0.69, 0.7, 0.71, 0.72, 0.73, 0.74, 0.75, 0.76, 0.77, 0.78, 0.79, 0.8, 0.81, 0.82, 0.83, 0.84, 0.85, 0.86, 0.87, 0.88, 0.89, 0.9, 0.91, 0.92, 0.93, 0.94, 0.95, 0.96, 0.97, 0.98, 0.99, 1.0]

We compute y using the function.

val y1 = x1.map{arccos(it)}
y1
[3.141592653589793, 3.000053180265366, 2.9412578112666736, 2.896027136074501, 2.857798544381465, 2.824032224298272, 2.793426632316832, 2.765209171272065, 2.738876812009132, 2.714080388644924, 2.6905658417935308, 2.6681414963177272, 2.646658527248898, 2.6259986473437027, 2.6060659992754056, 2.5867816206097216, 2.568079549166696, 2.549904011163249, 2.532207345558998, 2.514948441949053, 2.498091544796509, 2.481605324202295, 2.4654621440291318, 2.4496374784634765, 2.4341094418104503, 2.4188584057763776, 2.4038666851365442, 2.3891182774264563, 2.3745986457279264, 2.3602945361410685, 2.34619382340565, 2.3322853795425296, 2.3185589614548174, 2.3050051142482557, 2.2916150876649866, 2.278380763520252, 2.2652945924214527, 2.2523495383580134, 2.2395390299972684, 2.2268569177198194, 2.214297435588181, 2.201855167572918, 2.1895250174671474, 2.1773021820079834, 2.165182126795959, 2.15316056466364, 2.1412334361948187, 2.1293968921376973, 2.117647277490841, 2.1059811170704963, 2.0943951023931957, 2.0828860797290445, 2.0714510391994847, 2.0600871048090124, 2.048791525313849, 2.037561665842193, 2.02639500019072, 2.0152891037307157, 2.0042416468647826, 1.9932503889816524, 1.9823131728623846, 1.9714279194962685, 1.9605926232691573, 1.9498053474908474, 1.9390642202315367, 1.9283674304404068, 1.9177132243220583, 1.907099901948877, 1.896525814089527, 1.8859893592356212, 1.8754889808102941, 1.865023164543879, 1.8545904360032246, 1.8441893582623698, 1.8338185297033656, 1.8234765819369754, 1.8131621778338598, 1.80287400965761, 1.7926107972916911, 1.7823712865529922, 1.7721542475852274, 1.7619584733259561, 1.7517827780414443, 1.741625995924001, 1.7314869797468073, 1.7213645995715827, 1.7112577415047525, 1.701165306498042, 1.6910862091896848, 1.6810193767826433, 1.6709637479564565, 1.660918271809492, 1.6508819068285556, 1.6408536198829469, 1.6308323852401752, 1.6208171836006666, 1.6108070011488855, 1.6008008286183735, 1.5907976603682872, 1.5807964934690637, 1.5707963267948966, 1.5607961601207294, 1.5507949932215062, 1.5407918249714196, 1.5307856524409076, 1.5207754699891267, 1.5107602683496182, 1.5007390337068465, 1.4907107467612377, 1.4806743817803014, 1.4706289056333368, 1.46057327680715, 1.4505064444001086, 1.440427347091751, 1.4303349120850408, 1.4202280540182106, 1.410105673842986, 1.399966657665792, 1.389809875548349, 1.379634180263837, 1.369438406004566, 1.359221367036801, 1.3489818562981022, 1.3387186439321834, 1.3284304757559333, 1.318116071652818, 1.3077741238864278, 1.2974032953274235, 1.2870022175865687, 1.2765694890459143, 1.2661036727794992, 1.2556032943541722, 1.2450668395002664, 1.2344927516409163, 1.2238794292677349, 1.2132252231493863, 1.2025284333582567, 1.191787306098946, 1.181000030320636, 1.1701647340935246, 1.1592794807274085, 1.148342264608141, 1.1373510067250105, 1.1263035498590777, 1.1151976533990733, 1.1040309877476002, 1.0928011282759442, 1.081505548780781, 1.0701416143903084, 1.0587065738607488, 1.0471975511965979, 1.0356115365192968, 1.0239453760989525, 1.0121957614520958, 1.0003592173949747, 0.9884320889261531, 0.9764105267938343, 0.9642904715818097, 0.9520676361226456, 0.9397374860168752, 0.9272952180016123, 0.914735735869974, 0.9020536235925248, 0.8892431152317797, 0.8762980611683406, 0.863211890069541, 0.849977565924807, 0.8365875393415376, 0.823033692134976, 0.8093072740472634, 0.7953988301841436, 0.7812981174487247, 0.7669940078618667, 0.7524743761633368, 0.7377259684532488, 0.7227342478134157, 0.7074832117793429, 0.6919551751263169, 0.6761305095606613, 0.6599873293874984, 0.6435011087932843, 0.6266442116407406, 0.609385308030795, 0.5916886424265441, 0.5735131044230968, 0.5548110329800715, 0.5355266543143878, 0.5155940062460905, 0.4949341263408955, 0.4734511572720662, 0.45102681179626236, 0.4275122649448695, 0.4027158415806615, 0.3763834823177281, 0.34816602127296103, 0.3175604292915215, 0.283794109208328, 0.24556551751529213, 0.20033484232311968, 0.1415394733244273, 0.0]

Finally, we can plot the x and y.

Plotly.plot {
    scatter {
        x.set(x1)
        y.set(y1)
    }
}

The graph is:

y= arccos(x)

Voilà! The function is a nice smooth downward sloping curve. We can move the mouse along the blue curve to see what value y takes at different x. For example, the above picture shows that when \(x = 0.5\), \(y = 1.047198\).