Commit ca099d43 authored by Chanelle Lee's avatar Chanelle Lee
Browse files

add tests and changes from pc

parent 46ba8a6d
......@@ -10,6 +10,6 @@ include_directories(${SOURCE_DIR})
set(SOURCES "${SOURCE_DIR}/agentFunctions.cpp")
# Generate python module
#find_package(pybind11 REQUIRED)
add_subdirectory(pybind11)
find_package(pybind11 REQUIRED)
#add_subdirectory(pybind11)
pybind11_add_module(agentFunctions ${SOURCES} "${SOURCE_DIR}/bindings.cpp")
......@@ -37,15 +37,29 @@ class Agent(object):
numOptions : int
Number of options to choose between
noise : float
Between [0, 1] signifying the noisiness of the agent's sensors.
Based on the lambda in the theory.
"""
self.idNum = idNum
Between [0, inf] signifying the noisiness of the agent's sensors.
Based on the lambda in the theory. Else -1 for noiseless.
"""
if not (0.0 < distrust < 0.5):
raise ValueError("Passed distrust invalid - must be in (0, 0.5)")
if not (0.0 <= w <= 1.0):
raise ValueError("Passed w invalid - must be in [0, 1]")
# Check that belief has the right shape, sums to 1 and all the values
# are positive
if not np.shape(belief) == (numOptions, ):
raise ValueError("Passed belief has incorrect shape")
if not np.isclose(sum(belief), 1):
raise ValueError("Passed belief must sum to 1")
if np.any(belief < 0):
raise ValueError("Passed belief must have positive values")
self.idNum = int(idNum)
self._belief = belief
self._distrust = distrust
self._w = w
self._noise = noise
self._numOptions = numOptions
self._distrust = float(distrust)
self._w = float(w)
self._noise = float(noise)
self._numOptions = int(numOptions)
self.reached_decision = False
def setBelief(self, newBelief):
......@@ -54,15 +68,20 @@ class Agent(object):
N.B. Usage is only for removing the overhead during aggregation of
every agent calculating the same sum individually.
"""
newBelief = np.around(newBelief, 4)
if abs(np.sum(newBelief) - 1.0) > 0.001:
newBelief /= sum(newBelief)
elif np.min(newBelief) < 0:
newBelief /= sum(newBelief)
elif np.max(newBelief) > 1:
newBelief /= sum(newBelief)
if abs(np.sum(newBelief) - 1.0) > 0.0001:
raise ValueError("Can not set belief to, ", newBelief)
elif newBelief.shape != self._belief.shape:
raise ValueError("Incorrect shape for belief")
else:
newBelief = np.around(newBelief, 4)
if abs(np.sum(newBelief) - 1.0) > 0.001:
newBelief /= sum(newBelief)
elif np.min(newBelief) < 0:
newBelief /= sum(newBelief)
elif np.max(newBelief) > 1:
newBelief /= sum(newBelief)
self._belief = newBelief
self._belief = newBelief
def getBelief(self):
"""Returns the agent's belief"""
......@@ -97,12 +116,12 @@ class Agent(object):
p=[agg_prob, 1 - agg_prob])[0]
def compareSites(self, options):
"""Returns site with the higher quality"""
"""Returns site with the lower quality"""
return min(options, key=attrgetter('quality'))
def compareSitesWithNoise(self, options):
"""
Returns site with the perceived higher quality. Noise is simulated
Returns site with the perceived lower quality. Noise is simulated
as a confusion between the qualities of the site. i.e. greater
difference in site qualities, lower chance of confusing them.
"""
......@@ -135,7 +154,7 @@ class Agent(object):
A list of two option instances for comparison.
"""
if len(options) != 2:
raise ValueError("Expected two options to compare.")
raise TypeError("Expected two options to compare.")
if self._noise == -1:
option = self.compareSites(options)
confused = 0
......@@ -173,7 +192,8 @@ class Agent(object):
list of agent class instances
"""
beliefs = [n.getBelief() for n in neighbourhood]
poolSize = len(neighbourhood)
beliefs.append(self.getBelief()) # Add agent's belief
poolSize = len(neighbourhood) + 1
if af.check_neighbourhood_consistent(self._numOptions,
poolSize,
beliefs):
......
......@@ -221,8 +221,18 @@ int check_neighbourhood_consistent(int num_options, int pool_size,
xj_prod *= beliefs_ptr[j*num_options + i];
}
if (xj_prod == 0)
/*
One of the agents has a belief of zero in this option. Now check to
make sure another agent does not have total faith in this option
*/
{
return 0;
for (int k = 0; k < pool_size; ++k)
{
if (beliefs_ptr[k*num_options + i] == 1)
{
return 0;
}
}
}
}
return 1;
......
......@@ -130,7 +130,7 @@ class Population(object):
def receiveEvidence(self, evidence):
"""
All agents check whether they receive evidence this iteration. If they
do then they pick two options, compare their qualites and then update
do then they pick two options, compare their qualities and then update
based on this comparison.
Parameters
......
import pytest
import numpy.testing
from bestOfNSimulation.agent import *
from bestOfNSimulation.evidence import *
def test_initialise_valid():
idNum = 1
belief = np.array([0.6, 0.2, 0.2])
distrust = 0.001
w = 1
numOptions = 3
noise=-1
agent = Agent(idNum, belief, distrust, w, numOptions, noise)
assert agent.idNum == idNum
assert agent._distrust == distrust
assert agent._w == w
assert agent._numOptions == numOptions
assert agent._noise == noise
assert agent.reached_decision is False
numpy.testing.assert_almost_equal(agent._belief, belief)
@pytest.mark.parametrize("distrust, w", [
(0, 1),
(0.5, 1),
(0.001, -3)
])
def test_initialise_invalid_values(distrust, w):
with pytest.raises(ValueError):
Agent(1, np.array([0.6, 0.2, 0.2]), distrust, w, 3, -1)
@pytest.mark.parametrize("belief", [
(np.array([0.4, 0.6])),
(np.array([0.3, 0.2, 0.4])),
(np.array([0.9, -0.3, 0.4]))
])
def test_initialise_invalid_belief(belief):
with pytest.raises(ValueError):
Agent(1, belief, 0.001, 1, 3, -1)
def test_setBelief_valid():
agent = Agent(1, np.array([0.6, 0.2, 0.2]), 0.001, 1, 3, -1)
new_belief = np.array([0.8, 0.1, 0.1])
agent.setBelief(new_belief)
numpy.testing.assert_almost_equal(agent._belief, new_belief)
@pytest.mark.parametrize("new_belief", [
(np.array([0.8, 0.1, 0.0])),
(np.array([0.6, 0.1, 0.2, 0.1]))
])
def test_setBelief_invalid(new_belief):
agent = Agent(1, np.array([0.6, 0.2, 0.2]), 0.001, 1, 3, -1)
with pytest.raises(ValueError):
agent.setBelief(new_belief)
def test_getBelief_valid():
belief = np.array([0.6, 0.2, 0.2])
agent = Agent(1, belief, 0.001, 1, 3, -1)
numpy.testing.assert_almost_equal(agent.getBelief(), belief)
@pytest.mark.parametrize("agent, options, expected", [
(Agent(1, np.array([1.0, 0.0]), 0.001, 1, 2, -1),
[Option(0, 0.25), Option(1, 0.75)],
np.array([1.0, 0.0])),
(Agent(1, np.array([1.0, 0.0]), 0.001, 1, 2, -1),
[Option(0, 0.75), Option(1, 0.25)],
np.array([1.0, 0.0])), # Static fixed point doesn't change
(Agent(1, np.array([0.8, 0.2]), 0.001, 1, 2, -1),
[Option(0, 0.75), Option(1, 0.25)],
np.array([0.9996, 0.0004])),
(Agent(1, np.array([0.8, 0.2]), 0.001, 1, 2, -1),
[Option(0, 0.25), Option(1, 0.75)],
np.array([0.0040, 0.9960])),
(Agent(1, np.array([0.8, 0.2]), 0.2, 1, 2, -1),
[Option(0, 0.75), Option(1, 0.25)],
np.array([0.9412, 0.0588])),
(Agent(1, np.array([0.6, 0.3, 0.1]), 0.001, 1, 3, -1),
[Option(0, 0.15), Option(2, 0.6)],
np.array([0.0015, 0.74887, 0.2496])),
(Agent(1, np.array([0.6, 0.3, 0.1]), 0.001, 1, 3, -1),
[Option(0, 0.6), Option(2, 0.15)],
np.array([0.6665, 0.3332, 0.0001]))
])
def test_updateOnEvidence_valid(agent, options, expected):
agent.updateOnEvidence(options)
numpy.testing.assert_almost_equal(agent._belief, expected, decimal=4)
@pytest.mark.parametrize("evidence", [
(3),
(-1)
])
def test_updateOnEvidence_invalid(evidence):
agent = Agent(1, np.array([0.6, 0.3, 0.1]), 0.001, 1, 3, -1)
with pytest.raises(TypeError):
agent.updateOnEvidence(evidence)
@pytest.mark.parametrize("agent, neighbour, expected", [
(Agent(1, np.array([1.0, 0.0]), 0.001, 1, 2, -1),
Agent(2, np.array([1.0, 0.0]), 0.001, 1, 2, -1), True),
(Agent(1, np.array([0.6, 0.4]), 0.001, 1, 2, -1),
Agent(2, np.array([0.4, 0.6]), 0.001, 1, 2, -1), True),
(Agent(1, np.array([1.0, 0.0]), 0.001, 1, 2, -1),
Agent(2, np.array([0.0, 1.0]), 0.001, 1, 2, -1), False),
(Agent(1, np.array([0.6, 0.3, 0.1]), 0.001, 1, 3, -1),
Agent(2, np.array([0.0, 0.25, 0.75]), 0.001, 1, 3, -1), True),
(Agent(1, np.array([1.0, 0.0, 0.0]), 0.001, 1, 3, -1),
Agent(2, np.array([0.0, 0.0, 1.0]), 0.001, 1, 3, -1), False),
(Agent(1, np.array([1.0, 0.0, 0.0]), 0.001, 1, 3, -1),
Agent(2, np.array([0.0, 1.0, 0.0]), 0.001, 1, 3, -1), False),
(Agent(1, np.array([0.6, 0.3, 0.1]), 0.001, 1, 3, -1),
Agent(2, np.array([0.0, 0.25, 0.75]), 0.001, 1, 3, -1), True)
])
def test_checkNeighbourConsistent_valid(agent, neighbour, expected):
assert agent.checkNeighbourConsistent(neighbour) == expected
@pytest.mark.parametrize("agent, neighbourhood, expected", [
(Agent(1, np.array([0.5, 0.5]), 0.001, 1, 2, -1),
[Agent(2, np.array([0.5, 0.5]), 0.001, 1, 2, -1)],
np.array([0.5, 0.5])), # expected no change
(Agent(1, np.array([0.6, 0.4]), 0.001, 1, 2, -1),
[Agent(2, np.array([0.6, 0.4]), 0.001, 1, 2, -1)],
np.array([0.6923, 0.3077])), # n=2, k=2 case
(Agent(1, np.array([0.6, 0.3, 0.1]), 0.001, 1, 3, -1),
[Agent(2, np.array([0.0, 0.25, 0.75]), 0.001, 1, 3, -1)],
np.array([0, 0.5, 0.5])), # n>2, k=2 case
(Agent(1, np.array([0.6, 0.0, 0.4]), 0.001, 1, 3, -1),
[Agent(2, np.array([0.0, 0.25, 0.75]), 0.001, 1, 3, -1)],
np.array([0.0, 0.0, 1.0])), # still consistent
(Agent(1, np.array([0.6, 0.4]), 0.001, 1, 2, -1),
[Agent(2, np.array([0.6, 0.4]), 0.001, 1, 2, -1),
Agent(3, np.array([0.6, 0.4]), 0.001, 1, 2, -1)],
np.array([0.7714, 0.2286])), # n=2, k>2 case
(Agent(1, np.array([0.6, 0.3, 0.1]), 0.001, 1, 3, -1),
[Agent(2, np.array([0.0, 0.25, 0.75]), 0.001, 1, 3, -1),
Agent(3, np.array([0.1, 0.2, 0.7]), 0.001, 1, 3, -1)],
np.array([0.0, 0.2222, 0.7778])), # n>2, k>2 case
])
def test_aggregate_valid(agent, neighbourhood, expected):
ret_belief = agent.aggregate(neighbourhood)
numpy.testing.assert_almost_equal(ret_belief, expected, decimal=4)
def test_aggregate_valid_inconsistent():
agent = Agent(1, np.array([1.0, 0.0]), 0.001, 1, 2, -1)
neighbourhood = [Agent(1, np.array([1.0, 0.0]), 0.001, 1, 2, -1),
Agent(2, np.array([0.0, 1.0]), 0.001, 1, 2, -1)]
assert agent.aggregate(neighbourhood) is None
import pytest
import numpy.testing
import numpy as np
from collections import Counter
from bestOfNSimulation import agentFunctions as af
@pytest.mark.parametrize("num_options, weights, expected", [
(4, (1, 0, 0, 0), (100000, 33333, 33333, 33333)),
(4, (0.25, 0.25, 0.25, 0.25), (50000, 50000, 50000, 50000))
])
def test_pick_ops(num_options, weights, expected):
trials = [list(af.pick_ops(num_options, weights)) for i in range(0, 100000)]
trials_flat = [item for sublist in trials for item in sublist]
counter = Counter(trials_flat)
for i in range(0, num_options):
assert (expected[i] * 0.9) <= counter[i] <= (expected[i] * 1.1)
@pytest.mark.parametrize("evidenceID, distrust, belief, expected", [
(1, 0.001, np.array([1.0, 0.0]), np.array([1.0, 0.0])),
(0, 0.001, np.array([1.0, 0.0]), np.array([1.0, 0.0])),
(1, 0.001, np.array([0.8, 0.2]), np.array([0.9997, 0.0003])),
(0, 0.001, np.array([0.8, 0.2]), np.array([0.0040, 0.9960])),
(1, 0.2, np.array([0.8, 0.2]), np.array([0.9412, 0.0588])),
(0, 0.001, np.array([0.6, 0.3, 0.1]), np.array([0.0015, 0.74887, 0.2496])),
(2, 0.001, np.array([0.6, 0.3, 0.1]), np.array([0.6665, 0.3332, 0.0001]))
])
def test_update_on_evidence(evidenceID, distrust, belief, expected):
numpy.testing.assert_almost_equal(af.update_on_evidence(evidenceID,
distrust,
belief),
expected,
decimal=4)
@pytest.mark.parametrize("num_options, pool_size, beliefs, expected", [
(2, 2, np.array([[0.6, 0.4], [0.6, 0.4]]), np.array([0.6923, 0.3077])),
(3, 2, np.array([[0.6, 0.3, 0.1], [0.0, 0.25, 0.75]]),
np.array([0.0, 0.5, 0.5])),
(3, 2, np.array([[0.6, 0.0, 0.4], [0.0, 0.25, 0.75]]),
np.array([0.0, 0.0, 1.0]))
])
def test_aggregate_MProdOp(num_options, pool_size, beliefs, expected):
ret_belief = af.aggregate_MProdOp(num_options, pool_size, beliefs)
numpy.testing.assert_almost_equal(ret_belief, expected, decimal=4)
@pytest.mark.parametrize("belief1, belief2, expected", [
(np.array([1.0, 0.0]), np.array([1.0, 0.0]), True),
(np.array([0.6, 0.4]), np.array([0.4, 0.6]), True),
(np.array([1.0, 0.0]), np.array([0.0, 1.0]), False),
(np.array([0.6, 0.3, 0.1]), np.array([0.0, 0.25, 0.75]), True),
(np.array([1.0, 0.0, 0.0]), np.array([0.0, 0.0, 1.0]), False),
(np.array([1.0, 0.0, 0.0]), np.array([0.0, 1.0, 0.0]), False)
])
def test_check_neighbour_consistent(belief1, belief2, expected):
assert af.check_neighbour_consistent(belief1, belief2) == expected
def test_check_neighbourhood_consistent():
beliefs = np.array([[0.6, 0.3, 0.1], [0.0, 0.25, 0.75]])
assert af.check_neighbourhood_consistent(3, 2, beliefs) == 1
import pytest
from bestOfNSimulation.evidence import *
def test_intialise_valid():
evidence_rate = 0.4
optionList = [(0, 0.5), (1, 0.1), (2, 0.2), (3, 0.2)]
evidence = Evidence(optionList, evidence_rate)
assert evidence.evidenceRate == evidence_rate
assert len(evidence.options) == 4
assert evidence.options[0].id == 0
assert evidence.options[0].quality == 0.5
assert evidence.options[-1].id == 3
assert evidence.options[-1].quality == 0.2
def test_intialise_invalid_type():
with pytest.raises(TypeError):
Evidence(0.7, 0.5)
@pytest.mark.parametrize("evidence_rate, expected", [
(1, True),
(0, False)
])
def test_receiveEvidenceBool_simple(evidence_rate, expected):
evidence = Evidence(((0,0.5),(1,0.5)), evidence_rate)
result = evidence.receiveEvidenceBool()
assert result == expected
# Not sure how to test this function further as it then just becomes a case of
# testing random.choice which seems rather pointless.
def test_retOptions():
optionList = [(0, 0.5), (1, 0.1), (2, 0.2), (3, 0.2)]
evidence = Evidence(optionList, 0.4)
option = evidence.retOption(2)
assert option.id == 2
def test_retBestOption():
optionList = [(0, 0.5), (1, 0.1), (2, 0.2), (3, 0.2)]
evidence = Evidence(optionList, 0.4)
option = evidence.retBestOption()
assert option.id == 0
\ No newline at end of file
import pytest
import numpy.testing
from bestOfNSimulation.population import *
from bestOfNSimulation.agent import Agent
from bestOfNSimulation.evidence import Evidence
def test_initialise_valid():
size = 10
num_options = 4
distrust = 0.001
w = 1.0
expected_belief = np.array([0.25, 0.25, 0.25, 0.25])
noise = -1
agg_prob = 1
population = Population(size, num_options, distrust, w, noise, agg_prob)
# Check population attributes
assert population._size == size
assert population._numOptions == num_options
assert population.agg_prob == agg_prob
# Check initialised agents correctly
assert len(population._agents) == size
assert [agent.idNum for agent in population._agents] == list(range(size))
for agent in population._agents:
assert isinstance(agent, Agent)
assert agent._distrust == distrust
assert agent._w == w
assert agent._noise == noise
assert len(agent._belief) == num_options
numpy.testing.assert_almost_equal(agent._belief, expected_belief,
decimal=4)
def test_retBeliefs():
size = 10
num_options = 4
population = Population(size, num_options, 0.001, 1.0, -1, 1.0)
numpy.testing.assert_almost_equal(population.retBeliefs(),
1.0 / num_options * np.ones((size,
num_options)
),
decimal=4)
def test_moveAgents():
population = Population(10, 4, 0.001, 1.0, -1, 1.0)
pop_before_move = population._agents
moved_agents = population.moveAgents()
pop_after_move = population._agents
# Check that move doesn't affect the populations list of agents
assert pop_before_move == pop_after_move
# Check that all the agents are still accounted for
assert set(pop_before_move) == set(moved_agents)
def test_aggregationWholePopulation_valid_no_change():
population = Population(10, 4, 0.001, 1.0, -1, 1.0)
population.aggregationWholePopulation(population._agents)
numpy.testing.assert_almost_equal(population.retBeliefs(),
0.25 * np.ones((10, 4)),
decimal=4)
def test_aggregationWholePopulation_valid():
population = Population(3, 3, 0.001, 1.0, -1, 1.0)
population_beliefs_before_agg = np.array([[0.6, 0.3, 0.1],
[0.0, 0.25, 0.75],
[0.1, 0.2, 0.7]])
population_beliefs_after_agg = np.array([[0.0, 0.2222, 0.7778],
[0.0, 0.2222, 0.7778],
[0.0, 0.2222, 0.7778]])
# Unfortunately hacky way of getting variation in population beliefs
for i, agent in enumerate(population._agents):
agent.setBelief(population_beliefs_before_agg[i])
population.aggregationWholePopulation(population._agents)
numpy.testing.assert_almost_equal(population.retBeliefs(),
population_beliefs_after_agg,
decimal=4)
def test_aggregationLocalised_valid_no_change():
population = Population(10, 4, 0.001, 1.0, -1, 1.0)
population.aggregationLocalised(population._agents, 3)
numpy.testing.assert_almost_equal(population.retBeliefs(),
0.25 * np.ones((10, 4)),
decimal=4)
def test_aggregationLocalised_valid():
population = Population(3, 3, 0.001, 1.0, -1, 1.0)
population_beliefs_before_agg = np.array([[0.6, 0.3, 0.1],
[0.0, 0.25, 0.75],
[0.1, 0.2, 0.7]])
population_beliefs_after_agg = np.array([[0.0, 0.5, 0.5],
[0.0, 0.0870, 0.9130],
[0.3158, 0.3158, 0.3684]])
# Unfortunately hacky way of getting variation in population beliefs
for i, agent in enumerate(population._agents):
agent.setBelief(population_beliefs_before_agg[i])
population.aggregationLocalised(population._agents, 2)
numpy.testing.assert_almost_equal(population.retBeliefs(),
population_beliefs_after_agg,
decimal=4)
@pytest.mark.parametrize("neighbourhoodSize, expected", [
(0, np.array([[0.6, 0.3, 0.1],
[0.0, 0.25, 0.75],
[0.1, 0.2, 0.7]])), # 0 == pool -> no agg
(-1, np.array([[0.6, 0.3, 0.1],
[0.0, 0.25, 0.75],
[0.1, 0.2, 0.7]])), # 0 > pool -> no agg
(2, np.array([[0.0, 0.5, 0.5],
[0.0, 0.0870, 0.9130],
[0.3158, 0.3158, 0.3684]])), # pop_size > pool -> local agg
(3, np.array([[0.0, 0.2222, 0.7778],
[0.0, 0.2222, 0.7778],
[0.0, 0.2222, 0.7778]])), # pop_size == pool -> total agg
(10, np.array([[0.0, 0.2222, 0.7778],
[0.0, 0.2222, 0.7778],
[0.0, 0.2222, 0.7778]])) # pop_size < pool -> total agg
])
def test_aggregation_valid(neighbourhoodSize, expected):
population = Population(3, 3, 0.001, 1.0, -1, 1.0)
population_beliefs_before_agg = np.array([[0.6, 0.3, 0.1],
[0.0, 0.25, 0.75],
[0.1, 0.2, 0.7]])
# Unfortunately hacky way of getting variation in population beliefs
for i, agent in enumerate(population._agents):
agent.setBelief(population_beliefs_before_agg[i])
population.aggregation(population._agents, neighbourhoodSize)
numpy.testing.assert_almost_equal(population.retBeliefs(),
expected,
decimal=4)
@pytest.mark.parametrize(
"num_options, distrust, evidence_rate, option_list, expected", [
(2, 0.001, 1.0, ((0, 0.75), (1, 0.25)), np.array([0.999, 0.001])),
(2, 0.2, 1.0, ((0, 0.75), (1, 0.25)), np.array([0.8, 0.2])),
(2, 0.001, 1.0, ((0, 0.25), (1, 0.75)), np.array([0.001, 0.999])),
(4, 0.001, 0.0, ((0, 0.1), (1, 0.2), (2, 0.35), (3, 0.35)),
np.array([0.25, 0.25, 0.25, 0.25]))
])
def test_receiveEvidence_simple(num_options, distrust, evidence_rate,
option_list, expected):
population = Population(10, num_options, distrust, 1.0, -1, 1.0)
evidence = Evidence(option_list, evidence_rate)