feat: add support for dynamically varying algorithm paramters
This commit is contained in:
parent
3d2b41d7df
commit
f5197bfc85
@ -12,7 +12,7 @@ struct Agent {
|
|||||||
using F = std::function<float(T)>;
|
using F = std::function<float(T)>;
|
||||||
|
|
||||||
virtual void move(float dt) = 0;
|
virtual void move(float dt) = 0;
|
||||||
virtual void step(float dt) = 0;
|
virtual void step() = 0;
|
||||||
|
|
||||||
virtual std::pair<float, T> best() const = 0;
|
virtual std::pair<float, T> best() const = 0;
|
||||||
|
|
||||||
@ -21,44 +21,87 @@ protected:
|
|||||||
F f;
|
F f;
|
||||||
};
|
};
|
||||||
|
|
||||||
template<std::size_t N>
|
template <typename A>
|
||||||
|
concept ParameterChangeAlgorithm = requires(A alg, float f, unsigned int i) {
|
||||||
|
{ alg(f, f, f, i, i) } -> std::same_as<vec<3>>;
|
||||||
|
};
|
||||||
|
|
||||||
|
namespace ParamChange {
|
||||||
|
struct Const {
|
||||||
|
vec<3> operator()(
|
||||||
|
float visc, float nostal, float peerp, int _1, int _2) {
|
||||||
|
return {visc, nostal, peerp};
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
struct MLinAlg {
|
||||||
|
vec<3> operator()(
|
||||||
|
float visc, float nostal, float peerp, int curr, int max) {
|
||||||
|
float pct_done = (float)curr / (float)max;
|
||||||
|
return {
|
||||||
|
visc - (0.9f - 0.4f) * pct_done,
|
||||||
|
nostal - (2.5f - 0.5f) * pct_done,
|
||||||
|
peerp + (2.5f - 0.5f) * pct_done,
|
||||||
|
};
|
||||||
|
}
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
|
template<std::size_t N, ParameterChangeAlgorithm A = ParamChange::MLinAlg>
|
||||||
struct Particle : public Agent<vec<N>> {
|
struct Particle : public Agent<vec<N>> {
|
||||||
std::pair<float, vec<N>> best() const override { return {pb, pb_pos}; };
|
std::pair<float, vec<N>> best() const override { return {pb, pb_pos}; };
|
||||||
|
|
||||||
void move(float dt=1) override { position = position + velocity * dt; }
|
void move(float dt=1) override { position = position + velocity * dt; }
|
||||||
|
|
||||||
void step(float dt=1) override {
|
void step() override {
|
||||||
velocity = kviscosity * velocity
|
velocity = viscosity * velocity
|
||||||
+ knostalgia * (pb_pos - position)
|
+ nostalgia * (pb_pos - position)
|
||||||
+ kpeer_pressure * (peer.best().second - position);
|
+ peer_pressure * (peer.best().second - position);
|
||||||
|
|
||||||
float y = f(position);
|
float y = f(position);
|
||||||
if(y < pb) {
|
if(y < pb) {
|
||||||
pb = y;
|
pb = y;
|
||||||
pb_pos = position;
|
pb_pos = position;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
vec<3> params = alg(kviscosity, knostalgia, kpeer_pressure,
|
||||||
|
curr_iter, max_iter);
|
||||||
|
|
||||||
|
viscosity = params.x;
|
||||||
|
nostalgia = params.y;
|
||||||
|
peer_pressure = params.z;
|
||||||
|
|
||||||
|
curr_iter++;
|
||||||
};
|
};
|
||||||
|
|
||||||
float kviscosity = 0.9f;
|
const float kviscosity = 0.9f;
|
||||||
float knostalgia = 2.5f;
|
const float knostalgia = 2.5f;
|
||||||
float kpeer_pressure = 0.5f;
|
const float kpeer_pressure = 0.5f;
|
||||||
|
|
||||||
|
float viscosity = kviscosity;
|
||||||
|
float nostalgia = knostalgia;
|
||||||
|
float peer_pressure = kpeer_pressure;
|
||||||
|
|
||||||
Particle(Agent<vec<N>>::F f, const Agent<vec<N>>& peer,
|
Particle(Agent<vec<N>>::F f, const Agent<vec<N>>& peer,
|
||||||
vec<N> position, vec<N> velocity)
|
vec<N> position, vec<N> velocity, unsigned max_iter)
|
||||||
: Agent<vec<N>>(f), position(position), velocity(velocity),
|
: Agent<vec<N>>(f), position(position), velocity(velocity),
|
||||||
pb_pos(position), peer(peer) {
|
pb_pos(position), max_iter(max_iter), peer(peer) {
|
||||||
pb = f(position);
|
pb = f(position);
|
||||||
}
|
}
|
||||||
|
|
||||||
const vec<N> &get_position() const { return position; };
|
const vec<N> &get_position() const { return position; };
|
||||||
|
|
||||||
private:
|
private:
|
||||||
|
A alg;
|
||||||
vec<N> position;
|
vec<N> position;
|
||||||
vec<N> velocity;
|
vec<N> velocity;
|
||||||
|
|
||||||
vec<N> pb_pos;
|
vec<N> pb_pos;
|
||||||
float pb;
|
float pb;
|
||||||
|
|
||||||
|
unsigned curr_iter = 0;
|
||||||
|
unsigned max_iter;
|
||||||
|
|
||||||
const Agent<vec<N>>& peer;
|
const Agent<vec<N>>& peer;
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -71,7 +114,7 @@ struct Swarm : public Agent<vec<N>> {
|
|||||||
p.move(dt);
|
p.move(dt);
|
||||||
}
|
}
|
||||||
|
|
||||||
void step(float dt=1) override {
|
void step() override {
|
||||||
if(particles.empty()) return;
|
if(particles.empty()) return;
|
||||||
|
|
||||||
// find best before step() on each particle
|
// find best before step() on each particle
|
||||||
@ -85,26 +128,28 @@ struct Swarm : public Agent<vec<N>> {
|
|||||||
best_pos = b->best().second;
|
best_pos = b->best().second;
|
||||||
|
|
||||||
for(auto &p : particles)
|
for(auto &p : particles)
|
||||||
p.step(dt);
|
p.step();
|
||||||
}
|
}
|
||||||
|
|
||||||
void add_particle(std::size_t n=1) {
|
void add_particle(std::size_t n=1) {
|
||||||
for(std::size_t i=0; i <= n; ++i)
|
for(std::size_t i=0; i <= n; ++i)
|
||||||
particles.push_back(
|
particles.push_back(
|
||||||
Particle<N>(this->_f, *this, vec<N>(0), vec<N>(10))
|
Particle<N>(this->_f, *this, vec<N>(0), vec<N>(10), max_iter)
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
void add_particle(const vec<N> &pos, const vec<N> &vel) {
|
void add_particle(const vec<N> &pos, const vec<N> &vel) {
|
||||||
particles.push_back(
|
particles.push_back(
|
||||||
Particle<N>(this->f, *this, pos, vel)
|
Particle<N>(this->f, *this, pos, vel, max_iter)
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
const std::vector<Particle<N>>& get_particles() { return particles; };
|
const std::vector<Particle<N>>& get_particles() { return particles; };
|
||||||
|
|
||||||
Swarm(Agent<vec<N>>::F f) : Agent<vec<N>>(f) {}
|
Swarm(Agent<vec<N>>::F f, unsigned max_iter = 150)
|
||||||
|
: Agent<vec<N>>(f), max_iter(max_iter) {}
|
||||||
private:
|
private:
|
||||||
|
unsigned max_iter;
|
||||||
vec<N> best_pos;
|
vec<N> best_pos;
|
||||||
float best_val;
|
float best_val;
|
||||||
std::vector<Particle<N>> particles;
|
std::vector<Particle<N>> particles;
|
||||||
|
@ -8,8 +8,8 @@ static constexpr int kFPS = 60;
|
|||||||
static constexpr float kDT = 1.0 / kFPS;
|
static constexpr float kDT = 1.0 / kFPS;
|
||||||
|
|
||||||
float f(vec<2> x) {
|
float f(vec<2> x) {
|
||||||
return 50 * (std::pow(std::sin((x.x - 10)/2),2) + std::pow(std::sin(x.y/2),2))
|
return 50 * (std::pow(std::sin((x.x - 10)/2),2) + std::pow(std::sin(x.y/2),2)) +
|
||||||
+ std::pow(std::abs(x.x - 10), 1.2) + std::pow(std::abs(x.y), 1.2);
|
std::pow(std::abs(x.x - 3.141592653589), 1.2) + std::pow(std::abs(x.y), 1.2);
|
||||||
}
|
}
|
||||||
|
|
||||||
int
|
int
|
||||||
@ -18,7 +18,7 @@ main(int argc, char **argv) {
|
|||||||
if(argc < 2) iter_count = 100;
|
if(argc < 2) iter_count = 100;
|
||||||
else sscanf(argv[1], "%d", &iter_count);
|
else sscanf(argv[1], "%d", &iter_count);
|
||||||
|
|
||||||
Swarm<2> swarm(f);
|
Swarm<2> swarm(f, iter_count);
|
||||||
Screen scr(80, 24);
|
Screen scr(80, 24);
|
||||||
|
|
||||||
TanhColorizer tanh_col;
|
TanhColorizer tanh_col;
|
||||||
@ -148,7 +148,7 @@ main(int argc, char **argv) {
|
|||||||
|
|
||||||
case 'p':
|
case 'p':
|
||||||
auto [y, x] = swarm.best();
|
auto [y, x] = swarm.best();
|
||||||
printf("Current best: f(%.3f, %.3f) = %.3f", x.x, x.y, y);
|
printf("Current best: f(%.10f, %.10f) = %.10f", x.x, x.y, y);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Loading…
Reference in New Issue
Block a user