using Factors
using DataFrames

DataFrame(Factor(1:6, :X=>3, :Y=>2))

c = Dimension(:C, 3)
s = Dimension(:S, 10:2:18)

Factor([c, s], rand(3, 5))
Factor([c, s], rand(15)) # reshapes automatically
Factor(c, [2, 0, 16])

Factor([1 4; 2 5; 3 6], :X=> 3:5, :Y=> ['a', 'b'])
Factor(1:100, :X=>10, :Y=>2, :Z=>5) # reshape automatically

Factor(:X, [31, 33, 58])
Factor([:X, :Y], rand(20, 16)) 

Factor(c)  # all 0
Factor(c, 31)  # all 31
Factor([c, s], nothing)  # unitialized
Factor([c, s], 16)
Factor(Dict(:X=>14, :Y=>['Γ', 'Δ'], :Z=>'a':2:'z'))
Factor(Dict(:X=>14, :Y=>['Γ', 'Δ'], :Z=>'a':2:'z'), nothing)
Factor(:A=>10, :B=>3:20)
Factor(16, :A=>10, :B=>3:20)

Factor(2016)

ft = Factor([:X, :Y], rand(20, 16)) 
scope(ft)

names(ft)

similar(ft) # unitialized potential

size(ft, :X)

length(ft)

ndims(ft)

push(ft, Dimension(:J, 4))

ft = Factor([1 4; 2 5; 3 6], :X=> 2:4, :Y=>['a', 'b'])
ft[:X=>[3, 2], :Y=>'a']

ft[Assignment(:X=>[3, 2], :Y=>'a')] = [20, 16]
ft.potential

at2sub(ft, 3, 'b')

sub2at(ft, 1, 1)

at2a(ft, 2, 'a')

a2at(ft, :Y=>'b', :X=>2)

a2sub(ft, :Y=>'b', :X=>2)

sub2a(ft, 2, 2)

for t in Factor(:X=>'α':'γ', :Y=>["waldo", "carmen"], :Z=>3)
    println(t)
end

c = Dimension(:C, 2:4)
s = Dimension(:S, 'a':2:'h')
ft = Factor([c, s])

pattern(ft)

pattern_states(ft, :C)

permutedims!(ft, [2, 1])
pattern(ft)

map!(x -> x + 10, ft)
ft.potential

log(ft)
abs(ft)
sin(ft)

randn!(ft)
rand!(ft)
fill!(ft, 2016)
ft.potential

ft = Factor(1:6, :X=> 2:4, :Y=>['a', 'b'])
DataFrame(broadcast(*, ft, :Y, [100, 0.01]))

DataFrame(prod(ft, :X))

Z(ft) # purpously reminiscent of a partition function

ft = Factor(:W=>2, :X=>3, :Y=>2, :Z=>3)
marginalize(ft, :W)
marginalize(ft, [:W, :Y])

ft1 = Factor(collect(1:9), :A=>3, :B=>3)
ft2 = Factor(10, :B=>3, :C=>2)

DataFrame(ft1 * ft2)

Factor(:X, [-2016, 4])

set_negative_mode(NegativeWarn)
Factor(:X, [1, 1]) - Factor(:X, [2, 2])

set_negative_mode(NegativeError)
log(Factor(:X, [1E-2, 1//4]))

set_negative_mode(NegativeIgnore)

ds = map(s -> Dimension(:X, s), [["bob", "waldo", "superman"], ('a', 'α'), 'a':2:'z', 10:3:40, 2:15, 1:4, 16, []])

map(eltype, ds)

map(spttype, ds)

x = Dimension(:X, 'α':'ω')

for v in x
    print(v, " ")
end

x[2]

indexin('β', x)

(i, d) = update(x, ['α', 'ψ', 'ζ', 'δ'])

Dimension(:X, [1, 2, 3]) == Dimension(:X, 1:1:3)  == Dimension(:X, 1:3) == Dimension(:X, 3)

o = Dimension(:X, [3, 16, -2])
o .< -2 # here, 3 & 16 are less than -2

# 3, 16, and -2 are all ≥ 3
o .≥ 3