Baseline Flop Count Update, New Float Baseline

This commit is contained in:
[Quy Anh] «Elliot» Nguyen
2026-05-23 20:50:59 +02:00
committed by Ahmed Kallala
parent 40f4421d60
commit 43e54871df
18 changed files with 241860 additions and 68 deletions
+97
View File
@@ -0,0 +1,97 @@
#pragma once
#include "vector2d_float.hpp"
struct Obstacle {
Vector2d start; // First endpoint of the obstacle segment.
Vector2d end; // Second endpoint of the obstacle segment.
Vector2d obstacle_v; // Direction vector of the segment: end - start.
float length_sq_inv; // Inverse squared length of the segment, used for projection.
// Default constructor: creates a degenerate obstacle at the origin.
// This is mainly used for array allocation before assigning real obstacles.
Obstacle() : start(0, 0), end(0, 0), obstacle_v(0, 0), length_sq_inv(0.0) {}
// Constructs an obstacle as a finite line segment from s to e.
//
// The segment direction and inverse squared length are precomputed and cached because
// they are reused when projecting pedestrian positions onto the obstacle.
//
// @param s The first endpoint of the obstacle segment.
// @param e The second endpoint of the obstacle segment.
//
Obstacle(Vector2d s, Vector2d e) : start(s), end(e) {
obstacle_v = end - start;
float length_sq = obstacle_v.dot(obstacle_v);
length_sq_inv = length_sq != 0.0 ? 1.0 / length_sq : 0.0;
}
// Flop count: 5 ADDs, 5 MULTs
//
// Finds the point on this finite obstacle segment that is closest to p.
//
// The method projects the vector (p - start) onto the obstacle direction
// vector, then clamps the projection factor to [0, 1] so that the returned
// point lies on the finite segment.
//
// Note : If the obstacle is a single point, meaning start == end, length_sq_inv is zero
// and the method returns start.
//
// @param p The point for which the closest obstacle point is computed.
// @return The closest point on the obstacle segment to p.
//
Vector2d find_nearest_obstacle_point(const Vector2d &p) const {
// # 3 ADDs, 3 MULTs
float projection = (p - start).dot(obstacle_v) * length_sq_inv;
if (projection < 0.0)
projection = 0.0;
else if (projection > 1.0)
projection = 1.0;
// # 2 ADDs, 2 MULTs
return start + obstacle_v * projection;
}
};
struct Board {
float length; // Board length.
float width; // Board width.
Obstacle *obstacles; // Array of obstacles contained in the board.
int n_obstacles; // Total number of obstacles
// Constructs a rectangular board of size length x width.
//
// The input array o contains n user-defined obstacles. The constructor copies
// those obstacles and then appends the two horizontal borders of the board (bottom and top) as additional
// obstacle segments:
//
// bottom: (0, 0) -> (length, 0)
// top: (0, width) -> (length, width)
//
// Note: only the horizontal borders are modeled as obstacles. The vertical
// borders are left open so pedestrians can enter and leave the walkway without
// being affected by repulsive forces from those borders. This is consistent
// with Fig. 2 in the paper, where the horizontal walkway boundaries are
// emphasized but the vertical ends are not shown as walls.
//
// @param l The board length.
// @param w The board width.
// @param n The number of user-defined obstacles in o.
// @param o Array of user-defined obstacles to copy into the board obstacles array.
//
Board(float l, float w, int n, Obstacle *o) : length(l), width(w), n_obstacles(n + 2) {
obstacles = new Obstacle[n + 2];
for (int i = 0; i < n; i++) {
obstacles[i] = o[i];
}
// Board borders: bottom, top.
obstacles[n] = Obstacle(Vector2d(0, 0), Vector2d(l, 0));
obstacles[n + 1] = Obstacle(Vector2d(0, w), Vector2d(l, w));
}
// Releases the dynamically allocated obstacle array.
~Board() { delete[] obstacles; }
};
+44
View File
@@ -0,0 +1,44 @@
// # Replaced Vector2d with double
// # Predecessor: board.hpp
#pragma once
struct Obstacle {
double start_x;
double start_y;
double end_x;
double end_y;
double obstacle_v_x;
double obstacle_v_y;
double length_sq_inv;
Obstacle() : start_x(0), start_y(0), end_x(0), end_y(0), obstacle_v_x(0), obstacle_v_y(0), length_sq_inv(0.0) {}
Obstacle(double s_x, double s_y, double e_x, double e_y) : start_x(s_x), start_y(s_y), end_x(e_x), end_y(e_y) {
obstacle_v_x = end_x - start_x;
obstacle_v_y = end_y - start_y;
double length_sq = obstacle_v_x * obstacle_v_x + obstacle_v_y * obstacle_v_y;
length_sq_inv = length_sq != 0.0 ? 1.0 / length_sq : 0.0;
}
};
struct Board {
double length;
double width;
Obstacle *obstacles;
int n_obstacles;
Board(double l, double w, int n, Obstacle *o) : length(l), width(w), n_obstacles(n + 2) {
obstacles = new Obstacle[n + 2];
for (int i = 0; i < n; i++) {
obstacles[i] = o[i];
}
obstacles[n] = Obstacle(0, 0, l, 0);
obstacles[n + 1] = Obstacle(0, w, l, w);
}
~Board() { delete[] obstacles; }
};
+44
View File
@@ -0,0 +1,44 @@
// # Replaced double with float
// # Predecessor: board_reduced.hpp
#pragma once
struct Obstacle {
float start_x;
float start_y;
float end_x;
float end_y;
float obstacle_v_x;
float obstacle_v_y;
float length_sq_inv;
Obstacle() : start_x(0), start_y(0), end_x(0), end_y(0), obstacle_v_x(0), obstacle_v_y(0), length_sq_inv(0.0) {}
Obstacle(float s_x, float s_y, float e_x, float e_y) : start_x(s_x), start_y(s_y), end_x(e_x), end_y(e_y) {
obstacle_v_x = end_x - start_x;
obstacle_v_y = end_y - start_y;
float length_sq = obstacle_v_x * obstacle_v_x + obstacle_v_y * obstacle_v_y;
length_sq_inv = length_sq != 0.0 ? 1.0 / length_sq : 0.0;
}
};
struct Board {
float length;
float width;
Obstacle *obstacles;
int n_obstacles;
Board(float l, float w, int n, Obstacle *o) : length(l), width(w), n_obstacles(n + 2) {
obstacles = new Obstacle[n + 2];
for (int i = 0; i < n; i++) {
obstacles[i] = o[i];
}
obstacles[n] = Obstacle(0, 0, l, 0);
obstacles[n + 1] = Obstacle(0, w, l, w);
}
~Board() { delete[] obstacles; }
};
+105
View File
@@ -0,0 +1,105 @@
#pragma once
#include <cmath>
#include <new>
//
// $\frac{1}{\tau_{\alpha}}$; $\tau_{\alpha} = 0.5s$
//
const float tau_alpha_inv = 2.0;
// $V^0_{\alpha \beta}$
const float V0_AB = 2.1;
// $\sigma$
const float SIGMA = 0.3;
//
// $\frac{-1}{2\sigma}$
//
const float NEG_TWO_SIGMA_INV = -1.0 / (2 * SIGMA);
//
// $\frac{-V^0_{\alpha\beta}}{2\sigma}$
//
const float NEG_V0_AB_div_TWO_SIGMA = V0_AB * NEG_TWO_SIGMA_INV;
// $U^0_{\alpha B}$
const float U0_AB = 10.0;
// $R$
const float R = 0.2;
//
// $\frac{-1}{R}$
//
const float NEG_R_INV = -1.0 / R;
//
// $\frac{-U^0_{\alpha B}}{R}$
//
const float NEG_U0_AB_div_R = -U0_AB / R;
// $-c$
const float c_neg = -0.5;
// $\varphi$
const float phi = 100.0 / 180.0 * M_PI;
// $cos(\varphi)$
const float cos_phi = cos(phi);
//
// $\frac{1}{cos(\varphi)}$
//
const float cos_phi_inv = 1 / cos(phi);
// $<v^0>$
const float v0_mean = 1.34;
// $\sqrt{\theta}$
const float v0_std_dev = 0.26;
// $\varDelta_{t}$
const float delta_t = 2;
// $\varDelta_{t}^2$
const float delta_t_sq = delta_t * delta_t;
// $dt$
const float dt = 0.02;
// $-dt$
const float dt_neg = -dt;
// $-c \cdot dt$
const float c_neg_times_dt = c_neg * dt;
//
// $\frac{1}{\tau_{\alpha}} \cdot dt$
//
const float dt_times_tau_alpha_inv = dt * tau_alpha_inv;
const float cost_add = 1;
const float cost_mult = 1;
const float cost_div = 1;
// https://acl.inf.ethz.ch/teaching/fastcode/knowledgebase/#:~:text=How%20do%20exp(x)%2C%20sin(x)%2C%20etc.%20count%20in%20the%20flopcount%20of%20an%20algorithm%3F
const float cost_exp = 30;
// -O3 maps each sqrt() call to an instruction
const float cost_sqrt = 1;
// Numerical tolerance used to avoid division by zero and unstable operations
// when distances or norms are extremely small.
const float EPS = 1e-9;
// Squared numerical tolerance
const float EPS_SQ = EPS * EPS;
// Cutoff for pedestrian-pedestrian repulsion
const float CUTOFF = 12.0;
const float CUTOFF_SQ = CUTOFF * CUTOFF;
const float cos_phi_sq = cos_phi * cos_phi;
const size_t CACHE_BLOCK_SIZE = std::hardware_destructive_interference_size;
+65
View File
@@ -0,0 +1,65 @@
#pragma once
#include "constants_float.hpp"
#include "vector2d_float.hpp"
// Needed for visual simulation, in order to distinguish two groups of pedestrians:
// - White pedestrians move from left to right
// - Black pedestrians move from right to left
enum Color { WHITE, BLACK};
struct Pedestrian {
Color color;
// $\vec{v}_{\alpha}(t)$
Vector2d curr_vel; // v_alpha (actual, ≤ v_max)
// $\vec{w}_{\alpha}$
Vector2d w; // w_alpha (preferred, integrates force)
// $\vec{r}_\alpha(t)$
Vector2d curr_pos;
// $\vec{e}_{\alpha}(t)$
Vector2d e; // desired direction vector
// $v_{\alpha}^{max} = 1.3 v^{0}_{\alpha}$
float v_max;
// $v_\alpha^0$
float desired_v0;
// $\vec{r}^0_\alpha$
Vector2d destination;
// $s_\beta^2 = (v_\beta \Delta t)^2$
float s_b_sq;
// $s_\beta \vec{e}_\beta$
Vector2d s_b_e;
// Default constructor: initializes a pedestrian with color WHITE and all vector/scalar fields set to zero.
Pedestrian() : color(WHITE), curr_vel(0.0, 0.0), w(0.0, 0.0), curr_pos(0.0, 0.0), e(0.0, 0.0), v_max(0.0), desired_v0(0.0), destination(0.0, 0.0), s_b_sq(0.0), s_b_e(0.0, 0.0) {}
// Constructs a pedestrian with the given initial state and precomputes the
// quantities used in the pedestrian-pedestrian repulsion term.
//
// The preferred velocity w is initialized to the current velocity c_v. The
// cached quantities s_b_sq and s_b_e correspond to the predicted step of this
// pedestrian over $\Delta t$:
//
// s_b = ||c_v|| * dt
// s_b_sq = s_b^2
// s_b_e = e * s_b
//
// These values are used when another pedestrian computes the elliptical
// interaction term involving this pedestrian.
//
// @param clr The display/color category of the pedestrian.
// @param c_v The initial current velocity.
// @param c_p The initial current position.
// @param e The initial desired direction of motion.
// @param v_max The maximum speed that the pedestrian can reach.
// @param desired_v0 The desired walking speed.
// @param d The pedestrian's target destination point.
//
Pedestrian(Color clr, Vector2d c_v, Vector2d c_p, Vector2d e, float v_max, float desired_v0, Vector2d d) : color(clr), curr_vel(c_v), w(c_v), curr_pos(c_p), e(e), v_max(v_max), desired_v0(desired_v0), destination(d), s_b_sq(c_v.dot(c_v) * delta_t_sq), s_b_e(e * c_v.norm() * delta_t) {}
};
+38
View File
@@ -0,0 +1,38 @@
// # Replaced double with float
// # Predecessor: pedestrian_reduced.hpp
#pragma once
#include "constants_float.hpp"
struct Pedestrian {
int color;
float curr_vel_x;
float curr_vel_y;
float w_x;
float w_y;
float curr_pos_x;
float curr_pos_y;
float e_x;
float e_y;
float v_max;
float desired_v0;
float destination_x;
float destination_y;
float s_b_sq;
float s_b_e_x;
float s_b_e_y;
Pedestrian() : color(0), curr_vel_x(0.0), curr_vel_y(0), w_x(0.0), w_y(0.0), curr_pos_x(0.0), curr_pos_y(0.0), e_x(0.0), e_y(0.0), v_max(0.0), desired_v0(0.0), destination_x(0.0), destination_y(0.0), s_b_sq(0.0), s_b_e_x(0.0), s_b_e_y(0.0) {}
Pedestrian(int clr, float c_v_x, float c_v_y, float c_p_x, float c_p_y, float e_x, float e_y, float v_max, float desired_v0, float d_x, float d_y)
: color(clr), curr_vel_x(c_v_x), curr_vel_y(c_v_y), w_x(c_v_x), w_y(c_v_y), curr_pos_x(c_p_x), curr_pos_y(c_p_y), e_x(e_x), e_y(e_y), v_max(v_max), desired_v0(desired_v0), destination_x(d_x), destination_y(d_y), s_b_sq((c_v_x * c_v_x + c_v_y * c_v_y) * delta_t_sq), s_b_e_x(e_x * (sqrt(c_v_x * c_v_x + c_v_y * c_v_y)) * delta_t), s_b_e_y(e_y * (sqrt(c_v_x * c_v_x + c_v_y * c_v_y)) * delta_t) {}
};
+34
View File
@@ -0,0 +1,34 @@
#pragma once
#include "board_float.hpp"
#include "pedestrian_float.hpp"
// Initializes the pedestrians used in the simulation.
//
// The returned array contains n_p pedestrians split into two groups:
// one group walking from left to right and one group walking from right to left.
// Pedestrian positions, desired speeds, destinations, and initial directions are
// initialized according to the simulation setup.
//
// @param n_p : Number of pedestrians to initialize.
// @return Pointer to a dynamically allocated array of pedestrians.
Pedestrian *init_pedestrians(int n_p);
// Initializes a simulation board with no obstacles inside.
//
// @return Initialized Board instance.
Board init_board_without_obstacles();
// Runs the social force model with n_p pedestrians for n_iter iterations,
// i.e., n_iter * dt simulated seconds.
// If dump_path is not nullptr, the simulation states are written to that CSV
// file, which can be used to generate a visualization video. If dump_path is
// nullptr, no output file is generated.
//
// @param pedestrians : Array of pedestrians to simulate. The array is updated in place.
// @param board : Board containing the simulation dimensions and obstacles.
// @param n_p : Number of pedestrians.
// @param n_iter : Number of simulation iterations.
// @param dump_path : Optional path to the CSV output file.
// @return 0 on success.
int run_simulation(Pedestrian *pedestrians, Board &board, int n_p, int n_iter, const char *dump_path);
+34
View File
@@ -0,0 +1,34 @@
#pragma once
#include <math.h>
struct Vector2d {
float x, y;
Vector2d(float a, float b) : x(a), y(b) {}
Vector2d() : x(.0), y(.0) {}
Vector2d operator+(Vector2d v) const { return Vector2d(v.x + x, v.y + y); }
Vector2d operator-(Vector2d v) const { return Vector2d(x - v.x, y - v.y); }
Vector2d operator-(float a) const { return Vector2d(x - a, y - a); }
Vector2d operator+(float a) const { return Vector2d(x + a, y + a); }
Vector2d operator/(float a) const { return Vector2d(x / a, y / a); }
Vector2d operator*(float a) const { return Vector2d(x * a, y * a); }
Vector2d operator+=(const Vector2d &v) {
*this = *this + v;
return *this;
}
Vector2d operator-=(const Vector2d &v) {
*this = *this - v;
return *this;
}
Vector2d reverse_sign() { return Vector2d(-x, -y); }
// # 1 ADD, 2 MULTs, 1 SQRT
float norm() { return sqrt(x * x + y * y); }
// # 1 ADD, 2 MULTs
float dot(Vector2d v) { return x * v.x + y * v.y; }
void reset() {
x = 0;
y = 0;
}
};