<commit_before>package sudoku

import (
	"math"
	"math/rand"
	"testing"
)

const _NUM_RUNS_TEST_WEIGHTED_DISTRIBUTION = 10000
const _ALLOWABLE_DIFF_WEIGHTED_DISTRIBUTION = 0.01

func TestRandomWeightedIndex(t *testing.T) {

	result := randomIndexWithNormalizedWeights([]float64{1.0, 0.0})
	if result != 0 {
		t.Log("Got wrong result with random weights")
		t.Fail()
	}
	result = randomIndexWithNormalizedWeights([]float64{0.5, 0.0, 0.5})
	if result != 0 && result != 2 {
		t.Log("Didn't get one of two legal weights")
		t.Fail()
	}
	result = randomIndexWithNormalizedWeights([]float64{0.0, 0.0, 1.0})
	if result != 2 {
		t.Log("Should have gotten last item in random weights; we didn't")
		t.Fail()
	}

	if weightsNormalized([]float64{1.0, 0.000001}) {
		t.Log("thought weights were normalized when they weren't")
		t.Fail()
	}
	if !weightsNormalized([]float64{0.5, 0.25, 0.25}) {
		t.Log("Didn't think weights were normalized but they were")
		t.Fail()
	}

	if weightsNormalized([]float64{0.5, -0.25, 0.25}) {
		t.Error("A negative weight was considered normal.")
	}

	rand.Seed(1)
	result = randomIndexWithInvertedWeights([]float64{0.0, 0.0, 1.0})
	if result == 2 {
		t.Error("Got the wrong index for inverted weights")
	}

	for i := 0; i < 10; i++ {
		rand.Seed(int64(i))
		result = randomIndexWithInvertedWeights([]float64{0.5, 1.0, 0.0})
		if result == 1 {
			t.Error("RandominzedIndexWithInvertedWeights returned wrong result")
			break
		}
	}

	weightResult := normalizedWeights([]float64{2.0, 1.0, 1.0})
	if weightResult[0] != 0.5 || weightResult[1] != 0.25 || weightResult[2] != 0.25 {
		t.Log("Nomralized weights came back wrong")
		t.Fail()
	}

	weightResult = normalizedWeights([]float64{1.0, 1.0, -0.5})
	if weightResult[0] != 0.5 || weightResult[1] != 0.5 || weightResult[2] != 0 {
		t.Error("Normalized weights with a negative came back wrong: ", weightResult)
	}

	weightResult = normalizedWeights([]float64{-0.25, -0.5, 0.25})
	if weightResult[0] != 0.25 || weightResult[1] != 0 || weightResult[2] != 0.75 {
		t.Error("Normalized weights with two different negative numbers came back wrong: ", weightResult)
	}

	result = randomIndexWithWeights([]float64{1.0, 0.0})
	if result != 0 {
		t.Log("Got wrong result with random weights")
		t.Fail()
	}
	result = randomIndexWithWeights([]float64{5.0, 0.0, 5.0})
	if result != 0 && result != 2 {
		t.Log("Didn't get one of two legal weights")
		t.Fail()
	}
	result = randomIndexWithWeights([]float64{0.0, 0.0, 5.0})
	if result != 2 {
		t.Log("Should have gotten last item in random weights; we didn't")
		t.Fail()
	}
	for i := 0; i < 100; i++ {
		rand.Seed(int64(i))
		result = randomIndexWithWeights([]float64{1.0, 10.0, 0.5, -1.0, 0.0, 6.4})
		if result == 3 {
			t.Error("Random index with weights picked wrong index with seed ", i)
		}
	}
	for i := 0; i < 100; i++ {
		rand.Seed(int64(i))
		result = randomIndexWithWeights([]float64{1.0, 10.0, 0.5, 1.0, 0.0, 6.4, 0.0})
		if result == 4 || result == 6 {
			t.Error("Random index with weights that ended in zero picked wrong index with seed ", i)
		}
	}
}

