# tests/testthat/test-heuristics.R In heuristica: Heuristics Including Take the Best and Unit-Weight Linear

```context("heuristics")

# require('testthat')

test_that("predictPair error does not have row dimension", {
train_matrix <- matrix(c(5,4,1,0,0,1), 2, 3)
model <- ttbModel(train_matrix, 1, c(2,3))
expect_error(predictPair(train_matrix[1,], train_matrix[2,], model),
"Object does not have row dimension")
})

test_that("predictPair error too many rows", {
train_matrix <- matrix(c(5,4,1,0,0,1), 2, 3)
model <- ttbModel(train_matrix, 1, c(2,3))
expect_error(predictPair(train_matrix[c(1:2),], train_matrix[2,], model),
"Expected a single row but got 2 rows")
})

test_that("predictPairProb error does not have row dimension", {
train_matrix <- matrix(c(5,4,1,0,0,1), 2, 3)
model <- ttbModel(train_matrix, 1, c(2,3))
expect_error(predictPairProb(train_matrix[1,], train_matrix[2,], model),
"Object does not have row dimension")
})

test_that("predictPairProb error too many rows", {
train_matrix <- matrix(c(5,4,1,0,0,1), 2, 3)
model <- ttbModel(train_matrix, 1, c(2,3))
expect_error(predictPairProb(train_matrix[c(1:2),], train_matrix[2,], model),
"Expected a single row but got 2 rows")
})

# Variations with data types

test_that("ttbModel 2x3 predictPair/Prob forward data.frame", {
train_df <- data.frame(y=c(5,4), x1=c(1,0), x2=c(0,1))
model <- ttbModel(train_df, 1, c(2,3))
expect_equal(c(x1=1, x2=1), model\$cue_validities)
expect_equal(c(x1=1, x2=-1), model\$cue_directions)
expect_equal(c(x1=1, x2=0), model\$cue_validities_unreversed)
# The prediction whether row 1 or row 2 is greater is 1, meaning row1.
expect_equal(1, predictPair(oneRow(train_df, 1),
oneRow(train_df, 2), model))
# The logical opposite: the prediction whether row 1 or row 2 is greater is
# -1, meaning row2.
expect_equal(-1, predictPair(oneRow(train_df, 2),
oneRow(train_df, 1), model))

# predictPairProb
# The probability that row 1 > row 2 is 1.
expect_equal(1, predictPairProb(oneRow(train_df, 1),
oneRow(train_df, 2), model))
# The logical opposite: the probability that row2 > row 1 is 0.
expect_equal(0, predictPairProb(oneRow(train_df, 2),
oneRow(train_df, 1), model))
})

test_that("ttbModel 2x3 predictPair/Prob forward data.frame ignore extra", {
train_df <- data.frame(y=c(5,4), name=c("a", "b"), x1=c(1,0), x2=c(0,1))
model <- ttbModel(train_df, 1, c(3,4))
expect_equal(c(x1=1, x2=0), model\$cue_validities_unreversed)
# The prediction whether row 1 or row 2 is greater is 1, meaning row1.
expect_equal(1, predictPair(oneRow(train_df, 1),
oneRow(train_df, 2), model))
# The logical opposite: the prediction whether row 1 or row 2 is greater is
# -1, meaning row2.
expect_equal(-1, predictPair(oneRow(train_df, 2),
oneRow(train_df, 1), model))

# The probability that row 1 > row 2 is 1.
expect_equal(1, predictPairProb(oneRow(train_df, 1),
oneRow(train_df, 2), model))
# The logical opposite: the probability that row2 > row 1 is 0.
expect_equal(0, predictPairProb(oneRow(train_df, 2),
oneRow(train_df, 1), model))
})

# ttbModel on binary cues

test_that("ttbModel 2x3 predictPair predictPairProb forward", {
train_matrix <- matrix(c(5,4,1,0,0,1), 2, 3)
model <- ttbModel(train_matrix, 1, c(2,3))
expect_equal(c(1, 0), model\$cue_validities_unreversed)
# The probability that row 1 > row 2 is 1.
expect_equal(1, predictPairProb(oneRow(train_matrix, 1),
oneRow(train_matrix, 2), model))
expect_equal(1, predictPair(oneRow(train_matrix, 1),
oneRow(train_matrix, 2), model))
# The logical opposite: the probability that row2 > row 1 is 0.
expect_equal(0, predictPairProb(oneRow(train_matrix, 2),
oneRow(train_matrix, 1), model))
# So predict row 1 is NOT greater.
expect_equal(-1, predictPair(oneRow(train_matrix, 2),
oneRow(train_matrix, 1), model))
})

test_that("ttbModel 2x3 predictPair predictPairProb test_matrix backward cues", {
train_matrix <- cbind(y=c(5,4), x1=c(1,0), x2=c(0,1))
model <- ttbModel(train_matrix, 1, c(2,3))
expect_equal(c(x1=1, x2=0), model\$cue_validities_unreversed)
# Cues in test_data below have been reversed.
# So predictions should be reversed.
test_matrix <- cbind(y=c(5,4), x1=c(0,1), x2=c(1,0))
expect_equal(-1, predictPair(oneRow(test_matrix, 1),
oneRow(test_matrix, 2), model))
expect_equal(0, predictPairProb(oneRow(test_matrix, 1),
oneRow(test_matrix, 2), model))
# Check symmetry (row 2 vs. row1).
expect_equal(1, predictPair(oneRow(test_matrix, 2),
oneRow(test_matrix, 1), model))
expect_equal(1, predictPairProb(oneRow(test_matrix, 2),
oneRow(test_matrix, 1), model))
})

test_that("ttbModel 2x3 predictPair predictPairProb test_matrix backward criterion", {
train_matrix <- cbind(y=c(5,4), x1=c(1,0), x2=c(0,1))
model <- ttbModel(train_matrix, 1, c(2,3))
expect_equal(c(x1=1, x2=1), model\$cue_validities)
expect_equal(c(x1=1, x2=0), model\$cue_validities_unreversed)
# The criterion in test_data below has been reversed.
# It should be ignored-- continue to use the validities from train_matrix.
test_matrix <- cbind(y=c(4,5), x1=c(1,0), x2=c(0,1))
expect_equal(1, predictPair(oneRow(test_matrix, 1),
oneRow(test_matrix, 2), model))
expect_equal(1, predictPairProb(oneRow(test_matrix, 1),
oneRow(test_matrix, 2), model))
# Check symmetry (row 2 vs. row1).
expect_equal(-1, predictPair(oneRow(test_matrix, 2),
oneRow(test_matrix, 1), model))
expect_equal(0, predictPairProb(oneRow(test_matrix, 2),
oneRow(test_matrix, 1), model))
})

test_that("ttbModel 2x2 predictPair predictPairProb cue_reversal", {
train_matrix <- cbind(y=c(5,4), x1=c(0,1))
model <- ttbModel(train_matrix, 1, c(2))
expect_equal(c(x1=0), model\$cue_validities_unreversed)
expect_equal(c(x1=1), model\$cue_validities)
expect_equal(1, predictPair(oneRow(train_matrix, 1),
oneRow(train_matrix, 2), model))
expect_equal(1, predictPairProb(oneRow(train_matrix, 1),
oneRow(train_matrix, 2), model))
# Check symmetry (row 2 vs. row1).
expect_equal(-1, predictPair(oneRow(train_matrix, 2),
oneRow(train_matrix, 1), model))
expect_equal(0, predictPairProb(oneRow(train_matrix, 2),
oneRow(train_matrix, 1), model))
})

test_that("ttbModel 3x3 predictPair predictPairProb forward", {
train_matrix <- cbind(y=c(5,4,3), x1=c(1,0,1), x2=c(1,0,0))
model <- ttbModel(train_matrix, 1, c(2,3))
expect_equal(c(x1=0.5, x2=1), model\$cue_validities)
# Row 1 vs. row 2.
expect_equal(1, predictPair(oneRow(train_matrix, 1),
oneRow(train_matrix, 2), model))
expect_equal(1, predictPairProb(oneRow(train_matrix, 1),
oneRow(train_matrix, 2), model))
# Row 1 vs. row 3.
expect_equal(1, predictPair(oneRow(train_matrix, 1),
oneRow(train_matrix, 3), model))
expect_equal(1, predictPairProb(oneRow(train_matrix, 1),
oneRow(train_matrix, 3), model))
# Row 2 vs. row 3.
# Cue x1 discriminates rows 2 and 3, but validity=0.5, so not used.
expect_equal(0, predictPair(oneRow(train_matrix, 2),
oneRow(train_matrix, 3), model))
expect_equal(0.5, predictPairProb(oneRow(train_matrix, 2),
oneRow(train_matrix, 3), model))
})

test_that("ttbModel 3x3 predictPair/Prob cue_reversal", {
train_matrix <- cbind(y=c(5,4,3), x1=c(1,0,1), x2=c(0,0,1))
model <- ttbModel(train_matrix, 1, c(2,3))
expect_equal(c(x1=0.5, x2=0), model\$cue_validities_unreversed)
# x1 discriminates but has 0.5 validity.
# x2 does not discriminate.
# So it's a guess = 0.
expect_equal(0, predictPair(oneRow(train_matrix, 1),
oneRow(train_matrix, 2), model))
# Reverse the 2nd cue, and it discriminates to get these right.
expect_equal(1, predictPair(oneRow(train_matrix, 2),
oneRow(train_matrix, 3), model))
expect_equal(1, predictPair(oneRow(train_matrix, 1),
oneRow(train_matrix, 3), model))

# predictPairProb: guess = 0.5.
expect_equal(0.5, predictPairProb(oneRow(train_matrix, 1),
oneRow(train_matrix, 2), model))
# Reverse the 2nd cue, and it discriminates to get these right.
expect_equal(1, predictPairProb(oneRow(train_matrix, 2),
oneRow(train_matrix, 3), model))
expect_equal(1, predictPairProb(oneRow(train_matrix, 1),
oneRow(train_matrix, 3), model))
})

test_that("ttbModel 3x3 pos pos predictPair/Prob forward", {
train_matrix <- cbind(y=c(5,4,3), x1=c(1,0,0), x2=c(1,1,0))
model <- ttbModel(train_matrix, 1, c(2,3))
expect_equal(c(x1=1, x2=1),  model\$cue_validities_unreversed)

expect_equal(1, predictPair(oneRow(train_matrix, 1),
oneRow(train_matrix, 2), model))
expect_equal(-1, predictPair(oneRow(train_matrix, 2),
oneRow(train_matrix, 1), model))

expect_equal(1, predictPair(oneRow(train_matrix, 1),
oneRow(train_matrix, 3), model))
expect_equal(-1, predictPair(oneRow(train_matrix, 3),
oneRow(train_matrix, 1), model))

expect_equal(1, predictPair(oneRow(train_matrix, 2),
oneRow(train_matrix, 3), model))
expect_equal(-1, predictPair(oneRow(train_matrix, 3),
oneRow(train_matrix, 2), model))

# predictPairProb
expect_equal(1, predictPairProb(oneRow(train_matrix, 1),
oneRow(train_matrix, 2), model))
expect_equal(0, predictPairProb(oneRow(train_matrix, 2),
oneRow(train_matrix, 1), model))

expect_equal(1, predictPairProb(oneRow(train_matrix, 1),
oneRow(train_matrix, 3), model))
expect_equal(0, predictPairProb(oneRow(train_matrix, 3),
oneRow(train_matrix, 1), model))

expect_equal(1, predictPairProb(oneRow(train_matrix, 2),
oneRow(train_matrix, 3), model))
expect_equal(0, predictPairProb(oneRow(train_matrix, 3),
oneRow(train_matrix, 2), model))
})

test_that("ttbModel 3x3 pos pos predictPair/Prob backward cues in test", {
train_matrix <- cbind(y=c(5,4,3), x1=c(1,0,0), x2=c(1,1,0))
model <- ttbModel(train_matrix, 1, c(2,3))
expect_equal(c(x1=1, x2=1),  model\$cue_validities_unreversed)

# All cues backwards relative to training data.
test_matrix <- cbind(y=c(5,4,3), x1=c(0,1,1), x2=c(0,0,1))
expect_equal(-1, predictPair(oneRow(test_matrix, 1),
oneRow(test_matrix, 2), model))
expect_equal(1, predictPair(oneRow(test_matrix, 2),
oneRow(test_matrix, 1), model))

expect_equal(-1, predictPair(oneRow(test_matrix, 1),
oneRow(test_matrix, 3), model))
expect_equal(1, predictPair(oneRow(test_matrix, 3),
oneRow(test_matrix, 1), model))

expect_equal(-1, predictPair(oneRow(test_matrix, 2),
oneRow(test_matrix, 3), model))
expect_equal(1, predictPair(oneRow(test_matrix, 3),
oneRow(test_matrix, 2), model))

# predictPairProb
expect_equal(0, predictPairProb(oneRow(test_matrix, 1),
oneRow(test_matrix, 2), model))
expect_equal(1, predictPairProb(oneRow(test_matrix, 2),
oneRow(test_matrix, 1), model))

expect_equal(0, predictPairProb(oneRow(test_matrix, 1),
oneRow(test_matrix, 3), model))
expect_equal(1, predictPairProb(oneRow(test_matrix, 3),
oneRow(test_matrix, 1), model))

expect_equal(0, predictPairProb(oneRow(test_matrix, 2),
oneRow(test_matrix, 3), model))
expect_equal(1, predictPairProb(oneRow(test_matrix, 3),
oneRow(test_matrix, 2), model))
})

test_that("ttbModel 2x2,3x2 predictPair/Prob", {
train_matrix <- cbind(y=c(5,4,3), x1=c(1,0,0))
model <- ttbModel(train_matrix, 1, c(2))
expect_equal(c(x1=1), model\$cue_validities)
expect_equal(c(x1=1), model\$cue_validities_unreversed)
expect_equal(1, predictPair(oneRow(train_matrix, 1),
oneRow(train_matrix, 2), model))
expect_equal(1, predictPairProb(oneRow(train_matrix, 1),
oneRow(train_matrix, 2), model))

expect_equal(1, predictPair(oneRow(train_matrix, 1),
oneRow(train_matrix, 3), model))
expect_equal(1, predictPairProb(oneRow(train_matrix, 1),
oneRow(train_matrix, 3), model))

expect_equal(0, predictPair(oneRow(train_matrix, 2),
oneRow(train_matrix, 3), model))
expect_equal(0.5, predictPairProb(oneRow(train_matrix, 2),
oneRow(train_matrix, 3), model))
})

test_that("ttbModel 4x4 predictPairProb x1 cue dominates", {
train_data <- cbind(y=c(9,8,7,6), x1=c(1,1,1,0), x2=c(1,1,0,1),
x3=c(1,1,0,1))
# How this data looks:
# > train_data
#         y   x1   x2   x3
# [1,]    9    1    1    1
# [2,]    8    1    1    1
# [3,]    7    1    0    0
# [4,]    6    0    1    1
# Cue x2 has validity 1.0, cue x2 and cue x3 have validity 2/3.
# Cue x1 predicts Row 3 > Row 4.
# But if you sum cue weights, predict Row 4 > Row 3
model <- ttbModel(train_data, 1, c(2:4))
expect_equal(c(x1=1, x2=0.667, x3=0.667), model\$cue_validities_unreversed,
tolerance=0.002)
expect_equal(1, predictPair(oneRow(train_data, 3),
oneRow(train_data, 4), model))
expect_equal(-1, predictPair(oneRow(train_data, 4),
oneRow(train_data, 3), model))
})

test_that("ttbModel 4x4 predictPairProb cue x1 dominates non-binary", {
train_data <- cbind(y=c(9,8,7,6), x1=c(0.1, 0.1, 0.1, 0),
x2=c(1,1,0,1), x3=c(1,1,0,1))
# How this data looks:
# > train_data
#         y    x1   x2   x3
# [1,]    9   0.1    1    1
# [2,]    8   0.1    1    1
# [3,]    7   0.1    0    0
# [4,]    6     0    1    1
# Cue x1 has validity 1.0, cue x2 and cue x3 have validity 2/3.
# Cue x1 predicts Row 3 > Row 4.
# But if you sum cue weights, predict Row 4 > Row 3
model <- ttbModel(train_data, 1, c(2:4))
expect_equal(c(x1=1, x2=0.667, x3=0.667), model\$cue_validities_unreversed,
tolerance=0.002)
expect_equal(1, predictPair(oneRow(train_data, 3),
oneRow(train_data, 4), model))
expect_equal(-1, predictPair(oneRow(train_data, 4),
oneRow(train_data, 3), model))
})

test_that("ttbModel 4x4 predictPairProb cue x3 dominates non-binary", {
train_data <- cbind(y=c(9,8,7,6), x1=c(1,1,0,1), x2=c(1,1,0,1),
x3=c(0.1, 0.1, 0.1, 0))
# How this data looks:
# > train_data
#         y   x1   x2   x3
# [1,]    9    1    1  0.1
# [2,]    8    1    1  0.1
# [3,]    7    0    0  0.1
# [4,]    6    1    1  0.0
# Cue x1 and x2 have validity 2/3, cue x3 has validity 1.0.
# Cue x3 predicts Row 3 > Row 4.
# But if you sum cue weights, predict Row 4 > Row 3
model <- ttbModel(train_data, 1, c(2:4))
expect_equal(c(x1=0.667, x2=0.667, x3=1), model\$cue_validities_unreversed,
tolerance=0.002)
expect_equal(1, predictPair(oneRow(train_data, 3),
oneRow(train_data, 4), model))
expect_equal(-1, predictPair(oneRow(train_data, 4),
oneRow(train_data, 3), model))
})

test_that("ttbModel 4x4 predictPairProb 3nd cue dominates non-binary reverse cue", {
train_data <- cbind(y=c(9,8,7,6), x1=c(1,1,0,1), x2=c(1,1,0,1),
x3=c(0, 0, 0, 0.1))
# How this data looks:
# > train_data
#         y   x1   x2   x3
# [1,]    9    1    1  0.0
# [2,]    8    1    1  0.0
# [3,]    7    0    0  0.0
# [4,]    6    1    1  0.1
# Column y is the criterion column.  Cues follow.
# Cue x1 and x2 have validity 2/3, cue x3 has validity 0,
# but that validity is 1.0 when reversed.
# Cue x3 predicts Row 3 > Row 4.
# But if you sum all cue weights, predict Row 4 > Row 3
model <- ttbModel(train_data, 1, c(2:4))
expect_equal(c(x1=0.667, x2=0.667, x3=0), model\$cue_validities_unreversed,
tolerance=0.002)
expect_equal(1, predictPair(oneRow(train_data, 3),
oneRow(train_data, 4), model))
expect_equal(-1, predictPair(oneRow(train_data, 4),
oneRow(train_data, 3), model))
})

test_that("ttbModel 4x4 predictPairProb 3nd cue dominates non-binary reverse cue data.frame", {
train_df <- data.frame(y=c(9,8,7,6), x1=c(1,1,0,1), x2=c(1,1,0,1),
x3=c(0,0,0,0.1))
# How this data looks:
# > train_df
#   y x1 x2  x3
# 1 9  1  1 0.0
# 2 8  1  1 0.0
# 3 7  0  0 0.0
# 4 6  1  1 0.1
# Cue x1 and x2 have validity 2/3, cue x3 has validity 0,
# but that validity is 1.0 when reversed.
# Cue x3 predicts Row 3 > Row 4.
# But if you sum all cue weights, predict Row 4 > Row 3
model <- ttbModel(train_df, 1, c(2:4))
expect_equal(c(x1=0.667, x2=0.667, x3=0), model\$cue_validities_unreversed,
tolerance=0.002)
expect_equal(c(x1=0.667, x2=0.667, x3=1), model\$cue_validities,
tolerance=0.002)
# The coefficient for column c should be negative.
expect_equal(c(x3=-1), sign(coef(model)["x3"]), tolerance=0.002)
expect_equal(1, predictPairProb(oneRow(train_df, 3),
oneRow(train_df, 4), model))
expect_equal(0, predictPairProb(oneRow(train_df, 4),
oneRow(train_df, 3), model))
})

### ttbModel on real-valued cues ###

test_that(paste("ttbModel 4x4 predictPair 3nd cue dominates reverse cue data.frame",
"non-binary small diffs, big diffs, small diffs"), {
train_df <- data.frame(criterion=c(9,8,7,6), a=c(1.1,1.1,1.0,1.1), b=c(10,10,-10,10),
c=c(0,0,0,0.1))
# How this data looks:
#   criterion   a   b   c
# 1         9 1.1  10 0.0
# 2         8 1.1  10 0.0
# 3         7 1.0 -10 0.0
# 4         6 1.1  10 0.1
# Cue a and b have validity 2/3, cue c has validity 0,
# but that validity is 1.0 when reversed.
# Cue c predicts Row 3 > Row 4.
# But if you sum all cue weights, predict Row 4 > Row 3
model <- ttbModel(train_df, 1, c(2:4))
expect_equal(c(a=0.667, b=0.667, c=0), model\$cue_validities_unreversed, tolerance=0.002)
expect_equal(c(a=0.667, b=0.667, c=1), model\$cue_validities, tolerance=0.002)
# The coefficient for column c should be negative.
expect_equal(c(c=-1), sign(coef(model)["c"]), tolerance=0.002)
expect_equal(1, predictPair(oneRow(train_df, 3),
oneRow(train_df, 4), model))
expect_equal(-1, predictPair(oneRow(train_df, 4),
oneRow(train_df, 3), model))
})

test_that(paste("ttbModel 4x4 predictPair 3nd cue dominates cue data.frame",
"non-binary big diffs, big diffs, big diffs"), {
train_df <- data.frame(criterion=c(9,8,7,6), a=c(101,101,20,101), b=c(59,59,5,59),
c=c(90,90,90,10))
# Cue a and b have validity 2/3, cue c has validity 0,
# but that validity is 1.0 when reversed.
# Cue c predicts Row 3 > Row 4.
# But if you sum all cue weights, predict Row 4 > Row 3
model <- ttbModel(train_df, 1, c(2:4))
expect_equal(c(a=0.667, b=0.667, c=1), model\$cue_validities_unreversed, tolerance=0.002)
expect_equal(c(a=0.667, b=0.667, c=1), model\$cue_validities, tolerance=0.002)
expect_equal(c(c=1), sign(coef(model)["c"]), tolerance=0.002)
expect_equal(1, predictPair(oneRow(train_df, 3),
oneRow(train_df, 4), model))
expect_equal(-1, predictPair(oneRow(train_df, 4),
oneRow(train_df, 3), model))
})

test_that(paste("ttbModel 4x4 predictPair 3nd cue dominates cue data.frame",
"non-binary big criteriondiffs, big diffs, big diffs, big diffs"), {
train_df <- data.frame(criterion=c(900,400,100,6), a=c(101,101,20,101), b=c(59,59,5,59),
c=c(90,90,90,10))
# Cue a and b have validity 2/3, cue c has validity 0,
# but that validity is 1.0 when reversed.
# Cue c predicts Row 3 > Row 4.
# But if you sum all cue weights, predict Row 4 > Row 3
model <- ttbModel(train_df, 1, c(2:4))
expect_equal(c(a=0.667, b=0.667, c=1), model\$cue_validities_unreversed, tolerance=0.002)
expect_equal(c(a=0.667, b=0.667, c=1), model\$cue_validities, tolerance=0.002)
expect_equal(c(c=1), sign(coef(model)["c"]), tolerance=0.002)
expect_equal(1, predictPair(oneRow(train_df, 3),
oneRow(train_df, 4), model))
expect_equal(-1, predictPair(oneRow(train_df, 4),
oneRow(train_df, 3), model))
})

test_that(paste("ttbModel 4x4 predictPair 3nd cue dominates cue data.frame",
"non-binary big criteriondiffs, big diffs, big diffs, big unique diffs"), {
train_df <- data.frame(criterion=c(900,400,100,6), a=c(101,101,20,101), b=c(59,59,5,59),
c=c(90,80,70,10))
# Cue a and b have validity 2/3, cue c has validity 1.
# Cue c predicts Row 3 > Row 4.
# But if you sum all cue weights, predict Row 4 > Row 3
model <- ttbModel(train_df, 1, c(2:4))
expect_equal(c(a=0.667, b=0.667, c=1), model\$cue_validities_unreversed, tolerance=0.002)
expect_equal(c(a=0.667, b=0.667, c=1), model\$cue_validities, tolerance=0.002)
expect_equal(c(c=1), sign(coef(model)["c"]), tolerance=0.002)
expect_equal(1, predictPair(oneRow(train_df, 3),
oneRow(train_df, 4), model))
expect_equal(-1, predictPair(oneRow(train_df, 4),
oneRow(train_df, 3), model))
})

test_that(paste("ttbModel 4x4 predictPair 3nd cue dominates cue data.frame REVERSE",
"non-binary big criteriondiffs, big diffs, big diffs, big unique diffs"), {
train_df <- data.frame(criterion=c(6,100,400,900), a=c(101,20,101,101), b=c(59,5,59,59),
c=c(10,70,80,90))
# Cue a and b have validity 2/3, cue c has validity 0,
# but that validity is 1.0 when reversed.
# Cue c predicts Row 3 > Row 4.
# But if you sum all cue weights, predict Row 4 > Row 3
model <- ttbModel(train_df, 1, c(2:4))
expect_equal(c(a=0.667, b=0.667, c=1), model\$cue_validities_unreversed, tolerance=0.002)
expect_equal(c(a=0.667, b=0.667, c=1), model\$cue_validities, tolerance=0.002)
expect_equal(c(c=1), sign(coef(model)["c"]), tolerance=0.002)
expect_equal(-1, predictPair(oneRow(train_df, 3),
oneRow(train_df, 4), model))
expect_equal(1, predictPair(oneRow(train_df, 4),
oneRow(train_df, 3), model))
})

### ttbModel on same data as ttbGreedyModel ###

test_that("ttbModel on 3x3 where differs from greedy ttb", {
matrix <- cbind(y=c(3:1), x1=c(1,0,0), x2=c(1,0,1))
model <- ttbModel(matrix, 1, c(2:3))
expect_equal(1, predictPair(oneRow(matrix, 1),
oneRow(matrix, 2), model))
expect_equal(1, predictPair(oneRow(matrix, 1),
oneRow(matrix, 3), model))
# Below is the row pair that differs from greedy ttb.
expect_equal(0, predictPair(oneRow(matrix, 2),
oneRow(matrix, 3), model))
expect_equal(c(x1=1.0, x2=0.5), model\$cue_validities)
})

test_that("ttbModel on 2 same cues- differs from greedy ttb", {
matrix <- cbind(y=c(2:1), x1=c(1,0), x2=c(1,0))
model <- ttbModel(matrix, 1, c(2:3))
full_matrix <- cbind(y=c(3:1), x1=c(1,0,0), x2=c(1,1,0))
out <- percentCorrectList(full_matrix, list(model))
# TTB uses both cues, so it can get 100% correct.
expect_equal(100, out\$ttbModel)
expect_equal(c(x1=1.0, x2=1.0), model\$cue_validities)
})

test_that("ttbModel default fit_name", {
train_matrix <- matrix(c(5,4,1,0,0,1), 2, 3)
ttb_default <- ttbModel(train_matrix, 1, c(2,3))
expect_equal(class(ttb_default), ttb_default\$fit_name)
})

test_that("ttbModel override fit_name", {
train_matrix <- matrix(c(5,4,1,0,0,1), 2, 3)
ttb1 <- ttbModel(train_matrix, 1, c(2,3), fit_name="fit1")
expect_equal("fit1", ttb1\$fit_name)
ttb2 <- ttbModel(train_matrix, 1, c(2,3), fit_name="fit2")
expect_equal("fit2", ttb2\$fit_name)

# Checks taht the fit_name was properly used by other code.
out <- percentCorrectList(train_matrix, list(ttb1, ttb2))
expect_equal(c("fit1", "fit2"), colnames(out))
})

### ttbGreedyModel ###

test_that("ttbGreedyModel on 3x3 where differs from regular ttb", {
matrix <- cbind(y=c(3:1), x1=c(1,0,0), x2=c(1,0,1))
model <- ttbGreedyModel(matrix, 1, c(2:3))
expect_equal(1, predictPair(oneRow(matrix, 1),
oneRow(matrix, 2), model))
expect_equal(1, predictPair(oneRow(matrix, 1),
oneRow(matrix, 3), model))
# Below is the row pair that differs from regular ttb.
expect_equal(1, predictPair(oneRow(matrix, 2),
oneRow(matrix, 3), model))
# After using x1, it sees only last two rows of x2.  It reverses them
# to get a validity 1.0 cue, which is why it predicts 2 vs. 3 correctly.
expect_equal(c(x1=1.0, x2=1.0), model\$cue_validities)
})

test_that("ttbGreedyModel on 3x3 where differs from regular ttb reverse cue values", {
matrix <- cbind(y=c(3:1), x1=c(0,1,1), x2=c(0,1,0))
model <- ttbGreedyModel(matrix, 1, c(2:3))
expect_equal(1, predictPair(oneRow(matrix, 1),
oneRow(matrix, 2), model))
expect_equal(1, predictPair(oneRow(matrix, 1),
oneRow(matrix, 3), model))
# Below is the row pair that differs from regular ttb.
expect_equal(1, predictPair(oneRow(matrix, 2),
oneRow(matrix, 3), model))
# After using x1, it sees only last two rows of x2.  It reverses them
# to get a validity 1.0 cue, which is why it predicts 2 vs. 3 correctly.
expect_equal(c(x1=1.0, x2=1.0), model\$cue_validities)
})

test_that("ttbGreedyModel on 2 same cues- differs from regular ttb", {
matrix <- cbind(y=c(2:1), x1=c(1,0), x2=c(1,0))
model <- ttbGreedyModel(matrix, 1, c(2:3))
full_matrix <- cbind(y=c(3:1), x1=c(1,0,0), x2=c(1,1,0))
out <- percentCorrectList(full_matrix, list(model))
# Greedy TTB uses only one cue (random which one), so it has to guess on
# one row pair.  Accuracy = (1+1+0.5)/3.
expect_equal(83.333, out\$ttbGreedyModel, tolerance=0.001)
# One cue has NA, but we don't know which one.
expect_equal(c(1.0, NA), sort(unname(model\$cue_validities),
na.last=TRUE))
})

### prob helper functions ###

test_that("indexOfCueUsed 3 simple cues", {
cv <- c(0.9, 0.8, 0.7)
# Indexes are 1-based.  As long as cue 1 discriminates, use it.
expect_equal(1, indexOfCueUsed(cv, cbind(1,1,1), cbind(0,0,0)))
expect_equal(1, indexOfCueUsed(cv, cbind(1,1,1), cbind(0,0,1)))
expect_equal(1, indexOfCueUsed(cv, cbind(1,1,1), cbind(0,1,0)))
expect_equal(1, indexOfCueUsed(cv, cbind(1,1,1), cbind(0,1,1)))
# First cue does not discriminate.  Have to go to 2nd cue.
expect_equal(2, indexOfCueUsed(cv, cbind(1,1,1), cbind(1,0,0)))
expect_equal(2, indexOfCueUsed(cv, cbind(1,1,1), cbind(1,0,1)))
# First 2 cues do not discriminate.  Have to go to 3rd cue.
expect_equal(3, indexOfCueUsed(cv, cbind(1,1,1), cbind(1,1,0)))
# The above are 7 of the 8 possible combinations.
# The case where no cue discriminates is a separate test.
})

test_that("indexOfCueUsed 3 simple cues none discriminate", {
cv <- c(0.9, 0.8, 0.7)
expect_equal(-1, indexOfCueUsed(cv, cbind(1,1,1), cbind(1,1,1)))
# Should get same result with reversed
expect_equal(-1, indexOfCueUsed(rev(cv), cbind(1,1,1), cbind(1,1,1)))
})

test_that("indexOfCueUsed 3 simple cue order reversed", {
# Same cue validities as above.
cv_orig <- c(0.9, 0.8, 0.7)
# Reverse them.
cv <- rev(cv_orig)
# Indexes ar 1-based.  All cues discriminate, so choose the
# highest-validity cue.
expect_equal(3, indexOfCueUsed(cv, cbind(1,1,1), cbind(0,0,0)))
expect_equal(3, indexOfCueUsed(cv, cbind(1,1,1), cbind(1,0,0)))
expect_equal(3, indexOfCueUsed(cv, cbind(1,1,1), cbind(0,1,0)))
expect_equal(3, indexOfCueUsed(cv, cbind(1,1,1), cbind(1,1,0)))
# First cue does not discriminate.  Have to go to 2nd cue.
expect_equal(2, indexOfCueUsed(cv, cbind(1,1,1), cbind(0,0,1)))
expect_equal(2, indexOfCueUsed(cv, cbind(1,1,1), cbind(1,0,1)))
# First 2 cues do not discriminate.  Have to go to 3rd cue.
expect_equal(1, indexOfCueUsed(cv, cbind(1,1,1), cbind(0,1,1)))
})

test_that("indexOfCueUsed 3 simple cues rows reversed", {
cv <- c(0.9, 0.8, 0.7)
# Indexes are 1-based.  As long as cue 1 discriminates, use it.
expect_equal(1, indexOfCueUsed(cv, cbind(0,0,0), cbind(1,1,1)))
expect_equal(1, indexOfCueUsed(cv, cbind(0,0,1), cbind(1,1,1)))
expect_equal(1, indexOfCueUsed(cv, cbind(0,1,0), cbind(1,1,1)))
expect_equal(1, indexOfCueUsed(cv, cbind(0,1,1), cbind(1,1,1)))
# First cue does not discriminate.  Have to go to 2nd cue.
expect_equal(2, indexOfCueUsed(cv, cbind(1,0,0), cbind(1,1,1)))
expect_equal(2, indexOfCueUsed(cv, cbind(1,0,1), cbind(1,1,1)))
# First 2 cues do not discriminate.  Have to go to 3rd cue.
expect_equal(3, indexOfCueUsed(cv, cbind(1,1,0), cbind(1,1,1)))
# The above are 7 of the 8 possible combinations.
# The case where no cue discriminates is same when rows reversed.
})

### unitWeightModel ###

test_that("unitWeightModel 2x3 pos neg", {
model <- unitWeightModel(matrix(c(5,4,1,0,0,1), 2, 3), 1, c(2,3))
expect_equal(c(1,0),  model\$cue_validities_unreversed)
expect_equal(1,  coef(model)[[1]])
expect_equal(-1,  coef(model)[[2]])
expect_equal(2, length(coef(model)))
})

test_that("unitWeightModel 5x1 75", {
model <- unitWeightModel(matrix(c(5,4,3,2,1,1,1,1,0,1), 5, 2), 1, c(2))
expect_equal(c(0.75),  model\$cue_validities_unreversed)
expect_equal(1,  coef(model)[[1]])
expect_equal(1, length(coef(model)))
})

test_that("unitWeightModel 5x1 25", {
model <- unitWeightModel(matrix(c(5,4,3,2,1,1,0,1,1,1), 5, 2), 1, c(2))
expect_equal(c(0.25),  model\$cue_validities_unreversed)
expect_equal(-1,  coef(model)[[1]])
expect_equal(1, length(coef(model)))
})

test_that("unitWeightModel 4x4 predictPair 3nd cue dominates non-binary reverse cue", {
train_df <- data.frame(Y=c(9,8,7,6), a=c(1,1,0,1), b=c(1,1,0,1),
c=c(0,0,0,0.1))
# How this data looks:
# > train_df
#   Y a b   c
# 1 9 1 1 0.0
# 2 8 1 1 0.0
# 3 7 0 0 0.0
# 4 6 1 1 0.1
# Column Y is the criterion column.  Cues follow.
# Cue a and b have validity 2/3, cue c has validity validity 0,
# but that validity is 1.0 when reversed.
# Cue c predicts Row 3 > Row 4.
# But if you sum all cue weights, predict Row 4 > Row 3
model <- unitWeightModel(train_df, 1, c(2:4))
expect_equal(c(a=0.667, b=0.667, c=0), model\$cue_validities_unreversed,
tolerance=0.002)
expect_equal(c(a=0.667, b=0.667, c=1), model\$cue_validities,
tolerance=0.002)
expect_equal(c(a=1, b=1, c=-1), model\$linear_coef, tolerance=0.002)
expect_equal(-1, predictPair(oneRow(train_df, 3),
oneRow(train_df, 4), model))
expect_equal(1, predictPair(oneRow(train_df, 4),
oneRow(train_df, 3), model))
})

### validityWeightModel ###

test_that("validityWeightModel 2x3 predictPair pos neg reverse_cues FALSE", {
train_matrix <- cbind(y=c(5,4), x1=c(1,0), x2=c(0,1))
model <- validityWeightModel(train_matrix, 1, c(2,3), reverse_cues=FALSE)
expect_equal(c(x1=1, x2=0),  model\$cue_validities_unreversed)
expect_equal(c(x1=1, x2=0),  model\$linear_coef)
# Another way to get the linear coefficients.
expect_equal(c(x1=1, x2=0),  coef(model))
expect_equal(1, predictPair(oneRow(train_matrix, 1),
oneRow(train_matrix, 2), model))
})

test_that("validityWeightModel 2x3 predictPair pos neg", {
train_matrix <- cbind(y=c(5,4), x1=c(1,0), x2=c(0,1))
model <- validityWeightModel(train_matrix, 1, c(2,3))
expect_equal(c(x1=1, x2=0),  model\$cue_validities_unreversed)
expect_equal(c(x1=1, x2=-1),  model\$linear_coef)
expect_equal(1, predictPair(oneRow(train_matrix, 1),
oneRow(train_matrix, 2), model))
})

test_that("validityWeightModel rowPairApply 5x1 75", {
train_matrix <- cbind(y=c(5,4,3,2,1), x1=c(1,1,1,0,1))
model <- validityWeightModel(train_matrix, 1, c(2))
expect_equal(c(x1=0.75),  model\$cue_validities_unreversed)
expect_equal(c(x1=0.75),  model\$linear_coef)
out <- rowPairApply(train_matrix, rowIndexes(), heuristics(model))

expect_equal(0,  getPrediction_raw(out, c(1,2)), tolerance=0.002)
expect_equal(0,  getPrediction_raw(out, c(1,3)), tolerance=0.002)
expect_equal(1,  getPrediction_raw(out, c(1,4)), tolerance=0.002)
expect_equal(0,  getPrediction_raw(out, c(1,5)), tolerance=0.002)

expect_equal(-1, getPrediction_raw(out, c(4,5)), tolerance=0.002)
})

test_that("validityWeightModel 5x1 25 reverse_cues FALSE", {
train_matrix <- cbind(y=c(5,4,3,2,1), x1=c(1,0,1,1,1))
model <- validityWeightModel(train_matrix, 1, c(2), reverse_cues=FALSE)
expect_equal(c(x1=0.25),  model\$cue_validities_unreversed)
# No cue reversal means cue_validities is the same.
expect_equal(c(x1=0.25),  model\$cue_validities)
# No cue reversal means coefficients are same as cue validities.
expect_equal(c(x1=0.25),  coef(model))
out <- rowPairApply(train_matrix, rowIndexes(), heuristics(model))
expect_equal(1,  getPrediction_raw(out, c(1,2)), tolerance=0.002)
expect_equal(0,  getPrediction_raw(out, c(1,3)), tolerance=0.002)
expect_equal(0,  getPrediction_raw(out, c(1,4)), tolerance=0.002)
expect_equal(0,  getPrediction_raw(out, c(1,5)), tolerance=0.002)

expect_equal(-1, getPrediction_raw(out, c(2,3)), tolerance=0.002)
})

test_that("validityWeightModel 5x1 25", {
train_matrix <- cbind(y=c(5,4,3,2,1), x1=c(1,0,1,1,1))
# By default, reverse_cues is TRUE
model <- validityWeightModel(train_matrix, 1, c(2))
expect_equal(c(x1=0.25),  model\$cue_validities_unreversed)
# Cue reversal changes validity 0.25 to 0.75.
expect_equal(c(x1=0.75),  model\$cue_validities)
# Cue reversal changes coefficient from 0.75 to -0.75.
expect_equal(c(x1=-0.75),  coef(model))

out <- rowPairApply(train_matrix, rowIndexes(), heuristics(model))
expect_equal(-1, getPrediction_raw(out, c(1,2)), tolerance=0.002)
expect_equal(0,  getPrediction_raw(out, c(1,3)), tolerance=0.002)
expect_equal(0,  getPrediction_raw(out, c(1,4)), tolerance=0.002)
expect_equal(0,  getPrediction_raw(out, c(1,5)), tolerance=0.002)

expect_equal(1,  getPrediction_raw(out, c(2,3)), tolerance=0.002)
})

test_that("validityWeightModel 4x4 predictPair 3nd cue dominates non-binary reverse cue", {
train_df <- data.frame(Y=c(9,8,7,6), a=c(1,1,0,1), b=c(1,1,0,1), c=c(0,0,0,0.1))
# How this data looks:
# > train_df
#   Y a b   c
# 1 9 1 1 0.0
# 2 8 1 1 0.0
# 3 7 0 0 0.0
# 4 6 1 1 0.1
# Column Y is the criterion column.  Cues follow.
# Cue a and b have validity 2/3, cue c has validity validity 0,
# but that validity is 1.0 when reversed.
# Cue c predicts Row 3 > Row 4.
# But if you sum all cue weights, predict Row 4 > Row 3
model <- validityWeightModel(train_df, 1, c(2:4), reverse_cues=FALSE)
expect_equal(c(a=0.667, b=0.667, c=0), model\$cue_validities_unreversed,
tolerance=0.002)
# Soon: Linear coef will include reversing the cue pointed the wrong way.
expect_equal(c(a=0.667, b=0.667, c=0), model\$linear_coef, tolerance=0.002)

expect_equal(-1, predictPair(oneRow(train_df, 3),
oneRow(train_df, 4), model))
expect_equal(1, predictPair(oneRow(train_df, 4),
oneRow(train_df, 3), model))
})

### tallyModel ###

test_that("tallyModel 2x3 predictPair pos", {
train_matrix <- cbind(y=c(5,4), x1=c(1,0))
model <- tallyModel(train_matrix, 1, c(2))
expect_equal(c(x1=1),  model\$linear_coef)
expect_equal(1, predictPair(oneRow(train_matrix, 1),
oneRow(train_matrix, 2), model))
})

test_that("tallyModel 2x3 predictPair neg", {
train_matrix <- cbind(y=c(5,4), x2=c(0,1))
model <- tallyModel(train_matrix, 1, c(2))
expect_equal(c(x2=-1),  model\$linear_coef)
expect_equal(1, predictPair(oneRow(train_matrix, 1),
oneRow(train_matrix, 2), model))
})

test_that("tallyModel 2x3 predictPair pos neg", {
train_matrix <- cbind(y=c(5,4), x1=c(1,0), x2=c(0,1))
model <- tallyModel(train_matrix, 1, c(2, 3))
expect_equal(c(x1=1, x2=-1),  model\$linear_coef)
expect_equal(1, predictPair(oneRow(train_matrix, 1),
oneRow(train_matrix, 2), model))
})

test_that("tallyModel rowPairApply 5x1 75", {
train_matrix <- cbind(y=c(5,4,3,2,1), x1=c(1,1,1,0,1))
model <- tallyModel(train_matrix, 1, c(2))
expect_equal(c(x1=1),  model\$linear_coef)
expect_equal(0, predictPair(oneRow(train_matrix, 1),
oneRow(train_matrix, 2), model))
expect_equal(1, predictPair(oneRow(train_matrix, 1),
oneRow(train_matrix, 4), model))
expect_equal(-1, predictPair(oneRow(train_matrix, 4),
oneRow(train_matrix, 5), model))
})

test_that("tallyModel rowPairApply 5x2 75 2/3", {
train_matrix <- cbind(y=c(5,4,3,2,1), x1=c(1,1,1,0,1), x2=c(1,1,1,0,1))
model <- tallyModel(train_matrix, 1, c(2, 3))
expect_equal(c(x1=1, x2=1),  model\$linear_coef)
expect_equal(0, predictPair(oneRow(train_matrix, 1),
oneRow(train_matrix, 2), model))
expect_equal(0, predictPair(oneRow(train_matrix, 1),
oneRow(train_matrix, 3), model))
expect_equal(1, predictPair(oneRow(train_matrix, 1),
oneRow(train_matrix, 4), model))
expect_equal(0, predictPair(oneRow(train_matrix, 1),
oneRow(train_matrix, 5), model))
expect_equal(1, predictPair(oneRow(train_matrix, 3),
oneRow(train_matrix, 4), model))
expect_equal(-1, predictPair(oneRow(train_matrix, 4),
oneRow(train_matrix, 5), model))

})

test_that("tallyModel rowPairApply 5x2 cues disagree", {
train_matrix <- cbind(y=c(5,4,3,2,1), x1=c(1,1,1,0,1), x2=c(1,1,1,1,0))
model <- tallyModel(train_matrix, 1, c(2, 3))
expect_equal(c(x1=1, x2=1),  model\$linear_coef)
expect_equal(0, predictPair(oneRow(train_matrix, 4),
oneRow(train_matrix, 5), model))
})

### regInterceptModel ###

test_that("regInterceptModel 2x2 fit pos slope", {
train_matrix <- cbind(y=c(5,4), x1=c(1,0))
model <- regInterceptModel(train_matrix, 1, c(2))
expect_equal(4,  coef(model)[[1]])  # intercept
expect_equal(1,  coef(model)[[2]])  # slope
expect_equal(2, length(coef(model)))
expect_equal(1, predictPair(oneRow(train_matrix, 1),
oneRow(train_matrix, 2), model))
})

test_that("regInterceptModel 2x2 fit neg slope", {
train_matrix <- cbind(y=c(5,4), x1=c(0,1))
model <- regInterceptModel(train_matrix, 1, c(2))
expect_equal(5,  coef(model)[[1]])  # intercept
expect_equal(-1,  coef(model)[[2]])  # slope
expect_equal(1, predictPair(oneRow(train_matrix, 1),
oneRow(train_matrix, 2), model))
})

test_that("regInterceptModel 2x2 fit pos slope -- data.frame", {
train_df <- data.frame(y=c(5,4), x1=c(1,0))
model <- regInterceptModel(train_df, 1, c(2))
expect_equal(4,  coef(model)[[1]])  # intercept
expect_equal(1,  coef(model)[[2]])  # slope
expect_equal(2, length(coef(model)))
expect_equal(1, predictPair(oneRow(train_df, 1),
oneRow(train_df, 2), model))
})

test_that("lmWrapper 2x2 fit pos slope -- no intercept", {
train_matrix <- cbind(y=c(5,4), x1=c(1,0))
model <- lmWrapper(train_matrix, 1, c(2),  include_intercept=FALSE)
expect_equal(5,  coef(model)[[1]])  # slope
expect_equal(1, length(coef(model)))
})

test_that("regInterceptModel 2x3 fit 4.5,1,NA", {
train_matrix <- cbind(y=c(5,4), x1=c(1,0), x2=c(0,1))
model <- regInterceptModel(train_matrix, 1, c(2,3))
expect_equal(4,  coef(model)[[1]])  # intercept
expect_equal(1,  coef(model)[[2]])  # x1
#TODO(jean): Ideally regInterceptModel would randomize which cue got the NA coef.
# Right now, it's always the 2nd cue that gets the NA.
expect_true( is.na(coef(model)[[3]]) )  # x2 excluded because too many columns
expect_equal(1, predictPair(oneRow(train_matrix, 1),
oneRow(train_matrix, 2), model))
})

test_that("regInterceptModel 2x3 fit 4,1 (col 3 not fit)", {
model <- regInterceptModel(cbind(y=c(5,4), x1=c(1,0), x2=c(0,1)), 1, c(2))
expect_equal(4,  coef(model)[[1]])  # intercept
expect_equal(1,  coef(model)[[2]])  # x1
expect_equal(2, length(coef(model)))
})

test_that("regInterceptModel 2x3 fit 5,-1 (col 2 not fit)", {
model <- regInterceptModel(cbind(y=c(5,4), x1=c(1,0), x2=c(0,1)), 1, c(3))
expect_equal(5,  coef(model)[[1]])  # intercept
expect_equal(-1,  coef(model)[[2]])  # x1
expect_equal(2, length(coef(model)))
})

test_that("regInterceptModel 3x3 fit positive negative", {
model <- regInterceptModel(cbind(y=c(5,4,3), x1=c(1,0,0), x2=c(0,0,1)), 1, c(2,3))
expect_equal(4,  coef(model)[[1]])  # intercept
expect_equal(1,  coef(model)[[2]])  # V2
expect_equal(-1,  coef(model)[[3]])  # V3
expect_equal(3, length(coef(model)))
})

test_that("regInterceptModel 3x3 fit positive mixed", {
model <- regInterceptModel(cbind(y=c(5,4,3), x1=c(1,0,0), x2=c(1,0,1)), 1, c(2,3))
expect_equal(4,  coef(model)[[1]])  # intercept
expect_equal(2,  coef(model)[[2]])  # V2
expect_equal(-1, coef(model)[[3]])  # V3
expect_equal(3, length(coef(model)))
})

test_that("regInterceptModel predictPair with intercept (check bug)", {
tol <- 0.0001
m_train <- data.frame(y=c(5:1), x1=c(1,1,1,0,1))
model <- regInterceptModel(m_train, 1, c(2))
# Reg cannot distinguish between rows 1 and 2 based on x1.
# But in the past there was a bug where the intercept weight was
# applied to the criterion column so reg was always correct!
expect_equal(0, predictPair(oneRow(m_train, 1),
oneRow(m_train, 2), model))
})

# Warning: Not a self-contained test.  Uses city_population.
test_that("regInterceptModel predictPair city_population", {
tol <- 0.0001
model <- regInterceptModel(city_population, 3, c(4:ncol(city_population)))
# Hamburg (row 2) and Munich (row 3) differ only on the license plate, which has a
# coefficient of about 25,000.
# There is an intercept of 75k, but you can ignore it in pairs.
# So because Hamburg does not have a license plate, it should not be chosen.
expect_equal(-1, predictPair(oneRow(city_population, 2),
oneRow(city_population, 3), model))
})

### regModel ###

test_that("regModel predictPair", {
tol <- 0.0001
m_train <- data.frame(y=c(5:1), x1=c(1,1,1,0,1))
model <- regModel(m_train, 1, c(2))
# Reg cannot distinguish between rows 1 and 2 based on x1.
expect_equal(0, predictPair(oneRow(m_train, 1),
oneRow(m_train, 2), model))
# But this should be predicted correctly.
expect_equal(1, predictPair(oneRow(m_train, 1),
oneRow(m_train, 4), model))
})

### logRegModel ###

test_that("logRegModel predictPairProb 2x2 fit train_data", {
tol <- 0.0001
train_data <- cbind(y=c(5,4), x1=c(1,0))
model <- logRegModel(train_data, 1, c(2))
expect_equal(1, predictPairProb(oneRow(train_data, 1),
oneRow(train_data, 2), model))
expect_equal(0, predictPairProb(oneRow(train_data, 2),
oneRow(train_data, 1), model))
out <- rowPairApply(train_data, heuristicsProb(model))
# There is only one unique pair.
expect_equal(1, nrow(out))
})

test_that("logRegModel predictPair 2x2 fit train_data", {
tol <- 0.0001
train_data <- cbind(y=c(5,4), x1=c(1,0))
model <- logRegModel(train_data, 1, c(2))
expect_equal(1, predictPair(oneRow(train_data, 1),
oneRow(train_data, 2), model))
expect_equal(-1, predictPair(oneRow(train_data, 2),
oneRow(train_data, 1), model))
out <- rowPairApply(train_data, heuristicsProb(model))
# There is only one unique pair.
expect_equal(1, nrow(out))
})

test_that("logRegModel predictPairProb 2x2 fit train_data reverse cue", {
tol <- 0.0001
train_data <- cbind(y=c(5,4), x1=c(1,0))
model <- logRegModel(train_data, 1, c(2))
expect_equal(1, predictPairProb(oneRow(train_data, 1),
oneRow(train_data, 2), model))
expect_equal(0, predictPairProb(oneRow(train_data, 2),
oneRow(train_data, 1), model))
})

test_that("logRegModel predictPairProb 2x2,3x2 all correct", {
tol <- 0.0001
train_data <- cbind(y=c(5,4), x1=c(1,0))
model <- logRegModel(train_data, 1, c(2))
test_data <- cbind(y=c(5,4,3), x1=c(1,0,0))

expect_equal(1, predictPairProb(oneRow(test_data, 1),
oneRow(test_data, 2), model))
expect_equal(0, predictPairProb(oneRow(test_data, 2),
oneRow(test_data, 1), model))
expect_equal(1, predictPairProb(oneRow(test_data, 1),
oneRow(test_data, 3), model))
expect_equal(0, predictPairProb(oneRow(test_data, 3),
oneRow(test_data, 1), model))
# Row 2 and 3 have same cue values, so Row1 is equally likely to be greater.
expect_equal(0.5, predictPairProb(oneRow(test_data, 2),
oneRow(test_data, 3), model))
expect_equal(0.5, predictPairProb(oneRow(test_data, 3),
oneRow(test_data, 2), model))

out <- rowPairApply(test_data, heuristicsProb(model))
# There are three unique pairs.
expect_equal(3, nrow(out))
})

test_that("logRegModel predictPairProb 2x2,3x2 all incorrect", {
tol <- 0.0001
train_data <- cbind(y=c(5,4), x1=c(1,0))
model <- logRegModel(train_data, 1, c(2))
test_data <- cbind(y=c(5,4,3), x1=c(0,1,1))

out <- rowPairApply(test_data, rowIndexes(), heuristicsProb(model))
expect_equal(0,   getPrediction_raw(out, c(1,2)))
expect_equal(0,   getPrediction_raw(out, c(1,3)))
expect_equal(0.5, getPrediction_raw(out, c(2,3)))
# Confirm opposite pairs have opposite predictions.
expect_equal(1,   getPrediction_raw(out, c(2,1)))
expect_equal(1,   getPrediction_raw(out, c(3,1)))
expect_equal(0.5, getPrediction_raw(out, c(3,2)))
# There are three unique pairs.
expect_equal(3, nrow(out))
})

test_that("logRegModel predictPairProb 2x3 fit train_data", {
train_data <- cbind(y=c(5,4), x1=c(1,0), x2=c(1,0))
model <- logRegModel(train_data, 1, c(2,3))
expect_equal(1, predictPairProb(oneRow(train_data, 1),
oneRow(train_data, 2), model))
expect_equal(0, predictPairProb(oneRow(train_data, 2),
oneRow(train_data, 1), model))
})

test_that("logRegModel predictPairProb 2x3 fit train_data 2nd cue useless", {
train_data <- cbind(y=c(5,4), x1=c(1,0), x2=c(1,1))
model <- logRegModel(train_data, 1, c(2,3))
expect_equal(1, predictPairProb(oneRow(train_data, 1),
oneRow(train_data, 2), model))
expect_equal(0, predictPairProb(oneRow(train_data, 2),
oneRow(train_data, 1), model))
})

test_that("logRegModel predictPairProb 2x3 fit train_data 2nd cue reverse", {
train_data <- cbind(y=c(5,4), x1=c(1,0), x2=c(0,1))
model <- logRegModel(train_data, 1, c(2,3))
expect_equal(1, predictPairProb(oneRow(train_data, 1),
oneRow(train_data, 2), model))
expect_equal(0, predictPairProb(oneRow(train_data, 2),
oneRow(train_data, 1), model))
})

test_that("logRegModel predictPairProb 2x3 fit train_data 1st cue useless", {
train_data <- cbind(y=c(5,4), x1=c(0,0), x2=c(1,0))
model <- logRegModel(train_data, 1, c(2,3))
expect_equal(1, predictPairProb(oneRow(train_data, 1),
oneRow(train_data, 2), model))
expect_equal(0, predictPairProb(oneRow(train_data, 2),
oneRow(train_data, 1), model))
})

test_that("logRegModel percentCorrectList", {
tol <- 0.0001
train_data <- cbind(y=c(5:1), x=c(1,1,1,0,1))
model <- logRegModel(train_data, 1, c(2))
fit_accuracy <- percentCorrectList(train_data, list(model))
expect_equal(60, fit_accuracy\$logRegModel, tolerance=0.01)
})

test_that("logRegModel predictPairProb 2x2 data.frame", {
train_data <- data.frame(y=c(5,4), x1=c(1,0))
model <- logRegModel(train_data, 1, c(2))
expect_equal(1, predictPairProb(oneRow(train_data, 1),
oneRow(train_data, 2), model))
expect_equal(0, predictPairProb(oneRow(train_data, 2),
oneRow(train_data, 1), model))
out <- rowPairApply(train_data, heuristicsProb(model))
# There is only one unique pair.
expect_equal(1, nrow(out))
})

test_that("logRegModel error when train_data zero rows", {
train_data <- data.frame(y=c(), x1=c(), x2=c())
expect_error(logRegModel(train_data, 1, c(2,3)),
"Training set must have at least 2 rows but had 0 rows",
fixed=TRUE)
})

test_that("logRegModel error when train_data one row", {
train_data <- data.frame(y=c(5), x1=c(1), x2=c(0))
expect_error(logRegModel(train_data, 1, c(2,3)),
"Training set must have at least 2 rows but had 1 row",
fixed=TRUE)
})

# Test helper functions that allow logRegModel to better handle overspecified
# data.
test_that("rankByCueValidity", {
df <- data.frame(Criterion=c(5,4,3,2,1), a=c(1,0,0,0,1),
b=c(1,1,1,0,0), c=c(1,1,1,0,1))
# cue validities are a=0.5, b=1.0, c=0.75, so the 2nd cue should be used
# first, then the 3rd cue, then the 1st cue.
expect_equal(c(3,1,2), rankByCueValidity(df, 1, c(2:4)))
})

test_that("keepOrder so simple I could not mess this up, right", {
df <- data.frame(Criterion=c(5,4,3,2,1), a=c(1,0,0,0,1),
b=c(1,1,1,0,0), c=c(1,1,1,0,1))
expect_equal(c(1,2,3), keepOrder(df, 1, c(2:4)))
})

test_that("rankByCorrelation", {
df <- data.frame(Criterion=c(5,4,3,2,1), a=c(1,0,0,0,1),
b=c(1,1,1,0,0), c=c(1,1,1,0,1))
# correlations are a=0, b=0.866, c=0.354, so the 2nd cue should be used
# first, then the 3rd cue, then the 1st cue.
expect_equal(c(3,1,2), rankByCorrelation(df, 1, c(2:4)))
})

test_that("logRegModel predictPairProb cue order by validity", {
train_data <- cbind(y=c(5,4), x1=c(1,1), x2=c(1,0))
model_2_3 <- logRegModel(train_data, 1, c(2, 3))
expect_equal(c(2,3), model_2_3\$cols_to_fit)
# The stronger cue, x2, should be ordered first.
expect_equal(c(3,2), model_2_3\$sorted_cols_to_fit)
expect_equal(c(2,1), model_2_3\$cue_ordering)

model_3_2 <- logRegModel(train_data, 1, c(3, 2))
# The stronger cue, x2, should be ordered first.
expect_equal(c(3,2), model_3_2\$cols_to_fit)

expect_equal(1, predictPairProb(oneRow(train_data, 1),
oneRow(train_data, 2), model_2_3))
expect_equal(1, predictPairProb(oneRow(train_data, 1),
oneRow(train_data, 2), model_3_2))
})

test_that("logRegModel predictPairProb cue order by validity shifted", {
train_data <- data.frame(y=c(5,4), name=c("a", "b"), x1=c(1,1), x2=c(1,0))
model_2_3 <- logRegModel(train_data, 1, c(3, 4))
# The stronger cue, x2, should be ordered first.
expect_equal(c(3,4), model_2_3\$cols_to_fit)
expect_equal(c(4,3), model_2_3\$sorted_cols_to_fit)
expect_equal(c(2,1), model_2_3\$cue_ordering)

expect_equal(1, predictPairProb(oneRow(train_data, 1),
oneRow(train_data, 2), model_2_3))
})

test_that("logRegModel overspecified keepOrder", {
# Cues x1 and x2 are the same in training data, equally predictive of y.
# Either cue could be used while the other is dropped because the model is
# overspecified (two cues for only one row).
train_data <- cbind(y=c(5,4), x1=c(1,0), x2=c(1,0))
model_2_3 <- logRegModel(train_data, 1, c(2, 3),
cue_order_fn=keepOrder)
expect_equal(c(2 ,3), model_2_3\$cols_to_fit)

model_3_2 <- logRegModel(train_data, 1, c(3, 2),
cue_order_fn=keepOrder)
expect_equal(c(3, 2), model_3_2\$cols_to_fit)

# In test data, cues x1 and x2 point in opposite direction, so the
# prediction depends on which cue is used first.
test_data <- cbind(y=c(5,4), x1=c(1,0), x2=c(0,1))

expect_equal(1, predictPairProb(oneRow(test_data, 1),
oneRow(test_data, 2), model_2_3))
expect_equal(0, predictPairProb(oneRow(test_data, 1),
oneRow(test_data, 2), model_3_2))
})

# TODO: Move tests below to a new batch test file.

test_that("logRegModel percentCorrectList easy 100%", {
df <- data.frame(Criterion=c(5,4,3,2,1), a=c(5,4,3,2,1))
model <- logRegModel(df, 1, c(2))
out <- percentCorrectList(df, list(model))
expect_equal(100, out[, "logRegModel"])
})

test_that("logRegModel percentCorrectList cue reverse easy 100%", {
df <- data.frame(Criterion=c(5,4,3,2,1), a=c(1,2,3,4,5))
model <- logRegModel(df, 1, c(2))
out <- percentCorrectList(df, list(model))
expect_equal(100, out[, "logRegModel"])
})

test_that("logRegModel percentCorrectList criterion reverse easy 100%", {
df <- data.frame(Criterion=c(1,2,3,4,5), a=c(5,4,3,2,1))
model <- logRegModel(df, 1, c(2))
out <- percentCorrectList(df, list(model))
expect_equal(100, out[, "logRegModel"])
})

## singleCueModel

test_that("singleCueModel 4x2 guess when first cue non-discriminate", {
train_df <- data.frame(criterion=c(9,8,7,6), a=c(101,101,2,2), b=c(59,58,5,59))
# Cue a has validity 1, cue b has validity 0.6.
# Cue a cannot discriminate between row 1 and 2, so it will return 0.5.
# Single cue will not use cue b to help.
model <- singleCueModel(train_df, 1, c(2:3))
expect_equal(c(a=1, b=0.6), model\$cue_validities_unreversed, tolerance=0.002)
expect_equal(c(a=1, b=0.6), model\$cue_validities, tolerance=0.002)
# Only the highest-validity cue gets a weight-- the rest are zeroes.
expect_equal(c(a=1, b=0), coef(model), tolerance=0.002)
expect_equal(0, predictPair(oneRow(train_df, 1),
oneRow(train_df, 2), model))
expect_equal(0, predictPair(oneRow(train_df, 2),
oneRow(train_df, 1), model))
})

test_that("singleCueModel 4x3 real value cue c dominates", {
train_df <- data.frame(criterion=c(900,400,100,6), a=c(101,101,20,101),
b=c(59,59,5,59), c=c(90,80,70,10))
# Cue a and b have validity 2/3, cue c has validity 1.
# Cue c predicts Row 3 > Row 4.
# But if you sum all cue weights, predict Row 4 > Row 3
model <- singleCueModel(train_df, 1, c(2:4))
expect_equal(c(a=0.667, b=0.667, c=1), model\$cue_validities_unreversed, tolerance=0.002)
expect_equal(c(a=0.667, b=0.667, c=1), model\$cue_validities, tolerance=0.002)
# Only the highest-validity cue gets a weight-- the rest are zeroes.
expect_equal(c(a=0, b=0, c=1), coef(model), tolerance=0.002)
expect_equal(1, predictPair(oneRow(train_df, 3),
oneRow(train_df, 4), model))
expect_equal(-1, predictPair(oneRow(train_df, 4),
oneRow(train_df, 3), model))
})

test_that("singleCueModel 4x3 real value cue c dominates after reversal", {
train_df <- data.frame(criterion=c(900,400,100,6), a=c(101,101,20,101), b=c(59,59,5,59),
c=c(10,70,80,90))
# Cue a and b have validity 2/3, cue c has validity 0, reversed to 1.
# Cue c predicts Row 3 > Row 4.
# But if you sum all cue weights, predict Row 4 > Row 3
model <- singleCueModel(train_df, 1, c(2:4))
expect_equal(c(a=0.667, b=0.667, c=0), model\$cue_validities_unreversed, tolerance=0.002)
expect_equal(c(a=0.667, b=0.667, c=1), model\$cue_validities, tolerance=0.002)
# Only the highest-validity cue gets a weight-- the rest are zeroes.
expect_equal(c(a=0, b=0, c=-1), coef(model), tolerance=0.002)

expect_equal(1, predictPair(oneRow(train_df, 3),
oneRow(train_df, 4), model))
expect_equal(-1, predictPair(oneRow(train_df, 4),
oneRow(train_df, 3), model))
})

test_that("singleCueModel 4x3 real value cue a and b have same validity", {
train_df <- data.frame(criterion=c(900,400,100,6), a=c(101,101,20,101), b=c(59,59,5,59))
# Cue a and b have validity 2/3, the model should pick one cue at random rather than using both
model <- singleCueModel(train_df, 1, c(2:3))

expect_equal(1, sum(coef(model)))
})

## minModel

test_that("minModel predictPair 2x2 forward", {
train_data <- cbind(y=c(5,4), x1=c(1,0))
model <- minModel(train_data, 1, c(2))
expect_equal(1, predictPair(oneRow(train_data, 1),
oneRow(train_data, 2), model))
expect_equal(-1, predictPair(oneRow(train_data, 2),
oneRow(train_data, 1), model))
})

test_that("minModel predictPair 2x2 reverse cue", {
train_data <- cbind(y=c(5,4), x1=c(0,1))
model <- minModel(train_data, 1, c(2))
expect_equal(1, predictPair(oneRow(train_data, 1),
oneRow(train_data, 2), model))
expect_equal(-1, predictPair(oneRow(train_data, 2),
oneRow(train_data, 1), model))
})

test_that("minModel predictPair 5x4 all cues same after reverse", {
train_data <- cbind(y=c(5,4,3,2,1), x1=c(1,0,0,0,0), x2=c(1,0,0,0,0),
x3=c(0,1,1,1,1))
model <- minModel(train_data, 1, c(2:4))
expect_equal(c(x1=1, x2=1, x3=-1), model\$cue_directions)
# Note x3 is same when reversed.
# Gives same answer consistently, no matter which cue is selected.
for (i in 1:5) {
expect_equal(1, predictPair(oneRow(train_data, 1),
oneRow(train_data, 2), model))
}
})

test_that("minModel predictPair 5x4 cue_sample_fn in_order", {
train_data <- cbind(y=c(5,4,3,2,1), x1=c(1,0,0,0,0), x2=c(1,1,0,0,1),
x3=c(1,0,0,0,1))
model <- minModel(train_data, 1, c(2:4))
# For testing purposes, force cue order to always be x1, x2, x3.
in_order <- function(x) return(x)
model\$cue_sample_fn <- in_order
expect_equal(c(x1=1, x2=1, x3=0), model\$cue_directions)
expect_equal(c(x1=1, x2=0.667, x3=0.5), model\$cue_validities_unreversed,
tolerance=0.002)

# Between row 1 and 2, x1 predicts 1 (x2: guess, x3: 1)
expect_equal(1, predictPair(oneRow(train_data, 1),
oneRow(train_data, 2), model))

# Between row 4 and 5, x1 doesn't discriminate, then x2 predicts -1.
# (x3: -1).
expect_equal(-1, predictPair(oneRow(train_data, 4),
oneRow(train_data, 5), model))
})

test_that("minModel predictPair 5x4 cue_sample_fn reverse_order", {
train_data <- cbind(y=c(5,4,3,2,1), x1=c(1,0,0,0,0), x2=c(1,1,0,0,1),
x3=c(1,0,0,0,1))
model <- minModel(train_data, 1, c(2:4))
# For testing purposes, force cue order to always be x3, x2, x1.
model\$cue_sample_fn <- rev
expect_equal(c(x1=1, x2=1, x3=0), model\$cue_directions)
expect_equal(c(x1=1, x2=0.667, x3=0.5), model\$cue_validities_unreversed,
tolerance=0.002)

# Because cue_sample_fn is reverse, start from x3.
# Between row 1 and 2, x3 predicts 1 (x1: 1, x2: guess)
expect_equal(1, predictPair(oneRow(train_data, 1),
oneRow(train_data, 2), model))

# Between row 4 and 5, x3 predicts -1 (x1: guess, x2: -1)
expect_equal(-1, predictPair(oneRow(train_data, 4),
oneRow(train_data, 5), model))
})
```

## Try the heuristica package in your browser

Any scripts or data that you put into this service are public.

heuristica documentation built on Aug. 21, 2019, 9:05 a.m.