{
 "cells": [
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "# Control flow"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## Boolean types"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    " Booleans are special data types that can have two values, `true` or `false`. \n",
    " They are essential for conducting control flow.\n",
    "\n",
    "\n",
    "\n",
    "Boolean operators (copied from [here](https://docs.julialang.org/en/v1/manual/mathematical-operations/#Boolean-Operators))\n",
    "\n",
    "\n",
    "|Expression|\tName|\n",
    "|--|--|\n",
    "|`!x`|\tnegation|\n",
    "|`x && y`|\tshort-circuiting `and`|\n",
    "|`x \\|\\| y`|\tshort-circuiting `or`|\n",
    "\n",
    "Numeric comparisons (copied partially from [here](https://docs.julialang.org/en/v1/manual/mathematical-operations/#Numeric-Comparisons))\n",
    "|Operator|\tName|\n",
    "|--|--|\n",
    "|`==`\t|equality|\n",
    "|`!=`, `≠`\t|inequality|\n",
    "|`<`\t|less than|\n",
    "|`<=`, `≤`|\tless than or equal to|\n",
    "|`>`|\tgreater than|\n",
    "|`>=`, `≥`|\tgreater than or equal to|\n",
    "|`≈`, `isapprox` | approximate equality with _relative_ tolerance error `atol`|\n",
    "|`===` | programmatically identical equality comparison |"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "Most operators work exactly the same as in other languages."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 69,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "true"
      ]
     },
     "execution_count": 69,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "2 == 2"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 70,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "false"
      ]
     },
     "execution_count": 70,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "4>5"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "When I was learning coding in `Julia`, two operators were new to me: `≈` and `===`.\n",
    "\n",
    "Operator `≈` compares two  different objects given the tolerance error `atol`:"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 83,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "true"
      ]
     },
     "execution_count": 83,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "≈(2000, 2000.1, atol=.5)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 84,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "false"
      ]
     },
     "execution_count": 84,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "≈(2000, 2000.1; atol=.0001)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "Operator `===` checks whether two objects are programmatically identical. In case of arrays or dictionaries, it means that we check whether two objects refer to the same memory slots. Illustrative example below:"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 85,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "x==y: true\n",
      "x==z: true\n",
      "x===y: true\n",
      "x===z: false\n"
     ]
    }
   ],
   "source": [
    "x = [1,2]\n",
    "y = x\n",
    "z = deepcopy(x)\n",
    "\n",
    "println(\"x==y: $(x==y)\") #both objects have the same values\n",
    "println(\"x==z: $(x==z)\") #both objects have the same values\n",
    "println(\"x===y: $(x===y)\") #both objects refer to the same memory\n",
    "println(\"x===z: $(x===z)\") #both objects refer to different memory slots (even though they may have identical values)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "The mentioned operators can be broadcasted. As a result we get arrays:"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 91,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "3-element BitVector:\n",
       " 0\n",
       " 1\n",
       " 0"
      ]
     },
     "execution_count": 91,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "(1:1:3) .== (3:-1:1) #comparing [1 2 3] with [3 2 1]. It's true only for 2nd elements"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 92,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "2-element BitVector:\n",
       " 0\n",
       " 1"
      ]
     },
     "execution_count": 92,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    ".![true, false] #notice the order of `.` and `!`"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## Conditional evaluations"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "Implementation of  `if/elseif/else` is very standard and similar to other languages:\n",
    "\n",
    "```\n",
    "  if expr1 \n",
    "      sth1\n",
    "  elseif expr2\n",
    "      sth2\n",
    "  else \n",
    "      sth3\n",
    "  end\n",
    "```\n",
    "\n",
    "\n",
    "* `if`  - do `sth1` if `expr1` is true\n",
    "* `elseif` - do `sth2` if `expr2` is true and `expr1` is false \n",
    "* `else` - do `sth3` if both `expr1` and `expr2` are false\n",
    "\n",
    "Example below:"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 95,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "nothing\n"
     ]
    }
   ],
   "source": [
    "if 2!=2\n",
    "    println(\"asd\")\n",
    "elseif 3>4\n",
    "    println(\"3>4\")\n",
    "elseif 5==10\n",
    "    println(\"5==10\")\n",
    "else\n",
    "    println(\"nothing\")\n",
    "end"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## `?:` ternary operator"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "There is a ternary operator `?:` for short conditional evaluations. \n",
    "Its syntax is `cond ? sth1 : sth2`. The result of this operation conducted on scalar is: do `sth1` if `cond` is true and `sth2` otherwise.\n"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 106,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "\"x is even\""
      ]
     },
     "execution_count": 106,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "x = 4\n",
    "even_x = x%2==0 ? \"x is even\" : \"x is odd\""
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "(crra)=\n",
    "```{prf:example}\n",
    "Suppose we want to create the CRRA utlity function in `Julia`. It is defined as follows: \n",
    "\n",
    "$$ u(c_t, \\eta) = \\begin{cases}\\frac{c_t^{1-\\eta}-1}{1-\\eta}, \\text{if $\\eta \\neq 1$}\\\\ \n",
    "\\ln (c_t), \\text{if $\\eta=1.$}     \\end{cases}$$\n",
    "\n",
    "```\n",
    "\n",
    "We can use `?` to define this function:"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 32,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "u (generic function with 1 method)"
      ]
     },
     "execution_count": 32,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "u(cₜ, η) = η==1 ? log(cₜ) : (cₜ^(1. -η)-1.)/(1. -η)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "```{margin}\n",
    "I force `Julia` to operate on floating numbers by using `1.`. \n",
    "Try to use function defined as `u(cₜ, η) = η==1 ? log(cₜ) : (cₜ^(1 -η)-1)/(1 -η)`\n",
    "and  see what happens if you evaluate it at $c_t=3$ and $\\eta=2,$ both integers.\n",
    "\n",
    "```"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 33,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "0.6666666666666667"
      ]
     },
     "execution_count": 33,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "u(3,2)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "`?:` can be nested, just like in an example below:"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 40,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "x is smaller than 5 and is even\n"
     ]
    }
   ],
   "source": [
    "x = 4\n",
    "\n",
    "x<5 ?  ( \n",
    "        x%2==0 ? println(\"x is smaller than 5 and is even\") : #x<5 is true and x%2==0 is true\n",
    "                 println(\"x is smaller than 5 and is odd\")    #x<5 is true and x%2==0 is false\n",
    "        ) :\n",
    "         println(\"x is greater or equal to 5\")                #x<5 is false and x%2==0 is not evaluated"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "We know that the CRRA function is well defined if $\\eta\\geq 0.$ We can check this condition using nested `?`:"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 38,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "u (generic function with 1 method)"
      ]
     },
     "execution_count": 38,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "u(cₜ, η) = η≥0 ? \n",
    "            (η==1 ? log(cₜ) : (cₜ^(1. -η)-1. )/(1. -η)) :\n",
    "            @error \"η=$η is not allowed!\""
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 39,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "0.6666666666666667"
      ]
     },
     "execution_count": 39,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "u(3, 2)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 40,
   "metadata": {},
   "outputs": [
    {
     "name": "stderr",
     "output_type": "stream",
     "text": [
      "┌ Error: η=-1 is not allowed!\n",
      "└ @ Main In[38]:3\n"
     ]
    }
   ],
   "source": [
    "u(3, -1)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "(elementwise-question)=\n",
    "### Elementwise `?:`\n",
    "\n",
    "(elementwise-question-example)=\n",
    "```{note}\n",
    "Suppose that we want to perform a following mapping for $x\\in 1,2, \\ldots, 10:$\n",
    "\n",
    "$$ f(x) = \\begin{cases}x^2+1, \\text{if $x$ is odd,}\\\\\n",
    "                       -x^2, \\text{if $x$ is even.}\\\\ \\end{cases}$$\n",
    "```\n",
    "\n",
    "Such a task can be done relatively easily in other languages.\n",
    "For instance in `R` we get it by using `ifelse`: \n",
    "\n",
    "```\n",
    "    result <- ifelse(x%%2==0, -x^2, x^2 + 1) #this is `R` code. It will not work in `Julia`\n",
    "```\n",
    "\n",
    "We might be tempted to make elementwise comparisons using `.?`."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 132,
   "metadata": {},
   "outputs": [
    {
     "ename": "LoadError",
     "evalue": "syntax: space before \".\" not allowed in \"((x .% 2) .== 0) .\" at In[132]:2",
     "output_type": "error",
     "traceback": [
      "syntax: space before \".\" not allowed in \"((x .% 2) .== 0) .\" at In[132]:2",
      "",
      "Stacktrace:",
      " [1] top-level scope",
      "   @ In[132]:2",
      " [2] eval",
      "   @ ./boot.jl:360 [inlined]",
      " [3] include_string(mapexpr::typeof(REPL.softscope), mod::Module, code::String, filename::String)",
      "   @ Base ./loading.jl:1094"
     ]
    }
   ],
   "source": [
    "x = collect( 1:10 );\n",
    "result = ((x) .%2 .==0) .? -(x).^2 .: (x).^2.+1 "
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "As we can see, it will not work the way we would like. \n",
    "A solution to this problem is to use `map` function with an anonymous function:"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 115,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "10-element Vector{Int64}:\n",
       "    2\n",
       "   -4\n",
       "   10\n",
       "  -16\n",
       "   26\n",
       "  -36\n",
       "   50\n",
       "  -64\n",
       "   82\n",
       " -100"
      ]
     },
     "execution_count": 115,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "map(arg -> arg%2==0 ? -arg^2 : arg^2+1 , x)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "This works as intended."
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "(short-circuit)=\n",
    "## Short-circuit evaluations"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "`Julia` exhibits lazy evaluation of formulas. \n",
    "This means that operations are computed only if they are needed.\n",
    "This property has some particular consequences for two operators, `&&` and `||`.\n",
    "Laziness of `Julia` together with necessary condition for `true` value in `&&` and sufficient condition for `false` in `||` can be used for conditional evaluations.\n",
    "More precisely, the second (right-hand side) argument of `&&` is evaluated if and only if the first (left-hand side) argument is true.\n",
    "Similarly, the second (right-hand side) argument of `||` is _not_ valuated if if the first (left-hand side) argument is _false._\n",
    "\n",
    "As the second argument we can put some evaluations that we would like to conduct subject to the left-hand side argument.\n",
    "Simple illustrations below:"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 126,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "(2+2==4) It's true\n"
     ]
    }
   ],
   "source": [
    "(2+2==4) && println(\"(2+2==4) It's true\");\n"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 127,
   "metadata": {},
   "outputs": [],
   "source": [
    "(2+2==5) && println(\"(2+2==5) It's true\"); # the latter is not executed as (2+2==5) is false"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 2,
   "metadata": {},
   "outputs": [],
   "source": [
    "(2+2==4) || println(\"(2+2==4) It's false\"); # the latter is not executed as (2+2==4) is true"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 129,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "It's false\n"
     ]
    }
   ],
   "source": [
    "(2+2==5) || println(\"(2+2==5) It's false\");"
   ]
  }
 ],
 "metadata": {
  "kernelspec": {
   "display_name": "Julia 1.6.0",
   "language": "julia",
   "name": "julia-1.6"
  },
  "language_info": {
   "file_extension": ".jl",
   "mimetype": "application/julia",
   "name": "julia",
   "version": "1.6.0"
  },
  "orig_nbformat": 4
 },
 "nbformat": 4,
 "nbformat_minor": 2
}