diff --git a/@agent/agent.m b/@agent/agent.m index 7393cb3..6e64bbb 100644 --- a/@agent/agent.m +++ b/@agent/agent.m @@ -1,7 +1,6 @@ classdef agent properties (SetAccess = public, GetAccess = public) % Identifiers - index = NaN; label = ""; % Sensor @@ -41,7 +40,7 @@ classdef agent methods (Access = public) [obj] = initialize(obj, pos, vel, pan, tilt, collisionGeometry, sensorModel, guidanceModel, comRange, index, label); - [obj] = run(obj, domain, partitioning, t); + [obj] = run(obj, domain, partitioning, t, index); [obj, f] = plot(obj, ind, f); updatePlots(obj); end diff --git a/@agent/initialize.m b/@agent/initialize.m index c86c247..e067518 100644 --- a/@agent/initialize.m +++ b/@agent/initialize.m @@ -9,7 +9,6 @@ function obj = initialize(obj, pos, vel, pan, tilt, collisionGeometry, sensorMod sensorModel (1, 1) {mustBeSensor} guidanceModel (1, 1) {mustBeA(guidanceModel, 'function_handle')}; comRange (1, 1) double = NaN; - index (1, 1) double = NaN; label (1, 1) string = ""; debug (1, 1) logical = false; plotCommsGeometry (1, 1) logical = true; @@ -25,13 +24,12 @@ function obj = initialize(obj, pos, vel, pan, tilt, collisionGeometry, sensorMod obj.collisionGeometry = collisionGeometry; obj.sensorModel = sensorModel; obj.guidanceModel = guidanceModel; - obj.index = index; obj.label = label; obj.debug = debug; obj.plotCommsGeometry = plotCommsGeometry; % Add spherical geometry based on com range - obj.commsGeometry = obj.commsGeometry.initialize(obj.pos, comRange, REGION_TYPE.COMMS, sprintf("Agent %d Comms Geometry", obj.index)); + obj.commsGeometry = obj.commsGeometry.initialize(obj.pos, comRange, REGION_TYPE.COMMS, sprintf("%s Comms Geometry", obj.label)); if obj.debug obj.debugFig = figure; diff --git a/@agent/run.m b/@agent/run.m index 8f744c7..77698cd 100644 --- a/@agent/run.m +++ b/@agent/run.m @@ -1,16 +1,17 @@ -function obj = run(obj, domain, partitioning, t) +function obj = run(obj, domain, partitioning, t, index) arguments (Input) obj (1, 1) {mustBeA(obj, 'agent')}; domain (1, 1) {mustBeGeometry}; partitioning (:, :) double; t (1, 1) double; + index (1, 1) double; end arguments (Output) obj (1, 1) {mustBeA(obj, 'agent')}; end % Collect objective function values across partition - partitionMask = partitioning == obj.index; + partitionMask = partitioning == index; objectiveValues = domain.objective.values(partitionMask); % f(omega) on W_n % Compute sensor performance across partition diff --git a/@miSim/partition.m b/@miSim/partition.m index c292264..cd46794 100644 --- a/@miSim/partition.m +++ b/@miSim/partition.m @@ -16,7 +16,10 @@ function obj = partition(obj) [~, idx] = max(agentPerformances, [], 3); % Collect agent indices in the same way as performance - agentInds = cellfun(@(x) x.index * ones(size(obj.objective.X)), obj.agents, 'UniformOutput', false); + indices = 1:size(obj.agents, 1); + agentInds = squeeze(tensorprod(indices, ones(size(obj.objective.X)))); + agentInds = num2cell(agentInds, 2:3); + agentInds = cellfun(@(x) squeeze(x), agentInds, 'UniformOutput', false); agentInds{end + 1} = zeros(size(agentInds{end})); % index for no assignment agentInds = cat(3, agentInds{:}); diff --git a/@miSim/run.m b/@miSim/run.m index 8116326..01a7dd4 100644 --- a/@miSim/run.m +++ b/@miSim/run.m @@ -30,7 +30,7 @@ function [obj] = run(obj) % Iterate over agents to simulate their unconstrained motion for jj = 1:size(obj.agents, 1) - obj.agents{jj} = obj.agents{jj}.run(obj.domain, obj.partitioning, obj.t); + obj.agents{jj} = obj.agents{jj}.run(obj.domain, obj.partitioning, obj.t, jj); end % Adjust motion determined by unconstrained gradient ascent using diff --git a/sensorModels/@sigmoidSensor/sense.m b/sensorModels/@sigmoidSensor/sense.m deleted file mode 100644 index c7a2ea3..0000000 --- a/sensorModels/@sigmoidSensor/sense.m +++ /dev/null @@ -1,21 +0,0 @@ -function [values, positions] = sense(obj, agent, sensingObjective, domain, partitioning) - arguments (Input) - obj (1, 1) {mustBeA(obj, 'sigmoidSensor')}; - agent (1, 1) {mustBeA(agent, 'agent')}; - sensingObjective (1, 1) {mustBeA(sensingObjective, 'sensingObjective')}; - domain (1, 1) {mustBeGeometry}; - partitioning (:, :) double; - end - arguments (Output) - values (:, 1) double; - positions (:, 3) double; - end - - % Find positions for this agent's assigned partition in the domain - idx = partitioning == agent.index; - positions = [sensingObjective.X(idx), sensingObjective.Y(idx), zeros(size(sensingObjective.X(idx)))]; - - % Evaluate objective function at every point in this agent's - % assigned partiton - values = sensingObjective.values(idx); -end \ No newline at end of file diff --git a/test/test_miSim.m b/test/test_miSim.m index d78cb41..c2968a5 100644 --- a/test/test_miSim.m +++ b/test/test_miSim.m @@ -162,7 +162,7 @@ classdef test_miSim < matlab.unittest.TestCase sensor = sensor.initialize(tc.alphaDistMin + rand * (tc.alphaDistMax - tc.alphaDistMin), tc.betaDistMin + rand * (tc.betaDistMax - tc.betaDistMin), NaN, NaN, tc.alphaTiltMin + rand * (tc.alphaTiltMax - tc.alphaTiltMin), tc.betaTiltMin + rand * (tc.betaTiltMax - tc.betaTiltMin)); % Initialize candidate agent - newAgent = tc.agents{ii}.initialize(candidatePos, zeros(1,3), 0, 0, candidateGeometry, sensor, @gradientAscent, tc.comRange, ii, sprintf("Agent %d", ii)); + newAgent = tc.agents{ii}.initialize(candidatePos, zeros(1,3), 0, 0, candidateGeometry, sensor, @gradientAscent, tc.comRange, sprintf("Agent %d", ii)); % Make sure candidate agent doesn't collide with % domain @@ -296,7 +296,7 @@ classdef test_miSim < matlab.unittest.TestCase sensor = sensor.initialize(tc.alphaDistMin + rand * (tc.alphaDistMax - tc.alphaDistMin), tc.betaDistMin + rand * (tc.betaDistMax - tc.betaDistMin), NaN, NaN, tc.alphaTiltMin + rand * (tc.alphaTiltMax - tc.alphaTiltMin), tc.betaTiltMin + rand * (tc.betaTiltMax - tc.betaTiltMin)); % Initialize candidate agent - newAgent = tc.agents{ii}.initialize(candidatePos, zeros(1,3), 0, 0, candidateGeometry, sensor, @gradientAscent, tc.comRange, ii, sprintf("Agent %d", ii), false, false); + newAgent = tc.agents{ii}.initialize(candidatePos, zeros(1,3), 0, 0, candidateGeometry, sensor, @gradientAscent, tc.comRange, sprintf("Agent %d", ii), false, false); % Make sure candidate agent doesn't collide with % domain @@ -378,14 +378,14 @@ classdef test_miSim < matlab.unittest.TestCase % Initialize agents tc.agents = {agent; agent}; - tc.agents{1} = tc.agents{1}.initialize(tc.domain.center + dh + [d, 0, 0], zeros(1,3), 0, 0, geometry1, sensor, @gradientAscent, 3*d, 1, sprintf("Agent %d", 1)); - tc.agents{2} = tc.agents{2}.initialize(tc.domain.center + dh - [d, 0, 0], zeros(1,3), 0, 0, geometry2, sensor, @gradientAscent, 3*d, 2, sprintf("Agent %d", 2)); + tc.agents{1} = tc.agents{1}.initialize(tc.domain.center + dh + [d, 0, 0], zeros(1,3), 0, 0, geometry1, sensor, @gradientAscent, 3*d, sprintf("Agent %d", 1)); + tc.agents{2} = tc.agents{2}.initialize(tc.domain.center + dh - [d, 0, 0], zeros(1,3), 0, 0, geometry2, sensor, @gradientAscent, 3*d, sprintf("Agent %d", 2)); % Optional third agent along the +Y axis geometry3 = rectangularPrism; geometry3 = geometry3.initialize([tc.domain.center + dh - [0, d, 0] - tc.collisionRanges(1) * ones(1, 3); tc.domain.center + dh - [0, d, 0] + tc.collisionRanges(1) * ones(1, 3)], REGION_TYPE.COLLISION, sprintf("Agent %d collision volume", 3)); tc.agents{3} = agent; - tc.agents{3} = tc.agents{3}.initialize(tc.domain.center + dh - [0, d, 0], zeros(1, 3), 0, 0, geometry3, sensor, @gradientAscent, 3*d, 3, sprintf("Agent %d", 3)); + tc.agents{3} = tc.agents{3}.initialize(tc.domain.center + dh - [0, d, 0], zeros(1, 3), 0, 0, geometry3, sensor, @gradientAscent, 3*d, sprintf("Agent %d", 3)); % Initialize the simulation tc.testClass = tc.testClass.initialize(tc.domain, tc.domain.objective, tc.agents, tc.minAlt, tc.timestep, tc.partitoningFreq, tc.maxIter, cell(0, 1), tc.makeVideo); @@ -415,7 +415,7 @@ classdef test_miSim < matlab.unittest.TestCase % Initialize agents tc.agents = {agent}; - tc.agents{1} = tc.agents{1}.initialize([tc.domain.center(1:2), 3], zeros(1,3), 0, 0, geometry1, sensor, @gradientAscent, 3, 1, sprintf("Agent %d", 1)); + tc.agents{1} = tc.agents{1}.initialize([tc.domain.center(1:2), 3], zeros(1,3), 0, 0, geometry1, sensor, @gradientAscent, 3, sprintf("Agent %d", 1)); % Initialize the simulation tc.testClass = tc.testClass.initialize(tc.domain, tc.domain.objective, tc.agents, tc.minAlt, tc.timestep, tc.partitoningFreq, tc.maxIter, cell(0, 1), tc.makeVideo); @@ -445,7 +445,7 @@ classdef test_miSim < matlab.unittest.TestCase % Initialize agents tc.agents = {agent}; - tc.agents{1} = tc.agents{1}.initialize([tc.domain.center(1:2)-tc.domain.dimensions(1)/3, 3], zeros(1,3), 0, 0, geometry1, sensor, @gradientAscent, 3, 1, sprintf("Agent %d", 1), true); + tc.agents{1} = tc.agents{1}.initialize([tc.domain.center(1:2)-tc.domain.dimensions(1)/3, 3], zeros(1,3), 0, 0, geometry1, sensor, @gradientAscent, 3, sprintf("Agent %d", 1), true); % Initialize the simulation tc.testClass = tc.testClass.initialize(tc.domain, tc.domain.objective, tc.agents, tc.minAlt, tc.timestep, tc.partitoningFreq, tc.maxIter, cell(0, 1), tc.makeVideo); @@ -481,8 +481,8 @@ classdef test_miSim < matlab.unittest.TestCase % Initialize agents tc.agents = {agent; agent}; - tc.agents{1} = tc.agents{1}.initialize(tc.domain.center + d, zeros(1,3), 0, 0, geometry1, sensor, @gradientAscent, 3, 1, sprintf("Agent %d", 1), false); - tc.agents{2} = tc.agents{2}.initialize(tc.domain.center - d, zeros(1,3), 0, 0, geometry2, sensor, @gradientAscent, 3, 2, sprintf("Agent %d", 2), false); + tc.agents{1} = tc.agents{1}.initialize(tc.domain.center + d, zeros(1,3), 0, 0, geometry1, sensor, @gradientAscent, 3, sprintf("Agent %d", 1), false); + tc.agents{2} = tc.agents{2}.initialize(tc.domain.center - d, zeros(1,3), 0, 0, geometry2, sensor, @gradientAscent, 3, sprintf("Agent %d", 2), false); % Initialize the simulation tc.testClass = tc.testClass.initialize(tc.domain, tc.domain.objective, tc.agents, tc.minAlt, tc.timestep, tc.partitoningFreq, tc.maxIter, cell(0, 1), tc.makeVideo, tc.makePlots); @@ -516,8 +516,8 @@ classdef test_miSim < matlab.unittest.TestCase % Initialize agents tc.agents = {agent; agent;}; - tc.agents{1} = tc.agents{1}.initialize(tc.domain.center - d + [0, radius * 1.5, 0], zeros(1,3), 0, 0, geometry1, sensor, @gradientAscent, 10, 1, sprintf("Agent %d", 1), false, false); - tc.agents{2} = tc.agents{2}.initialize(tc.domain.center - d - [0, radius * 1.5, 0], zeros(1,3), 0, 0, geometry2, sensor, @gradientAscent, 10, 2, sprintf("Agent %d", 2), false, false); + tc.agents{1} = tc.agents{1}.initialize(tc.domain.center - d + [0, radius * 1.5, 0], zeros(1,3), 0, 0, geometry1, sensor, @gradientAscent, 10, sprintf("Agent %d", 1), false, false); + tc.agents{2} = tc.agents{2}.initialize(tc.domain.center - d - [0, radius * 1.5, 0], zeros(1,3), 0, 0, geometry2, sensor, @gradientAscent, 10, sprintf("Agent %d", 2), false, false); % Initialize obstacles obstacleLength = 1; @@ -557,8 +557,8 @@ classdef test_miSim < matlab.unittest.TestCase % Initialize agents commsRadius = 5; tc.agents = {agent; agent;}; - tc.agents{1} = tc.agents{1}.initialize(tc.domain.center - [d, 0, 0], zeros(1,3), 0, 0, geometry1, sensor, @gradientAscent, commsRadius, 1, sprintf("Agent %d", 1), false); - tc.agents{2} = tc.agents{2}.initialize(tc.domain.center - [0, d, 0], zeros(1,3), 0, 0, geometry2, sensor, @gradientAscent, commsRadius, 2, sprintf("Agent %d", 2), false); + tc.agents{1} = tc.agents{1}.initialize(tc.domain.center - [d, 0, 0], zeros(1,3), 0, 0, geometry1, sensor, @gradientAscent, commsRadius, sprintf("Agent %d", 1), false); + tc.agents{2} = tc.agents{2}.initialize(tc.domain.center - [0, d, 0], zeros(1,3), 0, 0, geometry2, sensor, @gradientAscent, commsRadius, sprintf("Agent %d", 2), false); % Initialize obstacles obstacleLength = 1.5; @@ -571,7 +571,6 @@ classdef test_miSim < matlab.unittest.TestCase % No communications link should be established tc.assertEqual(tc.testClass.adjacency, logical(eye(2))); end - function test_LNA_example_case(tc) % No obstacles % Fixed 5 agents initial conditions @@ -606,16 +605,17 @@ classdef test_miSim < matlab.unittest.TestCase % Initialize agents commsRadius = d; tc.agents = {agent; agent; agent; agent; agent;}; - tc.agents{1} = tc.agents{1}.initialize(tc.domain.center + [d, 0, 0], zeros(1,3), 0, 0, geometry1, sensor, @gradientAscent, commsRadius, 1, sprintf("Agent %d", 1), false); - tc.agents{2} = tc.agents{2}.initialize(tc.domain.center, zeros(1,3), 0, 0, geometry2, sensor, @gradientAscent, commsRadius, 2, sprintf("Agent %d", 2), false); - tc.agents{3} = tc.agents{3}.initialize(tc.domain.center + [-d, d, 0], zeros(1,3), 0, 0, geometry3, sensor, @gradientAscent, commsRadius, 3, sprintf("Agent %d", 3), false); - tc.agents{4} = tc.agents{4}.initialize(tc.domain.center + [-2*d, d, 0], zeros(1,3), 0, 0, geometry4, sensor, @gradientAscent, commsRadius, 4, sprintf("Agent %d", 4), false); - tc.agents{5} = tc.agents{5}.initialize(tc.domain.center + [0, d, 0], zeros(1,3), 0, 0, geometry5, sensor, @gradientAscent, commsRadius, 5, sprintf("Agent %d", 5), false); + tc.agents{1} = tc.agents{1}.initialize(tc.domain.center + [d, 0, 0], zeros(1,3), 0, 0, geometry1, sensor, @gradientAscent, commsRadius, sprintf("Agent %d", 1), false); + tc.agents{2} = tc.agents{2}.initialize(tc.domain.center, zeros(1,3), 0, 0, geometry2, sensor, @gradientAscent, commsRadius, sprintf("Agent %d", 2), false); + tc.agents{3} = tc.agents{3}.initialize(tc.domain.center + [-d, d, 0], zeros(1,3), 0, 0, geometry3, sensor, @gradientAscent, commsRadius, sprintf("Agent %d", 3), false); + tc.agents{4} = tc.agents{4}.initialize(tc.domain.center + [-2*d, d, 0], zeros(1,3), 0, 0, geometry4, sensor, @gradientAscent, commsRadius, sprintf("Agent %d", 4), false); + tc.agents{5} = tc.agents{5}.initialize(tc.domain.center + [0, d, 0], zeros(1,3), 0, 0, geometry5, sensor, @gradientAscent, commsRadius, sprintf("Agent %d", 5), false); % TODO % make agent label and ID optional, they can be derived from index % Consider how to do the same for collision geometry label % make @gradientAscent always the choice + % Build collision geometry initialization into agent initialization? % Initialize the simulation tc.testClass = tc.testClass.initialize(tc.domain, tc.domain.objective, tc.agents, 0, tc.timestep, tc.partitoningFreq, 125, tc.obstacles, false, false);