refactored sensing objective into domain, random inits

This commit is contained in:
2025-11-15 16:01:18 -08:00
parent e0f365b21b
commit afa5d79c1d
13 changed files with 110 additions and 51 deletions

View File

@@ -16,7 +16,7 @@ function [obj, f] = plot(obj)
end
% Plot objective gradient
f = obj.objective.plot(obj.objectivePlotIndices, f);
f = obj.domain.objective.plot(obj.objectivePlotIndices, f);
% Plot agents and their collision geometries
for ii = 1:size(obj.agents, 1)

View File

@@ -1,22 +1,21 @@
function obj = initialize(obj, objectiveFunction, footprint, groundAlt, discretizationStep)
function obj = initialize(obj, objectiveFunction, domain, discretizationStep)
arguments (Input)
obj (1,1) {mustBeA(obj, 'sensingObjective')};
objectiveFunction (1, 1) {mustBeA(objectiveFunction, 'function_handle')};
footprint (:, 2) double;
groundAlt (1, 1) double = 0;
domain (1, 1) {mustBeGeometry};
discretizationStep (1, 1) double = 1;
end
arguments (Output)
obj (1,1) {mustBeA(obj, 'sensingObjective')};
end
obj.groundAlt = groundAlt;
obj.groundAlt = domain.minCorner(3);
% Extract footprint limits
xMin = min(footprint(:, 1));
xMax = max(footprint(:, 1));
yMin = min(footprint(:, 2));
yMax = max(footprint(:, 2));
xMin = min(domain.footprint(:, 1));
xMax = max(domain.footprint(:, 1));
yMin = min(domain.footprint(:, 2));
yMax = max(domain.footprint(:, 2));
xGrid = unique([xMin:discretizationStep:xMax, xMax]);
yGrid = unique([yMin:discretizationStep:yMax, yMax]);

View File

@@ -0,0 +1,27 @@
function obj = initializeRandomMvnpdf(obj, domain, protectedRange, discretizationStep)
arguments (Input)
obj (1, 1) {mustBeA(obj, 'sensingObjective')};
domain (1, 1) {mustBeGeometry};
protectedRange (1, 1) double = 1;
discretizationStep (1, 1) double = 1;
end
arguments (Output)
obj (1, 1) {mustBeA(obj, 'sensingObjective')};
end
% Set random objective position
mu = domain.minCorner;
while domain.distance(mu) < protectedRange
mu = domain.random();
end
mu = mu(1:2);
% Set random distribution parameters
sig = [2 + rand * 2, 1; 1, 2 + rand * 2];
% Set up random bivariate normal distribution function
objectiveFunction = @(x, y) mvnpdf([x(:), y(:)], mu, sig);
% Regular initialization
obj = obj.initialize(objectiveFunction, domain, discretizationStep);
end

View File

@@ -18,7 +18,6 @@ function f = plot(obj, ind, f)
o.HitTest = 'off';
o.PickableParts = 'none';
hold(f.CurrentAxes, "off");
else
hold(f.Children(1).Children(ind(1)), "on");
o = surf(f.Children(1).Children(ind(1)), obj.X, obj.Y, repmat(obj.groundAlt, size(obj.X)), obj.values ./ max(obj.values, [], "all"), 'EdgeColor', 'none');

View File

@@ -12,7 +12,8 @@ classdef sensingObjective
end
methods (Access = public)
[obj] = initialize(obj, objectiveFunction, footprint, groundAlt, discretizationStep);
[obj] = initialize(obj, objectiveFunction, domain, discretizationStep);
[obj] = initializeRandomMvnpdf(obj, domain, protectedRange, discretizationStep);
[f ] = plot(obj, ind, f);
end
end

View File

