Compare commits

..

5 Commits

@ -1,23 +1,22 @@
# Pfad zum Makefile selbst bestimmen
MAKEFILE_DIR := $(dir $(abspath $(lastword $(MAKEFILE_LIST))))
CXX := clang++
CXXFLAGS := -Wall -Wextra -Wpedantic -O2 -std=c++23
CXXFLAGS := -std=c++23 -O2 -Wall -Wextra -Werror -fopenmp -Ilib
SRC_DIR := src
LIB_DIR := lib
OUT_DIR := out
SRC_DIR := $(MAKEFILE_DIR)/src
OUT_DIR := $(MAKEFILE_DIR)/out
PROJECTS := $(wildcard $(SRC_DIR)/*)
BINS := $(patsubst $(SRC_DIR)/%, $(OUT_DIR)/%, $(PROJECTS))
LIB_SOURCES := $(wildcard $(LIB_DIR)/*.cpp)
SOURCES := $(wildcard $(SRC_DIR)/*.cpp)
TARGETS := $(patsubst $(SRC_DIR)/%.cpp,$(OUT_DIR)/%,$(SOURCES))
all: $(BINS)
all: $(OUT_DIR) $(TARGETS)
$(OUT_DIR)/%: $(SRC_DIR)/% $(LIB_SOURCES) | $(OUT_DIR)
$(CXX) $(CXXFLAGS) $</*.cpp $(LIB_SOURCES) -o $@
$(OUT_DIR):
mkdir -p $(OUT_DIR)
$(OUT_DIR)/%: $(SRC_DIR)/%.cpp
$(CXX) $(CXXFLAGS) $< -o $@
clean:
rm -rf $(OUT_DIR)

@ -1,4 +1,22 @@
# Algorithmisches Beweisen - LAB
Dateien in diesem Repository:
- `Makefile`: Hiermit lässt sich jedes Programm in src kompilieren.
- `src/hello_world.cpp`: Hello World test Programm.
<a href="https://gitmoji.dev">
<img src="https://img.shields.io/badge/gitmoji-%20😜%20😍-FFDD67.svg?style=flat-square"
alt="Gitmoji">
</a>
Files and projects of this repository:
- `Makefile`: Compiles every project for you.
# Dependencies:
- clang++ using std=c++23
- openmp
## Hello
Hello World! test program
Files:
- `src/hello/hello_world.cpp`
## random kcnf
Randomly generates a kcnf formula.
Files:
- `src/random_kcnf/random_kcnf.cpp`
- `lib/kcnf.cpp`
- `lib/kcnf.hpp`

@ -0,0 +1,148 @@
#include "kcnf.hpp"
#include <algorithm>
#include <filesystem>
#include <fstream>
#include <iostream>
#include <random>
#include <stdexcept>
#include <vector>
#ifdef _OPENMP
#include <omp.h>
#endif
namespace fs = std::filesystem;
const fs::path CNF_DIR = "./CNF";
long binom(long n, long k) {
return (k > n) ? 0 :
(k == 0 || k == n) ? 1 :
(k == 1 || k == n - 1) ? n :
(k + k < n) ?
(binom(n - 1, k - 1) * n) / k :
(binom(n - 1, k) * n) / (n - k);
}
// get the (n choose k) possible variable choices at index idx
// example:
std::vector<int> unrank_combination(long n, long k, long long idx) {
std::vector<int> comb;
comb.reserve(k);
long start = 1;
for (long i = 0; i < k; ++i) {
for (long v = start; v <= n; ++v) {
long long count = binom(n - v, k - i - 1);
if (idx < count) {
comb.push_back((int)v);
start = v + 1;
break;
} else {
idx -= count;
}
}
}
return comb;
}
// sample c indices in [0,total] for our c = # of clauses
// this is the heart of the program as we are flattening the problem with our sampled indices and the unrank function!
std::vector<long long> sample_indices(long long total, long c) {
std::vector<long long> idx;
idx.reserve(c);
std::random_device rd;
std::mt19937 gen(rd());
std::uniform_int_distribution<long long> dist(0, total - 1);
for (long i = 0; i < c; ++i) {
idx.push_back(dist(gen));
}
return idx;
}
// decode one clause from global index (think of it like a hash function for better understanding!)
// idx = combo_id * 2^k + mask
Clause decode_clause(long n, long k, long long idx) {
long long combo_id = idx >> k;
int mask = idx & ((1 << k) - 1);
std::vector<int> comb = unrank_combination(n, k, combo_id);
Clause cl;
cl.reserve(k);
for (int i = 0; i < k; ++i) {
int lit = comb[i];
cl.push_back((mask & (1 << i)) ? lit : -lit);
}
return cl;
}
// parallel iteration to build clauses from indices
std::vector<Clause> build_clauses_parallel(
long n,
long k,
const std::vector<long long>& indices) {
std::vector<Clause> result(indices.size());
#pragma omp parallel for schedule(dynamic)
for (long i = 0; i < (long)indices.size(); ++i) {
result[i] = decode_clause(n, k, indices[i]);
}
return result;
}
KCNF KCNF::generate_random(long n, long c, long k) {
KCNF f;
f.n = n;
f.k = k;
// test for logical limits
long long total = binom(n,k) * (1LL << k);
if (c > total) {
throw std::runtime_error("Too many clauses requested.");
}
// test for hardware limits
long long estimated_bytes =
c * (sizeof(Clause) + k * sizeof(int));
if (estimated_bytes > 500 * 1024 * 1024) { // 500MB
throw std::runtime_error("Estimated memory too large");
}
auto indices = sample_indices(total, c);
f.clauses = build_clauses_parallel(n, k, indices);
return f;
}
bool KCNF::write_dimacs(const std::string& filename) const {
fs::create_directories(CNF_DIR);
fs::path path = CNF_DIR / filename;
path = path.lexically_normal();
std::ofstream out(path);
if (!out) {
std::cerr << "Error: Could not open file " << path << "\n";
return false;
}
out << "p cnf " << n << " " << clauses.size() << "\n";
for (const auto& cl : clauses) {
for (int lit : cl) {
out << lit << " ";
}
out << "0\n";
}
return true;
}

@ -0,0 +1,17 @@
#pragma once
#include <string>
#include <vector>
using Clause = std::vector<int>; // makes it nicer to read
class KCNF {
public:
long n = 0;
long k = 0;
std::vector<Clause> clauses;
static KCNF generate_random(long n, long c, long k);
bool write_dimacs(const std::string& filename) const;
};

@ -0,0 +1,6 @@
#include <iostream>
int main() {
std::cout << "Hello World!" << std::endl;
return 0;
}

@ -1,8 +0,0 @@
#include <iostream>
using namespace std;
int main(int argc, char *argv[]) {
cout << "Hello World!" << endl;
return 0;
}

@ -0,0 +1,29 @@
#include "kcnf.hpp"
#include <cstdlib>
#include <iostream>
int main(int argc, char* argv[]) {
if (argc != 5) {
std::cerr << "Usage: " << argv[0] << " n c k output.cnf\n";
return 1;
}
long n = strtol(argv[1], NULL, 10);
long c = strtol(argv[2], NULL, 10);
long k = strtol(argv[3], NULL, 10);
try {
KCNF f = KCNF::generate_random(n, c, k);
if (!f.write_dimacs(argv[4])) {
return 1;
}
} catch (const std::exception& e) {
std::cerr << e.what() << "\n";
return 1;
}
return 0;
}
Loading…
Cancel
Save