func TestWeightedRandomDistribution(t *testing.T) {

	//We're just going to bother testing randomIndexWithInvertedWeights since that's the one we actually use
	//in HumanSolve.

	type distributionTestCase struct {
		input       []float64
		expected    []float64
		description string
	}

	cases := []distributionTestCase{
		{
			[]float64{
				0.0,
				1.0,
				2.0,
			},
			[]float64{
				0.66666666666,
				0.33333333333,
				0.0,
			},
			"0 1 2",
		},
		{
			[]float64{
				0.0,
			},
			[]float64{
				1.0,
			},
			"0.0",
		},
		{
			[]float64{
				10.0,
			},
			[]float64{
				1.0,
			},
			"10.0",
		},
		{
			[]float64{
				0.5,
				0.5,
				1.0,
			},
			[]float64{
				0.5,
				0.5,
				0.0,
			},
			"0.5, 0.5, 1.0",
		},
		{
			[]float64{
				1.0,
				100.0,
				0.5,
				-1.0,
				0.0,
				6.4,
			},
			[]float64{
				0.20077063475968,
				0.0,
				0.20178462786453,
				0.20482660717907,
				0.20279862096938,
				0.18981950922734,
			},
			"1.0, 100.0, 0.5, -1.0, 0.0, 6.4",
		},
		{
			[]float64{
				3.0,
				3.0,
				4.0,
				4.0,
				4.0,
				4.0,
				100.0,
				100.0,
				400.0,
			},
			[]float64{
				0.13331094694426,
				0.13331094694426,
				0.13297515110813,
				0.13297515110813,
				0.13297515110813,
				0.13297515110813,
				0.10073875083949,
				0.10073875083949,
				0.0,
			},
			"Many at same weight; exponential incrase",
		},
	}

	for _, testCase := range cases {<commit_msg>Added a note next to the last test, about why that distribution seems wrong.<commit_after>package sudoku

import (
	"math"
	"math/rand"
	"testing"
)

const _NUM_RUNS_TEST_WEIGHTED_DISTRIBUTION = 10000
const _ALLOWABLE_DIFF_WEIGHTED_DISTRIBUTION = 0.01

func TestRandomWeightedIndex(t *testing.T) {

	result := randomIndexWithNormalizedWeights([]float64{1.0, 0.0})
	if result != 0 {
		t.Log("Got wrong result with random weights")
		t.Fail()
	}
	result = randomIndexWithNormalizedWeights([]float64{0.5, 0.0, 0.5})
	if result != 0 && result != 2 {
		t.Log("Didn't get one of two legal weights")
		t.Fail()
	}
	result = randomIndexWithNormalizedWeights([]float64{0.0, 0.0, 1.0})
	if result != 2 {
		t.Log("Should have gotten last item in random weights; we didn't")
		t.Fail()
	}

	if weightsNormalized([]float64{1.0, 0.000001}) {
		t.Log("thought weights were normalized when they weren't")
		t.Fail()
	}
	if !weightsNormalized([]float64{0.5, 0.25, 0.25}) {
		t.Log("Didn't think weights were normalized but they were")
		t.Fail()
	}

	if weightsNormalized([]float64{0.5, -0.25, 0.25}) {
		t.Error("A negative weight was considered normal.")
	}

	rand.Seed(1)
	result = randomIndexWithInvertedWeights([]float64{0.0, 0.0, 1.0})
	if result == 2 {
		t.Error("Got the wrong index for inverted weights")
	}

	for i := 0; i < 10; i++ {
		rand.Seed(int64(i))
		result = randomIndexWithInvertedWeights([]float64{0.5, 1.0, 0.0})
		if result == 1 {
			t.Error("RandominzedIndexWithInvertedWeights returned wrong result")
			break
		}
	}

	weightResult := normalizedWeights([]float64{2.0, 1.0, 1.0})
	if weightResult[0] != 0.5 || weightResult[1] != 0.25 || weightResult[2] != 0.25 {
		t.Log("Nomralized weights came back wrong")
		t.Fail()
	}

	weightResult = normalizedWeights([]float64{1.0, 1.0, -0.5})
	if weightResult[0] != 0.5 || weightResult[1] != 0.5 || weightResult[2] != 0 {
		t.Error("Normalized weights with a negative came back wrong: ", weightResult)
	}

	weightResult = normalizedWeights([]float64{-0.25, -0.5, 0.25})
	if weightResult[0] != 0.25 || weightResult[1] != 0 || weightResult[2] != 0.75 {
		t.Error("Normalized weights with two different negative numbers came back wrong: ", weightResult)
	}

	result = randomIndexWithWeights([]float64{1.0, 0.0})
	if result != 0 {
		t.Log("Got wrong result with random weights")
		t.Fail()
	}
	result = randomIndexWithWeights([]float64{5.0, 0.0, 5.0})
	if result != 0 && result != 2 {
		t.Log("Didn't get one of two legal weights")
		t.Fail()
	}
	result = randomIndexWithWeights([]float64{0.0, 0.0, 5.0})
	if result != 2 {
		t.Log("Should have gotten last item in random weights; we didn't")
		t.Fail()
	}
	for i := 0; i < 100; i++ {
		rand.Seed(int64(i))
		result = randomIndexWithWeights([]float64{1.0, 10.0, 0.5, -1.0, 0.0, 6.4})
		if result == 3 {
			t.Error("Random index with weights picked wrong index with seed ", i)
		}
	}
	for i := 0; i < 100; i++ {
		rand.Seed(int64(i))
		result = randomIndexWithWeights([]float64{1.0, 10.0, 0.5, 1.0, 0.0, 6.4, 0.0})
		if result == 4 || result == 6 {
			t.Error("Random index with weights that ended in zero picked wrong index with seed ", i)
		}
	}
}

func TestWeightedRandomDistribution(t *testing.T) {

	//We're just going to bother testing randomIndexWithInvertedWeights since that's the one we actually use
	//in HumanSolve.

	type distributionTestCase struct {
		input       []float64
		expected    []float64
		description string
	}

	cases := []distributionTestCase{
		{
			[]float64{
				0.0,
				1.0,
				2.0,
			},
			[]float64{
				0.66666666666,
				0.33333333333,
				0.0,
			},
			"0 1 2",
		},
		{
			[]float64{
				0.0,
			},
			[]float64{
				1.0,
			},
			"0.0",
		},
		{
			[]float64{
				10.0,
			},
			[]float64{
				1.0,
			},
			"10.0",
		},
		{
			[]float64{
				0.5,
				0.5,
				1.0,
			},
			[]float64{
				0.5,
				0.5,
				0.0,
			},
			"0.5, 0.5, 1.0",
		},
		{
			[]float64{
				1.0,
				100.0,
				0.5,
				-1.0,
				0.0,
				6.4,
			},
			[]float64{
				0.20077063475968,
				0.0,
				0.20178462786453,
				0.20482660717907,
				0.20279862096938,
				0.18981950922734,
			},
			"1.0, 100.0, 0.5, -1.0, 0.0, 6.4",
		},
		{
			[]float64{
				3.0,
				3.0,
				4.0,
				4.0,
				4.0,
				4.0,
				100.0,
				100.0,
				400.0,
			},
			//TODO: think about this hard... This probability seems wrong for what we're trying to accomplish.
			// The precense of the very high numbers makes it so that the early items are picked at a similar
			//rate to the later ones that should be an order of magnitude less likely. This kind of condition
			//happens a lot in HumanSolve (all you need is one high weighted technique), and would explain why
			//we have kind of odd selections of steps.
			[]float64{
				0.13331094694426,
				0.13331094694426,
				0.13297515110813,
				0.13297515110813,
				0.13297515110813,
				0.13297515110813,
				0.10073875083949,
				0.10073875083949,
				0.0,
			},
			"Many at same weight; exponential incrase",
		},
	}

	for _, testCase := range cases {
{'fraction_non_alphanumeric': 0.16039228092375832, 'fraction_numerical': 0.1187387957397448, 'mean_word_length': 2.864710676446618, 'pattern_counts': {'":': 0, '<': 9, '<?xml version=': 0, '>': 3, 'https://': 0, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 4, 'word_list_counts': {'cursed_substrings.json': 0, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '2815426', 'n_tokens_mistral': 4886, 'n_tokens_neox': 3770, 'n_words': 912}