fixed lesser neighbor algorithm

This commit is contained in:
2026-01-06 10:57:56 -08:00
parent 7d1154d028
commit 4fe897455d
4 changed files with 127 additions and 24 deletions

View File

@@ -28,6 +28,8 @@ classdef agent
% Communication % Communication
comRange = NaN; comRange = NaN;
commsGeometry = spherical; commsGeometry = spherical;
lesserNeighbors = [];
performance = 0; performance = 0;

View File

@@ -22,13 +22,14 @@ function obj = initialize(obj, pos, vel, pan, tilt, collisionGeometry, sensorMod
obj.tilt = tilt; obj.tilt = tilt;
obj.collisionGeometry = collisionGeometry; obj.collisionGeometry = collisionGeometry;
obj.sensorModel = sensorModel; obj.sensorModel = sensorModel;
obj.comRange = comRange;
obj.guidanceModel = @gradientAscent; obj.guidanceModel = @gradientAscent;
obj.label = label; obj.label = label;
obj.debug = debug; obj.debug = debug;
obj.plotCommsGeometry = plotCommsGeometry; obj.plotCommsGeometry = plotCommsGeometry;
% Add spherical geometry based on com range % Add spherical geometry based on com range
obj.commsGeometry = obj.commsGeometry.initialize(obj.pos, comRange, REGION_TYPE.COMMS, sprintf("%s Comms Geometry", obj.label)); obj.commsGeometry = obj.commsGeometry.initialize(obj.pos, obj.comRange, REGION_TYPE.COMMS, sprintf("%s Comms Geometry", obj.label));
if obj.debug if obj.debug
obj.debugFig = figure; obj.debugFig = figure;

View File

@@ -12,20 +12,69 @@ function obj = lesserNeighbor(obj)
% constraint adjacency matrix % constraint adjacency matrix
% Place that choice in the constraint adjacency matrix % Place that choice in the constraint adjacency matrix
% Begin with all possible connections and trim down constraintAdjacencyMatrix = logical(eye(size(obj.agents, 1)));
constraintAdjacencyMatrix = obj.adjacency;
% Iterate over each agent (by increasing index)
for ii = 1:size(obj.agents, 1) for ii = 1:size(obj.agents, 1)
% Iterate over each agent of lesser index and see if a higher % Find lesser neighbors of each agent
% indexed agent provides connectivity already % Lesser neighbors of ii are jj < ii in range of ii
lesserNeighbors = [];
for jj = 1:(ii - 1) for jj = 1:(ii - 1)
for kk = 1:(jj - 1) if obj.adjacency(ii, jj)
constraintAdjacencyMatrix(ii, kk) = false; lesserNeighbors = [lesserNeighbors, jj];
constraintAdjacencyMatrix(kk, ii) = false;
end end
end end
obj.agents{ii}.lesserNeighbors = lesserNeighbors;
% Early exit for isolated agents
if isempty(obj.agents{ii}.lesserNeighbors)
continue
end
% Focus on subgraph defined by lesser neighbors
subgraphAdjacency = obj.adjacency(obj.agents{ii}.lesserNeighbors, obj.agents{ii}.lesserNeighbors);
% Find connected components in each agent's subgraph
visited = false(size(subgraphAdjacency, 1), 1);
components = {};
for jj = 1:size(subgraphAdjacency, 1)
if ~visited(jj)
reachable = bfs(subgraphAdjacency, jj);
visited(reachable) = true;
components{end+1} = obj.agents{ii}.lesserNeighbors(reachable);
end
end end
obj.constraintAdjacencyMatrix = constraintAdjacencyMatrix; % Connect to the greatest index in each connected component in the
% lesser neighborhood of this agent
for jj = 1:size(components, 2)
constraintAdjacencyMatrix(ii, max(components{jj})) = true;
constraintAdjacencyMatrix(max(components{jj}), ii) = true;
end
end
obj.constraintAdjacencyMatrix = constraintAdjacencyMatrix | constraintAdjacencyMatrix';
end
function cComp = bfs(subgraphAdjacency, startIdx)
n = size(subgraphAdjacency, 1);
visited = false(1, n);
queue = startIdx;
cComp = startIdx;
visited(startIdx) = true;
while ~isempty(queue)
current = queue(1);
queue(1) = [];
% Find all neighbors of current node in the subgraph
neighbors = find(subgraphAdjacency(current, :));
for neighbor = neighbors
if ~visited(neighbor)
visited(neighbor) = true;
cComp = [cComp, neighbor];
queue = [queue, neighbor];
end
end
end
cComp = sort(cComp);
end end

View File

@@ -571,7 +571,8 @@ classdef test_miSim < matlab.unittest.TestCase
% No communications link should be established % No communications link should be established
tc.assertEqual(tc.testClass.adjacency, logical(eye(2))); tc.assertEqual(tc.testClass.adjacency, logical(eye(2)));
end end
function test_LNA_example_case(tc) function test_LNA_case_1(tc)
% based on example in meeting
% No obstacles % No obstacles
% Fixed 5 agents initial conditions % Fixed 5 agents initial conditions
% unitary communicaitons radius % unitary communicaitons radius
@@ -586,16 +587,12 @@ classdef test_miSim < matlab.unittest.TestCase
% Initialize agent collision geometry % Initialize agent collision geometry
radius = .01; radius = .01;
d = 1; d = 1;
geometry1 = spherical; geometry5 = spherical;
geometry2 = geometry1; geometry1 = geometry5.initialize(tc.domain.center + [d, 0, 0], radius, REGION_TYPE.COLLISION);
geometry3 = geometry2; geometry2 = geometry5.initialize(tc.domain.center, radius, REGION_TYPE.COLLISION);
geometry4 = geometry3; geometry3 = geometry5.initialize(tc.domain.center + [-d, d, 0], radius, REGION_TYPE.COLLISION);
geometry5 = geometry4; geometry4 = geometry5.initialize(tc.domain.center + [-2*d, d, 0], radius, REGION_TYPE.COLLISION);
geometry1 = geometry1.initialize(tc.domain.center + [d, 0, 0], radius, REGION_TYPE.COLLISION); geometry5 = geometry5.initialize(tc.domain.center + [0, d, 0], radius, REGION_TYPE.COLLISION);
geometry2 = geometry2.initialize(tc.domain.center, radius, REGION_TYPE.COLLISION);
geometry3 = geometry2.initialize(tc.domain.center + [-d, d, 0], radius, REGION_TYPE.COLLISION);
geometry4 = geometry2.initialize(tc.domain.center + [-2*d, d, 0], radius, REGION_TYPE.COLLISION);
geometry5 = geometry2.initialize(tc.domain.center + [0, d, 0], radius, REGION_TYPE.COLLISION);
% Initialize agent sensor model % Initialize agent sensor model
sensor = sigmoidSensor; sensor = sigmoidSensor;
@@ -619,8 +616,62 @@ classdef test_miSim < matlab.unittest.TestCase
[ 1, 1, 0, 0, 0; ... [ 1, 1, 0, 0, 0; ...
1, 1, 0, 0, 1; ... 1, 1, 0, 0, 1; ...
0, 0, 1, 1, 1; 0, 0, 1, 1, 1;
0, 0, 1, 0, 0; 0, 0, 1, 1, 0;
0, 1, 1, 0, 0; ])); 0, 1, 1, 0, 1; ]));
end
function test_LNA_case_2(tc)
% based on example in paper Asynchronous Local Construction of Bounded-Degree Network Topologies Using Only Neighborhood Information
% No obstacles
% Fixed 7 agents initial conditions
% unitary communicaitons radius
% negligible collision radius
% make basic domain
l = 10; % domain size
tc.domain = tc.domain.initialize([zeros(1, 3); l * ones(1, 3)], REGION_TYPE.DOMAIN, "Domain");
% make basic sensing objective
tc.domain.objective = tc.domain.objective.initialize(@(x, y) mvnpdf([x(:), y(:)], [8, 5]), tc.domain, tc.discretizationStep, tc.protectedRange);
% Initialize agent collision geometry
radius = .01;
d = 1;
geometry7 = spherical;
geometry1 = geometry7.initialize(tc.domain.center + [-0.9 * d/sqrt(2), 0.9 * d/sqrt(2), 0], radius, REGION_TYPE.COLLISION);
geometry2 = geometry7.initialize(tc.domain.center + [-0.5 * d, 0.25 * d, 0], radius, REGION_TYPE.COLLISION);
geometry3 = geometry7.initialize(tc.domain.center + [0.9 * d, 0, 0], radius, REGION_TYPE.COLLISION);
geometry4 = geometry7.initialize(tc.domain.center + [0.9 * d/sqrt(2), -0.9 * d/sqrt(2), 0], radius, REGION_TYPE.COLLISION);
geometry5 = geometry7.initialize(tc.domain.center + [0, 0.9 * d, 0], radius, REGION_TYPE.COLLISION);
geometry6 = geometry7.initialize(tc.domain.center, radius, REGION_TYPE.COLLISION);
geometry7 = geometry7.initialize(tc.domain.center + [d/2, d/2, 0], radius, REGION_TYPE.COLLISION);
% Initialize agent sensor model
sensor = sigmoidSensor;
alphaDist = l/2; % half of domain length/width
sensor = sensor.initialize(alphaDist, 3, NaN, NaN, 15, 3);
% Initialize agents
commsRadius = d;
tc.agents = {agent; agent; agent; agent; agent; agent; agent;};
tc.agents{1} = tc.agents{1}.initialize(tc.domain.center + [-0.9 * d/sqrt(2), 0.9 * d/sqrt(2), 0], zeros(1,3), 0, 0, geometry1, sensor, commsRadius);
tc.agents{2} = tc.agents{2}.initialize(tc.domain.center + [-0.5 * d, 0.25 * d, 0], zeros(1,3), 0, 0, geometry2, sensor, commsRadius);
tc.agents{3} = tc.agents{3}.initialize(tc.domain.center + [0.9 * d, 0, 0], zeros(1,3), 0, 0, geometry3, sensor, commsRadius);
tc.agents{4} = tc.agents{4}.initialize(tc.domain.center + [0.9 * d/sqrt(2), -0.9 * d/sqrt(2), 0], zeros(1,3), 0, 0, geometry4, sensor, commsRadius);
tc.agents{5} = tc.agents{5}.initialize(tc.domain.center + [0, 0.9 * d, 0], zeros(1,3), 0, 0, geometry5, sensor, commsRadius);
tc.agents{6} = tc.agents{6}.initialize(tc.domain.center, zeros(1,3), 0, 0, geometry6, sensor, commsRadius);
tc.agents{7} = tc.agents{7}.initialize(tc.domain.center + [d/2, d/2, 0], zeros(1,3), 0, 0, geometry7, sensor, commsRadius);
% 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);
% Constraint adjacency matrix defined by LNA should be as follows
tc.assertEqual(tc.testClass.constraintAdjacencyMatrix, logical( ...
[ 1, 1, 0, 0, 0, 0, 0; ...
1, 1, 0, 0, 1, 0, 0; ...
0, 0, 1, 1, 0, 0, 0;
0, 0, 1, 1, 0, 1, 0;
0, 1, 0, 0, 1, 1, 0;
0, 0, 0, 1, 1, 1, 1;
0, 0, 0, 0, 0, 1, 1; ]));
end end
end end