Skip to content
Draft
Show file tree
Hide file tree
Changes from 1 commit
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Prev Previous commit
Next Next commit
feat: add max attempts option to command line parsers and update rela…
…ted generators
  • Loading branch information
MichaelsJP committed May 27, 2025
commit 05f83254e1161e7d470203e98419f52e8068b05c
20 changes: 12 additions & 8 deletions docs/technical-details/api-benchmarks/coordinate-generators.md
Original file line number Diff line number Diff line change
Expand Up @@ -44,6 +44,7 @@ The tool generates random coordinates within a specified bounding box and then u
| `-m, --max-distances` | Maximum distances in meters **per profile** between the start and endpoint. | (none) |
| `-t, --threads` | Number of threads to use. | Available processors |
| `-sr, --snap-radius` | Search radius in meters for coordinate snapping. | 1000 |
| `-ma, --max-attempts` | Maximum number of attempts for coordinate generation. | 1000 |

### Route Generator Examples

Expand Down Expand Up @@ -78,6 +79,7 @@ Generate 50 routes for both driving-car and cycling-regular profiles with differ
--max-distances 5000,3000 \
--threads 4 \
--snap-radius 1500 \
--max-attempts 1500 \
--url http://localhost:8080/ors \
--output routes.csv"
```
Expand All @@ -94,14 +96,15 @@ The tool generates random coordinates within a specified bounding box and then u

### Snapping Generator Options

| Option | Description | Default |
|--------|-------------|---------|
| `-n, --num-points` | Number of points to generate per profile. | (required) |
| `-e, --extent` | Bounding box (minLon,minLat,maxLon,maxLat). | (required) |
| `-p, --profiles` | Comma-separated list of routing profiles. | (required) |
| `-r, --radius` | Search radius in meters. | 350 |
| `-u, --url` | ORS API base URL. | <http://localhost:8080/ors> |
| `-o, --output` | Output CSV file path. | snapped_coordinates.csv |
| Option | Description | Default |
|-----------------------|-------------------------------------------------------|-----------------------------|
| `-n, --num-points` | Number of points to generate per profile. | (required) |
| `-e, --extent` | Bounding box (minLon,minLat,maxLon,maxLat). | (required) |
| `-p, --profiles` | Comma-separated list of routing profiles. | (required) |
| `-r, --radius` | Search radius in meters. | 350 |
| `-u, --url` | ORS API base URL. | <http://localhost:8080/ors> |
| `-o, --output` | Output CSV file path. | snapped_coordinates.csv |
| `-ma, --max-attempts` | Maximum number of attempts for coordinate generation. | 1000 |

### Snapping Generator Examples

Expand Down Expand Up @@ -133,6 +136,7 @@ Generate 50 snapped points for both driving-car and cycling-regular profiles:
--extent 8.681495,49.411721,8.695485,49.419365 \
--profiles driving-car,cycling-regular \
--radius 250 \
--max-attempts 1500 \
--url http://localhost:8080/ors \
--output snapped.csv"
```
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,7 @@ public static void main(String[] args) {
CoordinateGeneratorRoute generator = cli.createGenerator();

LOGGER.info("Generating {} routes...", generator.getNumRoutes());
generator.generateRoutes();
generator.generate();
LOGGER.info("\n");

List<Route> result = generator.getResult();
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@ public class RouteCommandLineParser extends CommandLineParser {

private static final String OPT_THREADS = "threads";
private static final String OPT_SNAP_RADIUS = "snap-radius";
private static final String OPT_MAX_ATTEMPTS = "max-attempts";
private static final int DEFAULT_THREAD_COUNT = Runtime.getRuntime().availableProcessors();

public RouteCommandLineParser(String[] args) {
Expand Down Expand Up @@ -73,7 +74,6 @@ protected void setupOptions() {
.hasArg()
.desc("Maximum distances between coordinates in meters, comma-separated in profile order (e.g., 5000,3000)")
.build());

options.addOption(Option.builder("t")
.longOpt(OPT_THREADS)
.hasArg()
Expand All @@ -86,6 +86,13 @@ protected void setupOptions() {
.type(Number.class)
.desc("Search radius in meters for coordinate snapping (default: 1000)")
.build());

options.addOption(Option.builder("ma")
.longOpt(OPT_MAX_ATTEMPTS)
.hasArg()
.type(Number.class)
.desc("Maximum number of attempts for coordinate generation (default: 1000)")
.build());
}

@Override
Expand Down Expand Up @@ -124,6 +131,7 @@ public CoordinateGeneratorRoute createGenerator() {
String baseUrl = cmd.getOptionValue("u", "http://localhost:8080/ors");
double minDistance = Double.parseDouble(cmd.getOptionValue("d", "1"));
double snapRadius = Double.parseDouble(cmd.getOptionValue(OPT_SNAP_RADIUS, "1000"));
int maxAttempts = Integer.parseInt(cmd.getOptionValue(OPT_MAX_ATTEMPTS, String.valueOf(100)));

// Parse the max distances if provided
Map<String, Double> maxDistanceByProfile = parseMaxDistances(cmd.getOptionValue("m"), profiles);
Expand All @@ -132,13 +140,15 @@ public CoordinateGeneratorRoute createGenerator() {

if (LOGGER.isInfoEnabled()) {
LOGGER.info(
"Creating CoordinateGeneratorRoute with numRoutes={}, extent={}, profiles={}, baseUrl={}, minDistance={}, maxDistances={}, numThreads={}, snapRadius={}",
"Creating CoordinateGeneratorRoute with numRoutes={}, extent={}, profiles={}, baseUrl={}, minDistance={}, maxDistances={}, numThreads={}, snapRadius={}, maxAttempts={}",
numRoutes, extent, java.util.Arrays.toString(profiles), baseUrl, minDistance, maxDistanceByProfile,
numThreads, snapRadius);
numThreads, snapRadius, maxAttempts);
}

return new CoordinateGeneratorRoute(numRoutes, extent, profiles, baseUrl, minDistance, maxDistanceByProfile,
numThreads, snapRadius);
CoordinateGeneratorRoute generator = new CoordinateGeneratorRoute(numRoutes, extent, profiles, baseUrl,
minDistance, maxDistanceByProfile, numThreads, snapRadius, maxAttempts);
generator.generate();
return generator;
}

/**
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@

public class SnappingCommandLineParser extends CommandLineParser {
private static final Logger LOGGER = LoggerFactory.getLogger(SnappingCommandLineParser.class);
private static final String OPT_MAX_ATTEMPTS = "max-attempts";

public SnappingCommandLineParser(String[] args) {
super(args);
Expand Down Expand Up @@ -60,6 +61,13 @@ protected void setupOptions() {
.hasArg()
.desc("Output CSV file path")
.build());

options.addOption(Option.builder("ma")
.longOpt(OPT_MAX_ATTEMPTS)
.hasArg()
.type(Number.class)
.desc("Maximum number of attempts for coordinate generation (default: 1000)")
.build());
}

@Override
Expand Down Expand Up @@ -88,12 +96,17 @@ public CoordinateGeneratorSnapping createGenerator() {
String[] profiles = parseProfiles(cmd.getOptionValue("p"));
double radius = Double.parseDouble(cmd.getOptionValue("r", "350"));
String baseUrl = cmd.getOptionValue("u", "http://localhost:8080/ors");
int maxAttempts = Integer.parseInt(
cmd.getOptionValue(OPT_MAX_ATTEMPTS, "100"));

LOGGER.info(
"Creating CoordinateGeneratorSnapping with numPoints={}, extent={}, radius={}, profiles={}, baseUrl={}",
numPoints, extent, radius, profiles, baseUrl);
"Creating CoordinateGeneratorSnapping with numPoints={}, extent={}, radius={}, profiles={}, baseUrl={}, maxAttempts={}",
numPoints, extent, radius, profiles, baseUrl, maxAttempts);

return new CoordinateGeneratorSnapping(numPoints, extent, radius, profiles, baseUrl);
CoordinateGeneratorSnapping generator = new CoordinateGeneratorSnapping(numPoints, extent, radius, profiles,
baseUrl, maxAttempts);
generator.generate();
return generator;
}

/**
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,6 @@
*/
public abstract class AbstractCoordinateGenerator {
protected static final Logger LOGGER = LoggerFactory.getLogger(AbstractCoordinateGenerator.class);
protected static final int DEFAULT_MAX_ATTEMPTS = 10000;
protected static final double COORDINATE_PRECISION = 1e-6;
protected static final String DEFAULT_BASE_URL = "http://localhost:8082/ors";

Expand All @@ -35,6 +34,7 @@ public abstract class AbstractCoordinateGenerator {
protected final Random random;
protected final ObjectMapper mapper;
protected final String apiKey;
protected final int maxAttempts;

/**
* Creates a new coordinate generator
Expand All @@ -44,14 +44,16 @@ public abstract class AbstractCoordinateGenerator {
* @param baseUrl API base URL
* @param endpoint API endpoint name (for logging)
*/
protected AbstractCoordinateGenerator(double[] extent, String[] profiles, String baseUrl, String endpoint) {
protected AbstractCoordinateGenerator(double[] extent, String[] profiles, String baseUrl, String endpoint,
int maxAttempts) {
this.baseUrl = baseUrl != null ? baseUrl : DEFAULT_BASE_URL;
validateBaseInputParameters(extent, profiles, endpoint);
this.extent = extent;
this.profiles = profiles.clone();
this.random = new SecureRandom();
this.mapper = new ObjectMapper();
this.apiKey = getApiKey();
this.maxAttempts = maxAttempts;
}

private void validateBaseInputParameters(double[] extent, String[] profiles, String endpoint) {
Expand Down Expand Up @@ -130,11 +132,6 @@ protected String processResponse(ClassicHttpResponse response) throws IOExceptio
*/
public abstract void writeToCSV(String filePath) throws IOException;

/**
* Main generation method with specified maximum attempts
*/
protected abstract void generate(int maxAttempts);

/**
* Gets the generated results
*/
Expand All @@ -146,9 +143,8 @@ protected String processResponse(ClassicHttpResponse response) throws IOExceptio
protected abstract void initializeCollections();

/**
* Main generation method with default maximum attempts
* Main generation method
*/
public void generate() {
generate(DEFAULT_MAX_ATTEMPTS);
}
protected abstract void generate();

}
Original file line number Diff line number Diff line change
Expand Up @@ -48,8 +48,8 @@ public record MatrixDimensions(int numRows, int numCols) {

public CoordinateGeneratorMatrix(int numMatrices, double[] extent, String[] profiles, String baseUrl,
Map<String, Double> maxDistanceByProfile,
MatrixDimensions matrixDimensions, int numThreads, double snapRadius) {
super(extent, profiles, baseUrl, "matrix");
MatrixDimensions matrixDimensions, int numThreads, double snapRadius, int maxAttempts) {
super(extent, profiles, baseUrl, "matrix", maxAttempts);
validateInputs(numMatrices, numThreads);

this.numMatrices = numMatrices;
Expand Down Expand Up @@ -111,12 +111,12 @@ private Map<String, Double> normalizeMaxDistances(String[] profiles, Map<String,
}

public void generateMatrices() {
generate(DEFAULT_MAX_ATTEMPTS);
generate();
}

@Override
public void generate(int maxAttempts) {
LOGGER.info("Starting route generation with {} threads and max attempts: {}", numThreads, maxAttempts);
public void generate() {
LOGGER.info("Starting route generation with {} threads and max attempts: {}", numThreads, this.maxAttempts);
initializeCollections();

ExecutorService executor = null;
Expand All @@ -125,19 +125,19 @@ public void generate(int maxAttempts) {

try {
executor = Executors.newFixedThreadPool(numThreads);
executeMatrixGeneration(executor, maxAttempts, shouldContinue, consecutiveFailedAttempts);
executeMatrixGeneration(executor, shouldContinue, consecutiveFailedAttempts);
} catch (Exception e) {
LOGGER.error("Error generating routes: ", e);
} finally {
shutdownExecutor(executor);
}
}

private void executeMatrixGeneration(ExecutorService executor, int maxAttempts,
private void executeMatrixGeneration(ExecutorService executor,
AtomicBoolean shouldContinue, AtomicInteger consecutiveFailedAttempts) {
try (ProgressBar pb = createProgressBar()) {
while (!matrixRepository.areAllProfilesComplete(numMatrices) &&
consecutiveFailedAttempts.get() < maxAttempts &&
consecutiveFailedAttempts.get() < this.maxAttempts &&
shouldContinue.get()) {

int initialTotalMatrices = matrixRepository.getTotalMatrixCount();
Expand All @@ -161,13 +161,13 @@ private void executeMatrixGeneration(ExecutorService executor, int maxAttempts,
// Check if we made progress in this iteration
if (matrixRepository.getTotalMatrixCount() == initialTotalMatrices) {
int attempts = consecutiveFailedAttempts.incrementAndGet();
pb.setExtraMessage(String.format("Attempt %d/%d - No new routes", attempts, maxAttempts));
pb.setExtraMessage(String.format("Attempt %d/%d - No new routes", attempts, this.maxAttempts));
} else {
consecutiveFailedAttempts.set(0);
}
}

finalizeProgress(pb, maxAttempts, consecutiveFailedAttempts.get());
finalizeProgress(pb, consecutiveFailedAttempts.get());
}
}

Expand Down Expand Up @@ -202,11 +202,11 @@ private void updateProgressBar(ProgressBar pb) {
pb.setExtraMessage(matrixRepository.getProgressMessage());
}

private void finalizeProgress(ProgressBar pb, int maxAttempts, int attempts) {
private void finalizeProgress(ProgressBar pb, int attempts) {
pb.stepTo(matrixRepository.getTotalMatrixCount());
if (attempts >= maxAttempts) {
if (attempts >= this.maxAttempts) {
LOGGER.warn("Stopped route generation after {} attempts. Routes per profile: {}",
maxAttempts, matrixRepository.getProgressMessage());
this.maxAttempts, matrixRepository.getProgressMessage());
}
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -40,8 +40,8 @@ public class CoordinateGeneratorRoute extends AbstractCoordinateGenerator {

public CoordinateGeneratorRoute(int numRoutes, double[] extent, String[] profiles, String baseUrl,
double minDistance, Map<String, Double> maxDistanceByProfile, int numThreads,
double snapRadius) {
super(extent, profiles, baseUrl, "matrix");
double snapRadius, int maxAttempts) {
super(extent, profiles, baseUrl, "matrix", maxAttempts);
validateInputs(numRoutes, minDistance, numThreads);

this.numRoutes = numRoutes;
Expand Down Expand Up @@ -84,13 +84,9 @@ private Map<String, Double> normalizeMaxDistances(String[] profiles, Map<String,
return normalized;
}

public void generateRoutes() {
generate(DEFAULT_MAX_ATTEMPTS);
}

@Override
public void generate(int maxAttempts) {
LOGGER.info("Starting route generation with {} threads and max attempts: {}", numThreads, maxAttempts);
public void generate() {
LOGGER.info("Starting route generation with {} threads and max attempts: {}", numThreads, this.maxAttempts);
initializeCollections();
LOGGER.debug("Collections initialized.");

Expand All @@ -100,21 +96,21 @@ public void generate(int maxAttempts) {

try {
executor = Executors.newFixedThreadPool(numThreads);
executeRouteGeneration(executor, maxAttempts, shouldContinue, consecutiveFailedAttempts);
executeRouteGeneration(executor, shouldContinue, consecutiveFailedAttempts);
} catch (Exception e) {
LOGGER.error("Error generating routes: ", e);
} finally {
shutdownExecutor(executor);
}
}

private void executeRouteGeneration(ExecutorService executor, int maxAttempts,
AtomicBoolean shouldContinue, AtomicInteger consecutiveFailedAttempts) {
private void executeRouteGeneration(ExecutorService executor, AtomicBoolean shouldContinue,
AtomicInteger consecutiveFailedAttempts) {
LOGGER.debug("executeRouteGeneration: Starting. Max attempts: {}, Should continue: {}, Consecutive Fails: {}",
maxAttempts, shouldContinue.get(), consecutiveFailedAttempts.get());
this.maxAttempts, shouldContinue.get(), consecutiveFailedAttempts.get());
try (ProgressBar pb = createProgressBar()) {
while (!routeRepository.areAllProfilesComplete(numRoutes) &&
consecutiveFailedAttempts.get() < maxAttempts &&
consecutiveFailedAttempts.get() < this.maxAttempts &&
shouldContinue.get()) {
LOGGER.debug(
"executeRouteGeneration: Loop iteration. Profiles complete: {}, Consecutive Fails: {}, Should continue: {}",
Expand Down Expand Up @@ -154,7 +150,7 @@ private void executeRouteGeneration(ExecutorService executor, int maxAttempts,
}
}

finalizeProgress(pb, maxAttempts, consecutiveFailedAttempts.get());
finalizeProgress(pb, consecutiveFailedAttempts.get());
LOGGER.debug("executeRouteGeneration: Finalized progress.");
}
}
Expand Down Expand Up @@ -194,11 +190,11 @@ private void updateProgressBar(ProgressBar pb) {
pb.setExtraMessage(routeRepository.getProgressMessage());
}

private void finalizeProgress(ProgressBar pb, int maxAttempts, int attempts) {
private void finalizeProgress(ProgressBar pb, int attempts) {
pb.stepTo(routeRepository.getTotalRouteCount());
if (attempts >= maxAttempts) {
if (attempts >= this.maxAttempts) {
LOGGER.warn("Stopped route generation after {} attempts. Routes per profile: {}",
maxAttempts, routeRepository.getProgressMessage());
this.maxAttempts, routeRepository.getProgressMessage());
}
}

Expand Down
Loading