@@ -1,9 +1,11 @@
function obj = initialize(obj, bounds, tag, label)
function obj = initialize(obj, bounds, tag, label, objectiveFunction, discretizationStep)
arguments (Input)
obj (1, 1) {mustBeA(obj, 'rectangularPrism')};
bounds (2, 3) double;
tag (1, 1) REGION_TYPE = REGION_TYPE.INVALID;
label (1, 1) string = "";
objectiveFunction (1, 1) function_handle = @(x, y) 1;
discretizationStep (1, 1) double = 1;
end
arguments (Output)
obj (1, 1) {mustBeA(obj, 'rectangularPrism')};
@@ -12,7 +14,7 @@ function obj = initialize(obj, bounds, tag, label)
obj.tag = tag;
obj.label = label;
%% Define geometry bounds by LL corner and UR corner
% Define geometry bounds by LL corner and UR corner
obj.minCorner = bounds(1, 1:3);
obj.maxCorner = bounds(2, 1:3);
@@ -37,4 +39,9 @@ function obj = initialize(obj, bounds, tag, label)
[obj.minCorner(1), obj.maxCorner(2)]; ...
[obj.maxCorner(1), obj.minCorner(2)]; ...
obj.maxCorner(1:2)];
% Instantiate sensingObjective only for DOMAIN-type regions
if tag == REGION_TYPE.DOMAIN
obj.objective = sensingObjective;
end
end

View File

@@ -0,0 +1,18 @@
function [obj] = initializeRandom(obj, minDimension, tag, label)
arguments (Input)
obj (1, 1) {mustBeA(obj, 'rectangularPrism')};
minDimension (1, 1) double = 10;
tag (1, 1) REGION_TYPE = REGION_TYPE.INVALID;
label (1, 1) string = "";
end
arguments (Output)
obj (1, 1) {mustBeA(obj, 'rectangularPrism')};
end
% Produce random bounds
L = ceil(minDimension + rand * minDimension);
bounds = [zeros(1, 3); L * ones(1, 3)];
% Regular initialization
obj = obj.initialize(bounds, tag, label);
end

View File

@@ -21,9 +21,14 @@ classdef rectangularPrism
% Plotting
lines;
end
properties (SetAccess = public, GetAccess = public)
% Sensing objective (for DOMAIN region type only)
objective;
end
methods (Access = public)
[obj ] = initialize(obj, bounds, tag, label);
[obj ] = initialize(obj, bounds, tag, label, objectiveFunction, discretizationStep);
[obj ] = initializeRandom(obj, tag, label);
[r ] = random(obj);
[c ] = contains(obj, pos);
[d ] = distance(obj, pos);

View File

@@ -0,0 +1,6 @@
<?xml version="1.0" encoding="UTF-8"?>
<Info>
<Category UUID="FileClassCategory">
<Label UUID="design"/>
</Category>
</Info>

View File

@@ -0,0 +1,2 @@
<?xml version="1.0" encoding="UTF-8"?>
<Info location="initializeRandomMvnpdf.m" type="File"/>

View File

@@ -0,0 +1,6 @@
<?xml version="1.0" encoding="UTF-8"?>
<Info>
<Category UUID="FileClassCategory">
<Label UUID="design"/>
</Category>
</Info>

View File

@@ -0,0 +1,2 @@
<?xml version="1.0" encoding="UTF-8"?>
<Info location="initializeRandom.m" type="File"/>

View File

