{
 "cells": [
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "# Factors.jl"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "A factor maps from the cartesion product of its dimensions's supports to a `Float64`.  \n",
    "`Factor` represent dimensions with a [`Dimensions` datatype](#Dimensions)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 1,
   "metadata": {
    "collapsed": false
   },
   "outputs": [],
   "source": [
    "using Factors\n",
    "using DataFrames"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "`Julia` is column-major, and so are potentials: the first dimension varies over to the first axis (column), the second dimension varies over the second axis (rows) etc ..."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 2,
   "metadata": {
    "collapsed": false
   },
   "outputs": [
    {
     "data": {
      "text/html": [
       "<table class=\"data-frame\"><thead><tr><th></th><th>X</th><th>Y</th><th>potential</th></tr></thead><tbody><tr><th>1</th><td>1</td><td>1</td><td>1.0</td></tr><tr><th>2</th><td>2</td><td>1</td><td>2.0</td></tr><tr><th>3</th><td>3</td><td>1</td><td>3.0</td></tr><tr><th>4</th><td>1</td><td>2</td><td>4.0</td></tr><tr><th>5</th><td>2</td><td>2</td><td>5.0</td></tr><tr><th>6</th><td>3</td><td>2</td><td>6.0</td></tr></tbody></table>"
      ],
      "text/plain": [
       "6×3 DataFrames.DataFrame\n",
       "│ Row │ X │ Y │ potential │\n",
       "├─────┼───┼───┼───────────┤\n",
       "│ 1   │ 1 │ 1 │ 1.0       │\n",
       "│ 2   │ 2 │ 1 │ 2.0       │\n",
       "│ 3   │ 3 │ 1 │ 3.0       │\n",
       "│ 4   │ 1 │ 2 │ 4.0       │\n",
       "│ 5   │ 2 │ 2 │ 5.0       │\n",
       "│ 6   │ 3 │ 2 │ 6.0       │"
      ]
     },
     "execution_count": 2,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "DataFrame(Factor(1:6, :X=>3, :Y=>2))"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "`Factor`s can be initialized with explicitly created `Dimensions`:"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 3,
   "metadata": {
    "collapsed": false
   },
   "outputs": [
    {
     "data": {
      "text/plain": [
       "3 instantiations:\n",
       "\tC:  1:3"
      ]
     },
     "execution_count": 3,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "c = Dimension(:C, 3)\n",
    "s = Dimension(:S, 10:2:18)\n",
    "\n",
    "Factor([c, s], rand(3, 5))\n",
    "Factor([c, s], rand(15)) # reshapes automatically\n",
    "Factor(c, [2, 0, 16])"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "`Julia` will also convert any `T <: AbstractVector` to a `Dimension`:"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 4,
   "metadata": {
    "collapsed": false
   },
   "outputs": [
    {
     "data": {
      "text/plain": [
       "100 instantiations:\n",
       "\tX:  1:10\n",
       "\tY:  1:2\n",
       "\tZ:  1:5"
      ]
     },
     "execution_count": 4,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "Factor([1 4; 2 5; 3 6], :X=> 3:5, :Y=> ['a', 'b'])\n",
    "Factor(1:100, :X=>10, :Y=>2, :Z=>5) # reshape automatically"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "Or assume the `i`-th `Dimension` is `1:size(potential, i)`:"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 5,
   "metadata": {
    "collapsed": false
   },
   "outputs": [
    {
     "data": {
      "text/plain": [
       "320 instantiations:\n",
       "\tX:  1:20\n",
       "\tY:  1:16"
      ]
     },
     "execution_count": 5,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "Factor(:X, [31, 33, 58])\n",
    "Factor([:X, :Y], rand(20, 16)) "
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "`Factor`s can also have uniform values (the default is zero), or be uninitialized:"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 6,
   "metadata": {
    "collapsed": false
   },
   "outputs": [
    {
     "data": {
      "text/plain": [
       "180 instantiations:\n",
       "\tA:  1:10\n",
       "\tB:  3:20 (18)"
      ]
     },
     "execution_count": 6,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "Factor(c)  # all 0\n",
    "Factor(c, 31)  # all 31\n",
    "Factor([c, s], nothing)  # unitialized\n",
    "Factor([c, s], 16)\n",
    "Factor(Dict(:X=>14, :Y=>['Γ', 'Δ'], :Z=>'a':2:'z'))\n",
    "Factor(Dict(:X=>14, :Y=>['Γ', 'Δ'], :Z=>'a':2:'z'), nothing)\n",
    "Factor(:A=>10, :B=>3:20)\n",
    "Factor(16, :A=>10, :B=>3:20)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "A `Factor` can also be zero-dimensional (for weird edge cases, and marginalization):"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 7,
   "metadata": {
    "collapsed": false
   },
   "outputs": [
    {
     "data": {
      "text/plain": [
       "1 instantiation: 2016.0"
      ]
     },
     "execution_count": 7,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "Factor(2016)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "A `Factor`s scope is its dimensions:"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 8,
   "metadata": {
    "collapsed": false
   },
   "outputs": [
    {
     "data": {
      "text/plain": [
       "2-element Array{Factors.Dimension,1}:\n",
       " X:  1:20\n",
       " Y:  1:16"
      ]
     },
     "execution_count": 8,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "ft = Factor([:X, :Y], rand(20, 16)) \n",
    "scope(ft)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 9,
   "metadata": {
    "collapsed": false
   },
   "outputs": [
    {
     "data": {
      "text/plain": [
       "2-element Array{Symbol,1}:\n",
       " :X\n",
       " :Y"
      ]
     },
     "execution_count": 9,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "names(ft)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "### As an Array\n",
    "\n",
    "`Factor`s act as `AbstractArray`s in many cases"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 10,
   "metadata": {
    "collapsed": false
   },
   "outputs": [
    {
     "data": {
      "text/plain": [
       "320 instantiations:\n",
       "\tX:  1:20\n",
       "\tY:  1:16"
      ]
     },
     "execution_count": 10,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "similar(ft) # unitialized potential"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 11,
   "metadata": {
    "collapsed": false
   },
   "outputs": [
    {
     "data": {
      "text/plain": [
       "20"
      ]
     },
     "execution_count": 11,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "size(ft, :X)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 12,
   "metadata": {
    "collapsed": false
   },
   "outputs": [
    {
     "data": {
      "text/plain": [
       "320"
      ]
     },
     "execution_count": 12,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "length(ft)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 13,
   "metadata": {
    "collapsed": false
   },
   "outputs": [
    {
     "data": {
      "text/plain": [
       "2"
      ]
     },
     "execution_count": 13,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "ndims(ft)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 14,
   "metadata": {
    "collapsed": false
   },
   "outputs": [
    {
     "data": {
      "text/plain": [
       "1280 instantiations:\n",
       "\tX:  1:20\n",
       "\tY:  1:16\n",
       "\tJ:  1:4"
      ]
     },
     "execution_count": 14,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "push(ft, Dimension(:J, 4))"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "### Indexing"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "An `Assignment` (or `Pair`s) can index into a `Factor`:"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 15,
   "metadata": {
    "collapsed": false
   },
   "outputs": [
    {
     "data": {
      "text/plain": [
       "2 instantiations:\n",
       "\tX:  [3,2] (2)"
      ]
     },
     "execution_count": 15,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "ft = Factor([1 4; 2 5; 3 6], :X=> 2:4, :Y=>['a', 'b'])\n",
    "ft[:X=>[3, 2], :Y=>'a']"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 16,
   "metadata": {
    "collapsed": false
   },
   "outputs": [
    {
     "data": {
      "text/plain": [
       "3×2 Array{Float64,2}:\n",
       " 16.0  4.0\n",
       " 20.0  5.0\n",
       "  3.0  6.0"
      ]
     },
     "execution_count": 16,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "ft[Assignment(:X=>[3, 2], :Y=>'a')] = [20, 16]\n",
    "ft.potential"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "Besides overloading `sub2ind` and `ind2sub`, functions to convert from and `Assignment`s and assignment tuples are provided:"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 17,
   "metadata": {
    "collapsed": false
   },
   "outputs": [
    {
     "data": {
      "text/plain": [
       "(2,2)"
      ]
     },
     "execution_count": 17,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "at2sub(ft, 3, 'b')"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 18,
   "metadata": {
    "collapsed": false
   },
   "outputs": [
    {
     "data": {
      "text/plain": [
       "(2,'a')"
      ]
     },
     "execution_count": 18,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "sub2at(ft, 1, 1)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 19,
   "metadata": {
    "collapsed": false
   },
   "outputs": [
    {
     "data": {
      "text/plain": [
       "Dict{Symbol,Any} with 2 entries:\n",
       "  :X => 2\n",
       "  :Y => 'a'"
      ]
     },
     "execution_count": 19,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "at2a(ft, 2, 'a')"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 20,
   "metadata": {
    "collapsed": false
   },
   "outputs": [
    {
     "data": {
      "text/plain": [
       "(2,'b')"
      ]
     },
     "execution_count": 20,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "a2at(ft, :Y=>'b', :X=>2)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 21,
   "metadata": {
    "collapsed": false
   },
   "outputs": [
    {
     "data": {
      "text/plain": [
       "(1,2)"
      ]
     },
     "execution_count": 21,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "a2sub(ft, :Y=>'b', :X=>2)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 22,
   "metadata": {
    "collapsed": false
   },
   "outputs": [
    {
     "data": {
      "text/plain": [
       "Dict{Symbol,Any} with 2 entries:\n",
       "  :X => 3\n",
       "  :Y => 'b'"
      ]
     },
     "execution_count": 22,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "sub2a(ft, 2, 2)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "### Iterating"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "Iterating over a factor returns assignment tuples"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 23,
   "metadata": {
    "collapsed": false
   },
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "('α',\"waldo\",1)\n",
      "('β',\"waldo\",1)\n",
      "('γ',\"waldo\",1)\n",
      "('α',\"carmen\",1)\n",
      "('β',\"carmen\",1)\n",
      "('γ',\"carmen\",1)\n",
      "('α',\"waldo\",2)\n",
      "('β',\"waldo\",2)\n",
      "('γ',\"waldo\",2)\n",
      "('α',\"carmen\",2)\n",
      "('β',\"carmen\",2)\n",
      "('γ',\"carmen\",2)\n",
      "('α',\"waldo\",3)\n",
      "('β',\"waldo\",3)\n",
      "('γ',\"waldo\",3)\n",
      "('α',\"carmen\",3)\n",
      "('β',\"carmen\",3)\n"
     ]
    }
   ],
   "source": [
    "for t in Factor(:X=>'α':'γ', :Y=>[\"waldo\", \"carmen\"], :Z=>3)\n",
    "    println(t)\n",
    "end"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "### Patterns"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "`pattern` returns the sequence of a indices a `Dimension` will take in `Factor` across all indicies"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 24,
   "metadata": {
    "collapsed": false
   },
   "outputs": [
    {
     "data": {
      "text/plain": [
       "12×2 Array{Int64,2}:\n",
       " 1  1\n",
       " 2  1\n",
       " 3  1\n",
       " 1  2\n",
       " 2  2\n",
       " 3  2\n",
       " 1  3\n",
       " 2  3\n",
       " 3  3\n",
       " 1  4\n",
       " 2  4\n",
       " 3  4"
      ]
     },
     "execution_count": 24,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "c = Dimension(:C, 2:4)\n",
    "s = Dimension(:S, 'a':2:'h')\n",
    "ft = Factor([c, s])\n",
    "\n",
    "pattern(ft)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "`pattern_states` returns the sequence of states"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 25,
   "metadata": {
    "collapsed": false
   },
   "outputs": [
    {
     "data": {
      "text/plain": [
       "12×1 Array{Int64,2}:\n",
       " 2\n",
       " 3\n",
       " 4\n",
       " 2\n",
       " 3\n",
       " 4\n",
       " 2\n",
       " 3\n",
       " 4\n",
       " 2\n",
       " 3\n",
       " 4"
      ]
     },
     "execution_count": 25,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "pattern_states(ft, :C)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "This, of course, can be changed by permuting the dimensions:"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 26,
   "metadata": {
    "collapsed": false
   },
   "outputs": [
    {
     "data": {
      "text/plain": [
       "12×2 Array{Int64,2}:\n",
       " 1  1\n",
       " 2  1\n",
       " 3  1\n",
       " 4  1\n",
       " 1  2\n",
       " 2  2\n",
       " 3  2\n",
       " 4  2\n",
       " 1  3\n",
       " 2  3\n",
       " 3  3\n",
       " 4  3"
      ]
     },
     "execution_count": 26,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "permutedims!(ft, [2, 1])\n",
    "pattern(ft)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "### Mapping"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 27,
   "metadata": {
    "collapsed": false
   },
   "outputs": [
    {
     "data": {
      "text/plain": [
       "4×3 Array{Float64,2}:\n",
       " 10.0  10.0  10.0\n",
       " 10.0  10.0  10.0\n",
       " 10.0  10.0  10.0\n",
       " 10.0  10.0  10.0"
      ]
     },
     "execution_count": 27,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "map!(x -> x + 10, ft)\n",
    "ft.potential"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "Common functions have already been defined"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 28,
   "metadata": {
    "collapsed": false
   },
   "outputs": [
    {
     "data": {
      "text/plain": [
       "12 instantiations:\n",
       "\tS:  'a':2:'g' (4)\n",
       "\tC:  2:4 (3)"
      ]
     },
     "execution_count": 28,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "log(ft)\n",
    "abs(ft)\n",
    "sin(ft)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "As have other not-so-mappy ones"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 29,
   "metadata": {
    "collapsed": false
   },
   "outputs": [
    {
     "data": {
      "text/plain": [
       "4×3 Array{Float64,2}:\n",
       " 2016.0  2016.0  2016.0\n",
       " 2016.0  2016.0  2016.0\n",
       " 2016.0  2016.0  2016.0\n",
       " 2016.0  2016.0  2016.0"
      ]
     },
     "execution_count": 29,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "randn!(ft)\n",
    "rand!(ft)\n",
    "fill!(ft, 2016)\n",
    "ft.potential"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "### Broadcasting"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "Operations can be broadcast along dimensions:"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 30,
   "metadata": {
    "collapsed": false
   },
   "outputs": [
    {
     "data": {
      "text/html": [
       "<table class=\"data-frame\"><thead><tr><th></th><th>X</th><th>Y</th><th>potential</th></tr></thead><tbody><tr><th>1</th><td>2</td><td>a</td><td>100.0</td></tr><tr><th>2</th><td>3</td><td>a</td><td>200.0</td></tr><tr><th>3</th><td>4</td><td>a</td><td>300.0</td></tr><tr><th>4</th><td>2</td><td>b</td><td>0.04</td></tr><tr><th>5</th><td>3</td><td>b</td><td>0.05</td></tr><tr><th>6</th><td>4</td><td>b</td><td>0.06</td></tr></tbody></table>"
      ],
      "text/plain": [
       "6×3 DataFrames.DataFrame\n",
       "│ Row │ X │ Y   │ potential │\n",
       "├─────┼───┼─────┼───────────┤\n",
       "│ 1   │ 2 │ 'a' │ 100.0     │\n",
       "│ 2   │ 3 │ 'a' │ 200.0     │\n",
       "│ 3   │ 4 │ 'a' │ 300.0     │\n",
       "│ 4   │ 2 │ 'b' │ 0.04      │\n",
       "│ 5   │ 3 │ 'b' │ 0.05      │\n",
       "│ 6   │ 4 │ 'b' │ 0.06      │"
      ]
     },
     "execution_count": 30,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "ft = Factor(1:6, :X=> 2:4, :Y=>['a', 'b'])\n",
    "DataFrame(broadcast(*, ft, :Y, [100, 0.01]))"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "### Reduce"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "Dimensions can be reduced.\n",
    "Convience functions are provded for the following:\n",
    "* `sum`  \n",
    "* `prod`  \n",
    "* `maximum`  \n",
    "* `minimum`  "
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 31,
   "metadata": {
    "collapsed": false
   },
   "outputs": [
    {
     "data": {
      "text/html": [
       "<table class=\"data-frame\"><thead><tr><th></th><th>Y</th><th>potential</th></tr></thead><tbody><tr><th>1</th><td>a</td><td>6.0</td></tr><tr><th>2</th><td>b</td><td>120.0</td></tr></tbody></table>"
      ],
      "text/plain": [
       "2×2 DataFrames.DataFrame\n",
       "│ Row │ Y   │ potential │\n",
       "├─────┼─────┼───────────┤\n",
       "│ 1   │ 'a' │ 6.0       │\n",
       "│ 2   │ 'b' │ 120.0     │"
      ]
     },
     "execution_count": 31,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "DataFrame(prod(ft, :X))"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 32,
   "metadata": {
    "collapsed": false
   },
   "outputs": [
    {
     "data": {
      "text/plain": [
       "1 instantiation: 21.0"
      ]
     },
     "execution_count": 32,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "Z(ft) # purpously reminiscent of a partition function"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "Marginalization sums out all but:"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 33,
   "metadata": {
    "collapsed": false
   },
   "outputs": [
    {
     "data": {
      "text/plain": [
       "4 instantiations:\n",
       "\tW:  1:2\n",
       "\tY:  1:2"
      ]
     },
     "execution_count": 33,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "ft = Factor(:W=>2, :X=>3, :Y=>2, :Z=>3)\n",
    "marginalize(ft, :W)\n",
    "marginalize(ft, [:W, :Y])"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "### Joining"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "Factors can be joined through `join` or by multiplying (adding, etc.) them:"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 34,
   "metadata": {
    "collapsed": false
   },
   "outputs": [
    {
     "data": {
      "text/html": [
       "<table class=\"data-frame\"><thead><tr><th></th><th>A</th><th>B</th><th>C</th><th>potential</th></tr></thead><tbody><tr><th>1</th><td>1</td><td>1</td><td>1</td><td>10.0</td></tr><tr><th>2</th><td>2</td><td>1</td><td>1</td><td>20.0</td></tr><tr><th>3</th><td>3</td><td>1</td><td>1</td><td>30.0</td></tr><tr><th>4</th><td>1</td><td>2</td><td>1</td><td>40.0</td></tr><tr><th>5</th><td>2</td><td>2</td><td>1</td><td>50.0</td></tr><tr><th>6</th><td>3</td><td>2</td><td>1</td><td>60.0</td></tr><tr><th>7</th><td>1</td><td>3</td><td>1</td><td>70.0</td></tr><tr><th>8</th><td>2</td><td>3</td><td>1</td><td>80.0</td></tr><tr><th>9</th><td>3</td><td>3</td><td>1</td><td>90.0</td></tr><tr><th>10</th><td>1</td><td>1</td><td>2</td><td>10.0</td></tr><tr><th>11</th><td>2</td><td>1</td><td>2</td><td>20.0</td></tr><tr><th>12</th><td>3</td><td>1</td><td>2</td><td>30.0</td></tr><tr><th>13</th><td>1</td><td>2</td><td>2</td><td>40.0</td></tr><tr><th>14</th><td>2</td><td>2</td><td>2</td><td>50.0</td></tr><tr><th>15</th><td>3</td><td>2</td><td>2</td><td>60.0</td></tr><tr><th>16</th><td>1</td><td>3</td><td>2</td><td>70.0</td></tr><tr><th>17</th><td>2</td><td>3</td><td>2</td><td>80.0</td></tr><tr><th>18</th><td>3</td><td>3</td><td>2</td><td>90.0</td></tr></tbody></table>"
      ],
      "text/plain": [
       "18×4 DataFrames.DataFrame\n",
       "│ Row │ A │ B │ C │ potential │\n",
       "├─────┼───┼───┼───┼───────────┤\n",
       "│ 1   │ 1 │ 1 │ 1 │ 10.0      │\n",
       "│ 2   │ 2 │ 1 │ 1 │ 20.0      │\n",
       "│ 3   │ 3 │ 1 │ 1 │ 30.0      │\n",
       "│ 4   │ 1 │ 2 │ 1 │ 40.0      │\n",
       "│ 5   │ 2 │ 2 │ 1 │ 50.0      │\n",
       "│ 6   │ 3 │ 2 │ 1 │ 60.0      │\n",
       "│ 7   │ 1 │ 3 │ 1 │ 70.0      │\n",
       "│ 8   │ 2 │ 3 │ 1 │ 80.0      │\n",
       "│ 9   │ 3 │ 3 │ 1 │ 90.0      │\n",
       "│ 10  │ 1 │ 1 │ 2 │ 10.0      │\n",
       "│ 11  │ 2 │ 1 │ 2 │ 20.0      │\n",
       "│ 12  │ 3 │ 1 │ 2 │ 30.0      │\n",
       "│ 13  │ 1 │ 2 │ 2 │ 40.0      │\n",
       "│ 14  │ 2 │ 2 │ 2 │ 50.0      │\n",
       "│ 15  │ 3 │ 2 │ 2 │ 60.0      │\n",
       "│ 16  │ 1 │ 3 │ 2 │ 70.0      │\n",
       "│ 17  │ 2 │ 3 │ 2 │ 80.0      │\n",
       "│ 18  │ 3 │ 3 │ 2 │ 90.0      │"
      ]
     },
     "execution_count": 34,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "ft1 = Factor(collect(1:9), :A=>3, :B=>3)\n",
    "ft2 = Factor(10, :B=>3, :C=>2)\n",
    "\n",
    "DataFrame(ft1 * ft2)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "### Negatives"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "By default, negatives are allowed in factors:"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 35,
   "metadata": {
    "collapsed": false
   },
   "outputs": [
    {
     "data": {
      "text/plain": [
       "2 instantiations:\n",
       "\tX:  1:2"
      ]
     },
     "execution_count": 35,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "Factor(:X, [-2016, 4])"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "This can be changed to raise a warning or to throw an error"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 36,
   "metadata": {
    "collapsed": false
   },
   "outputs": [
    {
     "name": "stderr",
     "output_type": "stream",
     "text": [
      "\u001b[1m\u001b[31mWARNING: potential has negative values\u001b[0m\n"
     ]
    },
    {
     "data": {
      "text/plain": [
       "2 instantiations:\n",
       "\tX:  1:2"
      ]
     },
     "execution_count": 36,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "set_negative_mode(NegativeWarn)\n",
    "Factor(:X, [1, 1]) - Factor(:X, [2, 2])"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 37,
   "metadata": {
    "collapsed": false
   },
   "outputs": [
    {
     "ename": "LoadError",
     "evalue": "ArgumentError: potential has negative values",
     "output_type": "error",
     "traceback": [
      "ArgumentError: potential has negative values",
      "",
      " in _check_negatives(::Array{Float64,1}, ::Factors.NegativeMode{:error}) at C:\\Users\\Hamza El-Saawy\\.julia\\v0.5\\Factors\\src\\negatives.jl:34",
      " in Factors.Factor{1}(::Array{Factors.Dimension,1}, ::Array{Float64,1}) at C:\\Users\\Hamza El-Saawy\\.julia\\v0.5\\Factors\\src\\factors_main.jl:23",
      " in Factors.Factor{N}(::Array{Factors.Dimension,1}, ::Array{Float64,1}) at C:\\Users\\Hamza El-Saawy\\.julia\\v0.5\\Factors\\src\\factors_main.jl:50",
      " in log(::Factors.Factor{1}) at C:\\Users\\Hamza El-Saawy\\.julia\\v0.5\\Factors\\src\\factors_map.jl:122"
     ]
    }
   ],
   "source": [
    "set_negative_mode(NegativeError)\n",
    "log(Factor(:X, [1E-2, 1//4]))"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 38,
   "metadata": {
    "collapsed": false
   },
   "outputs": [
    {
     "data": {
      "text/plain": [
       "Factors.NegativeMode{:error}()"
      ]
     },
     "execution_count": 38,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "set_negative_mode(NegativeIgnore)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {
    "collapsed": false
   },
   "source": [
    "## Dimensions"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "The core unit are dimensions, which are names (`Symbol`) with countably-finite supports (`<: AbstractVector`)."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 39,
   "metadata": {
    "collapsed": false
   },
   "outputs": [
    {
     "data": {
      "text/plain": [
       "8-element Array{Any,1}:\n",
       " X:  String[\"bob\",\"waldo\",\"superman\"] (3)\n",
       " X:  ['a','α'] (2)                       \n",
       " X:  'a':2:'y' (13)                      \n",
       " X:  10:3:40 (11)                        \n",
       " X:  2:15 (14)                           \n",
       " X:  1:4                                 \n",
       " X:  1:16                                \n",
       " X:  Any[] (0)                           "
      ]
     },
     "execution_count": 39,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "ds = map(s -> Dimension(:X, s), [[\"bob\", \"waldo\", \"superman\"], ('a', 'α'), 'a':2:'z', 10:3:40, 2:15, 1:4, 16, []])"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 40,
   "metadata": {
    "collapsed": false
   },
   "outputs": [
    {
     "data": {
      "text/plain": [
       "8-element Array{Any,1}:\n",
       " String\n",
       " Char  \n",
       " Char  \n",
       " Int64 \n",
       " Int64 \n",
       " Int64 \n",
       " Int64 \n",
       " Any   "
      ]
     },
     "execution_count": 40,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "map(eltype, ds)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 41,
   "metadata": {
    "collapsed": false
   },
   "outputs": [
    {
     "data": {
      "text/plain": [
       "8-element Array{Any,1}:\n",
       " Array{String,1}       \n",
       " Array{Char,1}         \n",
       " StepRange{Char,Int64} \n",
       " StepRange{Int64,Int64}\n",
       " UnitRange{Int64}      \n",
       " Base.OneTo{Int64}     \n",
       " Base.OneTo{Int64}     \n",
       " Array{Any,1}          "
      ]
     },
     "execution_count": 41,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "map(spttype, ds)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "### Indexing and iterating"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 42,
   "metadata": {
    "collapsed": false
   },
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "α β γ δ ε ζ η θ ι κ λ μ ν ξ ο π ρ ς σ τ υ φ χ ψ ω "
     ]
    }
   ],
   "source": [
    "x = Dimension(:X, 'α':'ω')\n",
    "\n",
    "for v in x\n",
    "    print(v, \" \")\n",
    "end"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 43,
   "metadata": {
    "collapsed": false
   },
   "outputs": [
    {
     "data": {
      "text/plain": [
       "'β'"
      ]
     },
     "execution_count": 43,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "x[2]"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 44,
   "metadata": {
    "collapsed": false
   },
   "outputs": [
    {
     "data": {
      "text/plain": [
       "2"
      ]
     },
     "execution_count": 44,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "indexin('β', x)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 45,
   "metadata": {
    "collapsed": false
   },
   "outputs": [
    {
     "data": {
      "text/plain": [
       "([1,24,6,4],X:  ['α','ψ','ζ','δ'] (4))"
      ]
     },
     "execution_count": 45,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "(i, d) = update(x, ['α', 'ψ', 'ζ', 'δ'])"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "### Dimension Comparisons"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "Equality for dimensions is by their support:"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 46,
   "metadata": {
    "collapsed": false
   },
   "outputs": [
    {
     "data": {
      "text/plain": [
       "true"
      ]
     },
     "execution_count": 46,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "Dimension(:X, [1, 2, 3]) == Dimension(:X, 1:1:3)  == Dimension(:X, 1:3) == Dimension(:X, 3)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "Comparisons use the position of elements in a dimension"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 47,
   "metadata": {
    "collapsed": false
   },
   "outputs": [
    {
     "data": {
      "text/plain": [
       "3-element BitArray{1}:\n",
       "  true\n",
       "  true\n",
       " false"
      ]
     },
     "execution_count": 47,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "o = Dimension(:X, [3, 16, -2])\n",
    "o .< -2 # here, 3 & 16 are less than -2"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 48,
   "metadata": {
    "collapsed": false
   },
   "outputs": [
    {
     "data": {
      "text/plain": [
       "3-element BitArray{1}:\n",
       " true\n",
       " true\n",
       " true"
      ]
     },
     "execution_count": 48,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "# 3, 16, and -2 are all ≥ 3\n",
    "o .≥ 3"
   ]
  }
 ],
 "metadata": {
  "kernelspec": {
   "display_name": "Julia 0.5.0",
   "language": "julia",
   "name": "julia-0.5"
  },
  "language_info": {
   "file_extension": ".jl",
   "mimetype": "application/julia",
   "name": "julia",
   "version": "0.5.0"
  }
 },
 "nbformat": 4,
 "nbformat_minor": 2
}