Compare commits
5 Commits
6f620644bf
...
00858cf74f
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
00858cf74f | ||
|
|
3e065e50a9 | ||
|
|
ab0f152742 | ||
|
|
014821ceb5 | ||
|
|
1bd8a9f7b2 |
8
build.sh
8
build.sh
@@ -2,9 +2,15 @@
|
||||
|
||||
set -xe
|
||||
|
||||
OUT="cw_tree.out"
|
||||
GFLAGS="-Wall -Wextra -Wswitch-enum -std=c++17"
|
||||
DFLAGS="-ggdb -fsanitize=address -fsanitize=undefined"
|
||||
CFLAGS="$GFLAGS $DFLAGS"
|
||||
LIBS="-lraylib -lm"
|
||||
|
||||
c++ $CFLAGS -o cw_tree.out src/node.cpp src/state.cpp src/worker.cpp src/numerics.cpp src/main.cpp $LIBS
|
||||
c++ $CFLAGS -o $OUT src/node.cpp src/state.cpp src/worker.cpp src/numerics.cpp src/main.cpp $LIBS
|
||||
|
||||
if [ "$1" = "run" ]
|
||||
then
|
||||
./$OUT
|
||||
fi
|
||||
|
||||
127
src/main.cpp
127
src/main.cpp
@@ -5,18 +5,22 @@
|
||||
* Commentary: 2024-07-25
|
||||
*/
|
||||
|
||||
#include "./numerics.hpp"
|
||||
|
||||
#include <chrono>
|
||||
#include <cmath>
|
||||
#include <cstdio>
|
||||
#include <iostream>
|
||||
#include <sstream>
|
||||
#include <stack>
|
||||
#include <thread>
|
||||
#include <tuple>
|
||||
|
||||
#include <raylib.h>
|
||||
|
||||
#include "base.hpp"
|
||||
#include "node.hpp"
|
||||
#include "numerics.hpp"
|
||||
#include "worker.hpp"
|
||||
|
||||
#define WIDTH 1024
|
||||
#define HEIGHT 1024
|
||||
#define FONT_SIZE 20
|
||||
@@ -24,6 +28,9 @@
|
||||
#define LINE_TOP (7 * HEIGHT / 16)
|
||||
#define LINE_BOTTOM (9 * HEIGHT / 16)
|
||||
|
||||
using cw::state::DrawState;
|
||||
using cw::state::State;
|
||||
|
||||
std::pair<std::string, int> fraction_to_string(Fraction f)
|
||||
{
|
||||
std::string s{to_string(f)};
|
||||
@@ -40,6 +47,121 @@ void draw_fraction(Fraction f, word_t x, word_t y)
|
||||
DrawText(s.c_str(), x - width / 2, y - FONT_SIZE, FONT_SIZE, WHITE);
|
||||
}
|
||||
|
||||
constexpr u64 clamp_to_width(const DrawState &ds, f64 val)
|
||||
{
|
||||
return (WIDTH / (ds.bounds.upper_val - ds.bounds.lower_val)) *
|
||||
(val - ds.bounds.lower_val);
|
||||
}
|
||||
|
||||
void draw_tree(const DrawState &ds)
|
||||
{
|
||||
// Number line
|
||||
DrawLine(0, HEIGHT / 2, WIDTH, HEIGHT / 2, WHITE);
|
||||
|
||||
// Bounds
|
||||
u64 lower_x = clamp_to_width(ds, ds.bounds.leftmost.value.norm);
|
||||
u64 upper_x = clamp_to_width(ds, ds.bounds.rightmost.value.norm);
|
||||
DrawLine(lower_x, LINE_TOP, lower_x, LINE_BOTTOM, WHITE);
|
||||
DrawLine(upper_x, LINE_TOP, upper_x, LINE_BOTTOM, WHITE);
|
||||
|
||||
std::stack<cw::node::Node> stack;
|
||||
stack.push(ds.state.allocator.get_val(0));
|
||||
while (!stack.empty())
|
||||
{
|
||||
auto n = stack.top();
|
||||
stack.pop();
|
||||
u64 x = clamp_to_width(ds, n.value.norm);
|
||||
DrawLine(x, LINE_TOP, x, LINE_BOTTOM, RED);
|
||||
if (n.left >= 0)
|
||||
stack.push(ds.state.allocator.get_val(n.left));
|
||||
if (n.right >= 0)
|
||||
stack.push(ds.state.allocator.get_val(n.right));
|
||||
}
|
||||
}
|
||||
|
||||
using Clock = std::chrono::steady_clock;
|
||||
using Ms = std::chrono::milliseconds;
|
||||
|
||||
int main(void)
|
||||
{
|
||||
// Init general state
|
||||
cw::state::State state;
|
||||
cw::state::DrawState draw_state{state};
|
||||
|
||||
// Init timer
|
||||
auto time_current = Clock::now();
|
||||
auto time_previous = time_current;
|
||||
constexpr auto time_delta = 1;
|
||||
|
||||
// Init meta text (counter, iterations, etc)
|
||||
u64 count = 1, prev_count = 0;
|
||||
std::stringstream format_stream;
|
||||
std::string format_str;
|
||||
u64 format_str_width = 0;
|
||||
|
||||
// Setup our first node (1/1)
|
||||
state.allocator.alloc(cw::node::Node{{1, 1}, -1, -1});
|
||||
state.queue.push(0);
|
||||
|
||||
// Init thread
|
||||
std::thread threads[] = {
|
||||
std::thread(cw::worker::worker, std::ref(state)),
|
||||
std::thread(cw::worker::worker, std::ref(state)),
|
||||
std::thread(cw::worker::worker, std::ref(state)),
|
||||
std::thread(cw::worker::worker, std::ref(state)),
|
||||
};
|
||||
|
||||
// Setup raylib window
|
||||
InitWindow(WIDTH, HEIGHT, "Calkin-Wilf tree");
|
||||
SetTargetFPS(60);
|
||||
|
||||
while (!WindowShouldClose())
|
||||
{
|
||||
// Update
|
||||
time_current = Clock::now();
|
||||
count = state.allocator.vec.size();
|
||||
if (!state.pause_work &&
|
||||
std::chrono::duration_cast<Ms>(time_current - time_previous).count() >=
|
||||
time_delta)
|
||||
{
|
||||
time_previous = time_current;
|
||||
}
|
||||
|
||||
if (prev_count != count)
|
||||
{
|
||||
draw_state.compute_bounds();
|
||||
prev_count = count;
|
||||
format_stream << "Count=" << count << "\n\n"
|
||||
<< "Iterations=" << (count - 1) / 2 << "\n\n"
|
||||
<< "Lower=" << to_string(draw_state.bounds.leftmost.value)
|
||||
<< "\n\n"
|
||||
<< "Upper=" << to_string(draw_state.bounds.rightmost.value);
|
||||
format_str = format_stream.str();
|
||||
format_stream.str("");
|
||||
format_str_width = MeasureText(format_str.c_str(), FONT_SIZE * 2);
|
||||
}
|
||||
|
||||
// Draw
|
||||
|
||||
ClearBackground(BLACK);
|
||||
BeginDrawing();
|
||||
draw_tree(draw_state);
|
||||
DrawText(format_str.c_str(), WIDTH / 2 - format_str_width / 2, HEIGHT / 8,
|
||||
FONT_SIZE, WHITE);
|
||||
EndDrawing();
|
||||
}
|
||||
|
||||
CloseWindow();
|
||||
|
||||
state.stop_work = true;
|
||||
for (auto &thread : threads)
|
||||
{
|
||||
thread.join();
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
#if 0
|
||||
struct State
|
||||
{
|
||||
NodeAllocator allocator;
|
||||
@@ -209,6 +331,7 @@ int main(void)
|
||||
CloseWindow();
|
||||
return 0;
|
||||
}
|
||||
#endif
|
||||
|
||||
/* Copyright (C) 2024, 2025 Aryadev Chavali
|
||||
|
||||
|
||||
@@ -21,6 +21,7 @@ namespace cw::state
|
||||
cw::node::NodeAllocator allocator;
|
||||
std::queue<u64> queue;
|
||||
|
||||
bool pause_work, stop_work;
|
||||
std::mutex mutex_queue;
|
||||
std::mutex mutex_allocator;
|
||||
|
||||
|
||||
@@ -5,9 +5,12 @@
|
||||
* Commentary:
|
||||
*/
|
||||
|
||||
#include "worker.hpp"
|
||||
#include <chrono>
|
||||
#include <thread>
|
||||
#include <tuple>
|
||||
|
||||
#include "worker.hpp"
|
||||
|
||||
namespace cw::worker
|
||||
{
|
||||
using cw::node::Fraction;
|
||||
@@ -54,6 +57,20 @@ namespace cw::worker
|
||||
state.queue.push(right_child);
|
||||
state.mutex_queue.unlock();
|
||||
}
|
||||
|
||||
void worker(State &state)
|
||||
{
|
||||
while (!state.stop_work)
|
||||
{
|
||||
std::this_thread::sleep_for(THREAD_GENERAL_DELAY);
|
||||
while (state.pause_work)
|
||||
{
|
||||
std::this_thread::sleep_for(THREAD_PAUSE_DELAY);
|
||||
}
|
||||
|
||||
do_iteration(state);
|
||||
}
|
||||
}
|
||||
} // namespace cw::worker
|
||||
|
||||
/* Copyright (C) 2025 Aryadev Chavali
|
||||
|
||||
@@ -8,6 +8,7 @@
|
||||
#ifndef WORKER_HPP
|
||||
#define WORKER_HPP
|
||||
|
||||
#include <chrono>
|
||||
#include <tuple>
|
||||
|
||||
#include "state.hpp"
|
||||
@@ -16,6 +17,8 @@ namespace cw::worker
|
||||
{
|
||||
using cw::node::NodeAllocator;
|
||||
using cw::state::State;
|
||||
constexpr auto THREAD_PAUSE_DELAY = std::chrono::milliseconds(1000);
|
||||
constexpr auto THREAD_GENERAL_DELAY = std::chrono::milliseconds(1);
|
||||
|
||||
// Given `index`, return the indices of its children in the tree. If not
|
||||
// present already, generate them using the allocator.
|
||||
@@ -28,6 +31,10 @@ namespace cw::worker
|
||||
// Each step will block on the relevant mutex for the resource (1,3 will block
|
||||
// on the queue mutex, 2 will block on the allocator mutex) so is thread safe.
|
||||
void do_iteration(State &state);
|
||||
|
||||
// Steady living thread worker which performs iterations. If state.pause_work
|
||||
// is true, thread will pause until otherwise.
|
||||
void worker(State &state);
|
||||
} // namespace cw::worker
|
||||
|
||||
#endif
|
||||
|
||||
Reference in New Issue
Block a user