@@ -2,12 +2,15 @@ classdef test_miSim < matlab.unittest.TestCase
properties (Access = private)
testClass = miSim;
% Domain
domain = rectangularPrism; % domain geometry
% Sim
maxIter = 250;
timestep = 0.05
partitoningFreq = 5;
% Domain
domain = rectangularPrism; % domain geometry
minDimension = 10;
% Obstacles
minNumObstacles = 1; % Minimum number of obstacles to be randomly generated
maxNumObstacles = 3; % Maximum number of obstacles to be randomly generated
@@ -16,7 +19,7 @@ classdef test_miSim < matlab.unittest.TestCase
obstacles = cell(1, 0);
% Objective
objectiveDiscretizationStep = 0.01; % Step at which the objective function is solved in X and Y space
discretizationStep = 0.01; % Step at which the objective function is solved in X and Y space
protectedRange = 1; % Minimum distance between the sensing objective and the edge of the domain
objective = sensingObjective;
@@ -39,26 +42,10 @@ classdef test_miSim < matlab.unittest.TestCase
methods (TestMethodSetup)
% Generate a random domain
function tc = setDomain(tc)
% random integer-sized cube domain ranging from [0, 5 -> 25]
% in all dimensions
L = ceil(5 + rand * 10 + rand * 10);
tc.domain = tc.domain.initialize([zeros(1, 3); L * ones(1, 3)], REGION_TYPE.DOMAIN, "Domain");
end
% Generate a random sensing objective within that domain
function tc = setSensingObjective(tc)
% Using a bivariate normal distribution
% Set peak position (mean)
mu = tc.domain.minCorner;
while tc.domain.distance(mu) < tc.protectedRange
mu = tc.domain.random();
end
mu(3) = 0;
% Set standard deviations of bivariate distribution
sig = [2 + rand * 2, 1; 1, 2 + rand * 2];
% Define objective
tc.objective = tc.objective.initialize(@(x, y) mvnpdf([x(:), y(:)], mu(1:2), sig), tc.domain.footprint, tc.domain.minCorner(3), tc.objectiveDiscretizationStep);
% random integer-dimensioned cubic domain
tc.domain = tc.domain.initializeRandom(tc.minDimension, REGION_TYPE.DOMAIN, "Domain");
% Random bivariate normal PDF objective
tc.domain.objective = tc.domain.objective.initializeRandomMvnpdf(tc.domain, tc.protectedRange, tc.discretizationStep);
end
% Instantiate agents
function tc = setAgents(tc)
@@ -121,13 +108,13 @@ classdef test_miSim < matlab.unittest.TestCase
% Make sure that the obstacles don't cover the sensing
% objective
if obstacleCoversObjective(tc.objective, tc.obstacles{ii})
if obstacleCoversObjective(tc.domain.objective, tc.obstacles{ii})
continue;
end
% Make sure that the obstacles aren't too close to the
% sensing objective
if obstacleCrowdsObjective(tc.objective, tc.obstacles{ii}, tc.protectedRange)
if obstacleCrowdsObjective(tc.domain.objective, tc.obstacles{ii}, tc.protectedRange)
continue;
end
@@ -140,11 +127,11 @@ classdef test_miSim < matlab.unittest.TestCase
for ii = 1:size(tc.agents, 1)
initInvalid = true;
while initInvalid
candidatePos = [tc.objective.groundPos, 0];
candidatePos = [tc.domain.objective.groundPos, 0];
% Generate a random position for the agent based on
% existing agent positions
if ii == 1
while agentsCrowdObjective(tc.objective, candidatePos, mean(tc.domain.dimensions) / 2)
while agentsCrowdObjective(tc.domain.objective, candidatePos, mean(tc.domain.dimensions) / 2)
candidatePos = tc.domain.random();
end
else
@@ -159,7 +146,7 @@ classdef test_miSim < matlab.unittest.TestCase
% Make sure that the candidate position does not crowd
% the sensing objective and create boring scenarios
if agentsCrowdObjective(tc.objective, candidatePos, mean(tc.domain.dimensions) / 2)
if agentsCrowdObjective(tc.domain.objective, candidatePos, mean(tc.domain.dimensions) / 2)
continue;
end
@@ -243,7 +230,7 @@ classdef test_miSim < matlab.unittest.TestCase
end
% Initialize the simulation
[tc.testClass, f] = tc.testClass.initialize(tc.domain, tc.objective, tc.agents, tc.timestep, tc.partitoningFreq, tc.maxIter, tc.obstacles);
[tc.testClass, f] = tc.testClass.initialize(tc.domain, tc.domain.objective, tc.agents, tc.timestep, tc.partitoningFreq, tc.maxIter, tc.obstacles);
end
function misim_run(tc)
% randomly create obstacles
@@ -289,13 +276,13 @@ classdef test_miSim < matlab.unittest.TestCase
% Make sure that the obstacles don't cover the sensing
% objective
if obstacleCoversObjective(tc.objective, tc.obstacles{ii})
if obstacleCoversObjective(tc.domain.objective, tc.obstacles{ii})
continue;
end
% Make sure that the obstacles aren't too close to the
% sensing objective
if obstacleCrowdsObjective(tc.objective, tc.obstacles{ii}, tc.protectedRange)
if obstacleCrowdsObjective(tc.domain.objective, tc.obstacles{ii}, tc.protectedRange)
continue;
end
@@ -308,11 +295,11 @@ classdef test_miSim < matlab.unittest.TestCase
for ii = 1:size(tc.agents, 1)
initInvalid = true;
while initInvalid
candidatePos = [tc.objective.groundPos, 0];
candidatePos = [tc.domain.objective.groundPos, 0];
% Generate a random position for the agent based on
% existing agent positions
if ii == 1
while agentsCrowdObjective(tc.objective, candidatePos, mean(tc.domain.dimensions) / 2)
while agentsCrowdObjective(tc.domain.objective, candidatePos, mean(tc.domain.dimensions) / 2)
candidatePos = tc.domain.random();
end
else
@@ -327,7 +314,7 @@ classdef test_miSim < matlab.unittest.TestCase
% Make sure that the candidate position does not crowd
% the sensing objective and create boring scenarios
if agentsCrowdObjective(tc.objective, candidatePos, mean(tc.domain.dimensions) / 2)
if agentsCrowdObjective(tc.domain.objective, candidatePos, mean(tc.domain.dimensions) / 2)
continue;
end
@@ -411,7 +398,7 @@ classdef test_miSim < matlab.unittest.TestCase
end
% Initialize the simulation
[tc.testClass, f] = tc.testClass.initialize(tc.domain, tc.objective, tc.agents, tc.timestep, tc.partitoningFreq, tc.maxIter, tc.obstacles);
[tc.testClass, f] = tc.testClass.initialize(tc.domain, tc.domain.objective, tc.agents, tc.timestep, tc.partitoningFreq, tc.maxIter, tc.obstacles);
% Run simulation loop
[tc.testClass, f] = tc.testClass.run(f);
@@ -424,7 +411,7 @@ classdef test_miSim < matlab.unittest.TestCase
tc.domain = tc.domain.initialize([zeros(1, 3); 10 * ones(1, 3)], REGION_TYPE.DOMAIN, "Domain");
% make basic sensing objective
tc.objective = tc.objective.initialize(@(x, y) mvnpdf([x(:), y(:)], tc.domain.center(1:2), eye(2)), tc.domain.footprint, tc.domain.minCorner(3), tc.objectiveDiscretizationStep);
tc.domain.objective = tc.domain.objective.initialize(@(x, y) mvnpdf([x(:), y(:)], tc.domain.center(1:2), eye(2)), tc.domain.footprint, tc.domain.minCorner(3), tc.discretizationStep);
% Initialize agent collision geometry
geometry1 = rectangularPrism;
@@ -442,7 +429,7 @@ classdef test_miSim < matlab.unittest.TestCase
tc.agents{2} = tc.agents{2}.initialize(tc.domain.center - [d, 0, 0], zeros(1,3), 0, 0, geometry2, sensor, @gradientAscent, 3*d, 2, sprintf("Agent %d", 2));
% Initialize the simulation
[tc.testClass, f] = tc.testClass.initialize(tc.domain, tc.objective, tc.agents, tc.timestep, tc.partitoningFreq, tc.maxIter);
[tc.testClass, f] = tc.testClass.initialize(tc.domain, tc.domain.objective, tc.agents, tc.timestep, tc.partitoningFreq, tc.maxIter);
end
end
end