An open API service indexing awesome lists of open source software.

https://github.com/kgorze/dna-assembly-problem-solver

Advanced DNA sequence reconstruction tool using genetic algorithms and metaheuristics. Implements Short-Base Hybridization (SBH) problem solver with adaptive crossover operators and comprehensive error handling.
https://github.com/kgorze/dna-assembly-problem-solver

bioinformatics cpp dna-assembly genetic-algorithms metaheuristics optimization sbhs sequence-reconstruction

Last synced: 3 months ago
JSON representation

Advanced DNA sequence reconstruction tool using genetic algorithms and metaheuristics. Implements Short-Base Hybridization (SBH) problem solver with adaptive crossover operators and comprehensive error handling.

Awesome Lists containing this project

README

          

# Optymalizacja Kombinatoryczna - DNA Assembly Problem Solver

## Spis treści
- [Wprowadzenie](#wprowadzenie)
- [Struktura projektu](#struktura-projektu)
- [Algorytmy](#algorytmy)
- [Komponenty](#komponenty)
- [Konfiguracja](#konfiguracja)
- [Interfejsy](#interfejsy)
- [Szczegółowa dokumentacja](#szczegółowa-dokumentacja)

## Wprowadzenie
Program implementuje rozwiązanie problemu składania DNA (DNA Assembly Problem) przy użyciu algorytmów metaheurystycznych, w szczególności algorytmu genetycznego. Program zawiera zaawansowane mechanizmy optymalizacji i adaptacji parametrów. Zadanie na labolatoria do dr. Radoma - Bioinformatyka 3 semestr, optymalizacja kombinatoryczna.

## Struktura projektu
```
.
├── include/ # Pliki nagłówkowe
│ ├── metaheuristics/ # Implementacje metaheurystyk
│ ├── interfaces/ # Interfejsy
│ ├── dna/ # Obsługa instancji DNA
│ ├── utils/ # Narzędzia pomocnicze
│ └── configuration/ # Konfiguracja
├── src/ # Pliki źródłowe
└── test/ # Testy jednostkowe
```

## Algorytmy

### Algorytm Genetyczny (GeneticAlgorithm)
Główna klasa implementująca algorytm genetyczny dla problemu DNA Assembly.

#### Główne komponenty:
- **Inicjalizacja**: `initializePopulation(int popSize, const DNAInstance& instance)`
- Tworzy początkową populację rozwiązań
- Parametry:
- `popSize`: Rozmiar populacji
- `instance`: Instancja problemu DNA

- **Ewaluacja**: `evaluatePopulation()`
- Ocenia jakość każdego osobnika w populacji
- Wykorzystuje funkcję przystosowania opartą na grafie

- **Selekcja**: Implementowana przez interfejs `ISelection`
- Wybiera osobniki do reprodukcji
- Dostępne strategie:
- Selekcja turniejowa
- Selekcja rankingowa
- Selekcja ruletki

- **Krzyżowanie**: Implementowane przez interfejs `ICrossover`
- Tworzy nowe rozwiązania przez kombinację istniejących
- Dostępne operatory:
- Krzyżowanie jednopunktowe
- Krzyżowanie dwupunktowe
- Krzyżowanie adaptacyjne (AdaptiveCrossover)

- **Mutacja**: Implementowana przez interfejs `IMutation`
- Wprowadza losowe zmiany w rozwiązaniach
- Dostępne operatory:
- Mutacja przez zamianę
- Mutacja przez inwersję
- Mutacja przez przesunięcie

### Reprezentacja rozwiązań
Implementowana w klasie `PermutationRepresentation`:
- Reprezentacja permutacyjna fragmentów DNA
- Operacje na permutacjach
- Walidacja poprawności rozwiązań

## Komponenty

### DNAInstance
Klasa reprezentująca instancję problemu:
```cpp
class DNAInstance {
std::vector fragments; // Fragmenty DNA
int k; // Parametr k dla odległości Levenshteina
std::string originalSequence; // Oryginalna sekwencja (jeśli znana)
};
```

### Individual
Reprezentacja pojedynczego osobnika w populacji:
```cpp
class Individual {
std::vector genes; // Reprezentacja rozwiązania
double fitness; // Wartość funkcji przystosowania
std::string dna; // Złożona sekwencja DNA
};
```

### FitnessImpl
Implementacje funkcji przystosowania:
- `OptimizedGraphBasedFitness`: Ocena bazująca na grafie
- `LevenshteinBasedFitness`: Ocena bazująca na odległości Levenshteina

## Konfiguracja

### GAConfig
Konfiguracja algorytmu genetycznego:
```cpp
struct GAConfig {
int populationSize; // Rozmiar populacji
int maxGenerations; // Maksymalna liczba generacji
double crossoverProbability; // Prawdopodobieństwo krzyżowania
double mutationProbability; // Prawdopodobieństwo mutacji
SelectionType selectionType; // Typ selekcji
CrossoverType crossoverType; // Typ krzyżowania
MutationType mutationType; // Typ mutacji
};
```

## Interfejsy

### Podstawowe interfejsy algorytmu

#### IAlgorithm
Bazowy interfejs dla wszystkich algorytmów:
```cpp
class IAlgorithm {
virtual std::string run(const DNAInstance& instance) = 0;
virtual ~IAlgorithm() = default;
};
```

#### IRepresentation
Interfejs reprezentacji rozwiązania:
```cpp
class IRepresentation {
virtual std::vector decode(const std::string& dna) = 0;
virtual std::string encode(const std::vector& genes) = 0;
virtual bool isValid(const std::vector& genes) = 0;
};
```

### Interfejsy operatorów genetycznych

#### ISelection
Interfejs selekcji osobników:
```cpp
class ISelection {
virtual std::vector> select(
const std::vector>& population,
int count) = 0;

virtual SelectionType getType() const = 0;
};
```

#### ICrossover
Interfejs operatora krzyżowania:
```cpp
class ICrossover {
virtual std::pair, std::shared_ptr>
crossover(const std::shared_ptr& parent1,
const std::shared_ptr& parent2) = 0;

virtual CrossoverType getType() const = 0;
};
```

#### IMutation
Interfejs operatora mutacji:
```cpp
class IMutation {
virtual void mutate(std::shared_ptr individual) = 0;
virtual MutationType getType() const = 0;
virtual void setMutationProbability(double probability) = 0;
};
```

#### IReplacement
Interfejs strategii wymiany pokoleń:
```cpp
class IReplacement {
virtual std::vector> replace(
const std::vector>& oldPopulation,
const std::vector>& offspring) = 0;

virtual ReplacementType getType() const = 0;
};
```

### Interfejsy oceny i zatrzymania

#### IFitness
Interfejs funkcji przystosowania:
```cpp
class IFitness {
virtual double calculate(const std::vector& genes,
const DNAInstance& instance) = 0;

virtual FitnessType getType() const = 0;
};
```

#### IStopping
Interfejs kryterium zatrzymania:
```cpp
class IStopping {
virtual bool shouldStop(int generation, double bestFitness) = 0;
virtual void reset() = 0;
virtual StoppingType getType() const = 0;
};
```

### Interfejsy optymalizacyjne

#### IPopulationCache
Interfejs cache'owania populacji:
```cpp
class IPopulationCache {
virtual void addToCache(const std::vector& genes, double fitness) = 0;
virtual bool isInCache(const std::vector& genes) const = 0;
virtual double getCachedFitness(const std::vector& genes) const = 0;
virtual void clear() = 0;
virtual size_t size() const = 0;
};
```

#### IBenchmark
Interfejs dla benchmarków:
```cpp
class IBenchmark {
virtual void run() = 0;
virtual void generateReport(const std::string& outputFile) = 0;
virtual BenchmarkType getType() const = 0;
};
```

## Implementacje interfejsów

### Operatory selekcji
- `TournamentSelection`: Selekcja turniejowa
- `RouletteSelection`: Selekcja metodą ruletki
- `RankSelection`: Selekcja rankingowa

### Operatory krzyżowania
- `SinglePointCrossover`: Krzyżowanie jednopunktowe
- `TwoPointCrossover`: Krzyżowanie dwupunktowe
- `UniformCrossover`: Krzyżowanie równomierne
- `AdaptiveCrossover`: Krzyżowanie adaptacyjne

### Operatory mutacji
- `SwapMutation`: Mutacja przez zamianę
- `InversionMutation`: Mutacja przez inwersję
- `ScrambleMutation`: Mutacja przez przemieszanie

### Strategie wymiany pokoleń
- `GenerationalReplacement`: Wymiana generacyjna
- `ElitistReplacement`: Wymiana elitarna
- `SteadyStateReplacement`: Wymiana w stanie ustalonym

### Funkcje przystosowania
- `GraphBasedFitness`: Ocena bazująca na grafie
- `LevenshteinFitness`: Ocena bazująca na odległości Levenshteina
- `HybridFitness`: Ocena hybrydowa

### Kryteria zatrzymania
- `GenerationLimit`: Limit generacji
- `FitnessThreshold`: Próg funkcji przystosowania
- `TimeLimit`: Limit czasowy
- `StagnationDetection`: Wykrywanie stagnacji

## Szczegółowa dokumentacja

### Klasa GeneticAlgorithm

#### Metody publiczne:
- `GeneticAlgorithm(std::unique_ptr representation, GAConfig& config, bool debugMode = false)`
- Konstruktor inicjalizujący algorytm genetyczny
- Parametry:
- `representation`: Implementacja reprezentacji rozwiązań
- `config`: Konfiguracja algorytmu
- `debugMode`: Tryb debugowania

- `std::string run(const DNAInstance& instance)`
- Uruchamia algorytm genetyczny
- Zwraca: Najlepsze znalezione rozwiązanie (sekwencję DNA)

- `double getBestFitness()`
- Zwraca wartość przystosowania najlepszego rozwiązania

#### Metody prywatne:
- `void initializePopulation(int popSize, const DNAInstance& instance)`
- Inicjalizuje populację początkową

- `void evaluatePopulation()`
- Ocenia wszystkie osobniki w populacji

- `bool updateGlobalBest()`
- Aktualizuje najlepsze znalezione rozwiązanie

- `void logGenerationStats()`
- Zapisuje statystyki generacji

### Klasa AdaptiveCrossover

Implementuje adaptacyjny operator krzyżowania:
```cpp
class AdaptiveCrossover : public ICrossover {
void updateCrossoverRates(); // Aktualizacja współczynników
void adaptParameters(); // Adaptacja parametrów
double calculateSuccess(); // Obliczenie skuteczności
};
```

### Klasa PathAnalyzer

Analizuje ścieżki w grafie reprezentującym problem:
```cpp
class PathAnalyzer {
std::vector findBestPath();
double evaluatePath(const std::vector& path);
void preprocessEdges();
};
```

## Główne moduły programu

### Main (main.cpp)
Główny plik programu zawierający logikę sterującą i obsługę trybów działania:

#### Tryby działania programu:
- `debug` - Tryb debugowania z domyślnymi ustawieniami
- `generate_instance` - Generowanie instancji testowych
- `test_instance` - Rozwiązywanie problemu rekonstrukcji DNA z pliku wejściowego
- `tuning` - Strojenie parametrów algorytmu
- `tuning_hybrid` - Zaawansowane strojenie hybrydowe (1+lambda) ES + Racing

#### Główne funkcje:
```cpp
void printUsage()
// Wyświetla instrukcję użycia programu i dostępne opcje

DNAInstance generateInstance(int n, int k, int deltaK, int lNeg, int lPoz)
// Generuje instancję problemu DNA o zadanych parametrach
// Parametry:
// n - długość DNA (300-700)
// k - długość oligonukleotydów (7-10)
// deltaK - zakres Delta K (0-2)
// lNeg - błędy negatywne (0 lub >=10)
// lPoz - błędy pozytywne (0 lub >=10)

void runGeneticAlgorithm(const DNAInstance& instance,
const std::string& outputFile,
int processId,
const std::string& configFile,
bool debugMode)
// Uruchamia algorytm genetyczny dla danej instancji
// Parametry:
// instance - instancja problemu DNA
// outputFile - plik wyjściowy dla wyników
// processId - identyfikator procesu
// configFile - plik konfiguracyjny
// debugMode - tryb debugowania

double runGeneticAlgorithmWithFitness(...)
// Wersja zwracająca wartość funkcji przystosowania

void runParameterTuningWithRacing(const DNAInstance& instance)
// Uruchamia strojenie parametrów z wykorzystaniem metody Racing

TuningResult runParameterTuning(...)
// Przeprowadza strojenie parametrów i zwraca wyniki

### Generator DNA (generator/)

#### DNAGenerator
Klasa odpowiedzialna za generowanie instancji problemu:
```cpp
class DNAGenerator {
std::string generateRandomDNA(int length);
std::vector generateFragments(const std::string& dna, int k);
void introduceErrors(std::vector& fragments, int lNeg, int lPoz);
};
```

### Moduł strojenia (tuning/)

#### ParameterTuningManager
Zarządza procesem strojenia parametrów:
```cpp
class ParameterTuningManager {
void tuneParameters();
void evaluateConfiguration(const ParameterSet& params);
void saveResults(const std::string& outputFile);
};
```

#### Racing
Implementacja metody Racing do selekcji konfiguracji:
```cpp
class Racing {
void runRace(std::vector& configs);
void eliminateConfigurations();
Configuration getBestConfiguration();
};
```

#### ParameterParser
Parsowanie i walidacja parametrów strojenia:
```cpp
class ParameterParser {
// Metody parsowania
ParameterSet parseConfigFile(const std::string& filename);
void validateParameters(const ParameterSet& params);

// Obsługa różnych typów parametrów
int parseIntParameter(const std::string& value, const std::string& name);
double parseDoubleParameter(const std::string& value, const std::string& name);
std::string parseEnumParameter(const std::string& value, const std::vector& allowedValues);
};
```

#### TuningStructures
Struktury danych używane w procesie strojenia:
```cpp
struct ParameterSet {
std::map> parameters;
double fitness;
int evaluations;
};

struct Configuration {
ParameterSet params;
std::vector results;
double mean;
double stdDev;
};

struct TuningResult {
ParameterSet bestParams;
double bestFitness;
int generations;
double tuningTime;
};
```

#### MetaEA
Metaewolucyjny algorytm do strojenia parametrów:
```cpp
class MetaEA {
// Główne metody
void evolveParameters();
void evaluatePopulation();
void selectBestConfigurations();

// Operatory
ParameterSet crossover(const ParameterSet& parent1, const ParameterSet& parent2);
void mutate(ParameterSet& params);

// Parametry meta-algorytmu
const int META_POPULATION_SIZE = 20;
const int META_GENERATIONS = 50;
const double META_MUTATION_RATE = 0.1;
};
```

### Moduł benchmarków (benchmark/)

#### CrossoverBenchmark
Testy wydajności operatorów krzyżowania:
```cpp
class CrossoverBenchmark {
void runBenchmark();
void compareCrossoverOperators();
void generateStatistics();
};
```

#### AdaptiveCrossoverBenchmark
Testy wydajności adaptacyjnego operatora krzyżowania:
```cpp
class AdaptiveCrossoverBenchmark {
void testAdaptation();
void measureConvergence();
};
```

### Moduł błędów DNA (dna/)

#### ErrorIntroduction
Klasy do wprowadzania błędów w sekwencjach DNA:
```cpp
class NegativeErrorIntroducer {
void introduceErrors(std::vector& fragments, int count);
};

class PositiveErrorIntroducer {
void introduceErrors(std::vector& fragments, int count);
};
```

### Narzędzia pomocnicze (utils/)

#### Random
Generator liczb pseudolosowych:
```cpp
class Random {
// Generowanie liczb losowych
int getRandomInt(int min, int max);
double getRandomDouble(double min, double max);
bool getRandomBool(double probability);

// Operacje na kolekcjach
template
void shuffle(std::vector& vec);

template
T getRandomElement(const std::vector& vec);
};
```

#### Timer
Pomiar czasu wykonania:
```cpp
class Timer {
void start();
void stop();
double getElapsedTime() const;
void reset();

static std::string formatTime(double seconds);
};
```

#### Logging
System logowania:
```cpp
class Logger {
// Poziomy logowania
enum class Level {
DEBUG,
INFO,
WARNING,
ERROR
};

// Metody logowania
void log(Level level, const std::string& message);
void setLogLevel(Level level);
void setLogFile(const std::string& filename);

// Konfiguracja
void enableConsoleOutput(bool enable);
void enableFileOutput(bool enable);
};
```

#### PerformanceProfillingFramework
Narzędzie do profilowania wydajności:
```cpp
class Profiler {
// Pomiar wydajności
void startSection(const std::string& name);
void endSection(const std::string& name);

// Raportowanie
void generateReport();
void saveReport(const std::string& filename);

// Statystyki
struct SectionStats {
double totalTime;
int calls;
double avgTime;
double minTime;
double maxTime;
};
};
```

#### ZobristHasher
Implementacja hashowania Zobrista dla efektywnego cache'owania:
```cpp
class ZobristHasher {
// Inicjalizacja
void initialize(size_t size);

// Hashowanie
size_t hash(const std::vector& genes);
void updateHash(size_t& currentHash, int pos, int oldVal, int newVal);

// Parametry
static constexpr size_t HASH_SIZE = 64;
};
```

#### UtilityFunctions
Zbiór funkcji pomocniczych:
```cpp
namespace Utils {
// Operacje na plikach
std::string readFile(const std::string& filename);
void writeFile(const std::string& filename, const std::string& content);

// Operacje na stringach
std::vector split(const std::string& str, char delimiter);
std::string trim(const std::string& str);

// Konwersje
template
std::string toString(const T& value);

template
T fromString(const std::string& str);

// Operacje matematyczne
double calculateMean(const std::vector& values);
double calculateStdDev(const std::vector& values);

// Operacje na DNA
int calculateLevenshteinDistance(const std::string& s1, const std::string& s2);
double calculateSequenceSimilarity(const std::string& s1, const std::string& s2);
}
```

## Format plików wejściowych/wyjściowych

### Plik konfiguracyjny (config.txt)
```
population_size=100
max_generations=1000
crossover_probability=0.8
mutation_probability=0.1
selection_type=tournament
crossover_type=adaptive
mutation_type=swap
tournament_size=3
elite_size=2
```

### Plik instancji (instance.txt)
```
300 8 # N=300 (długość DNA), K=8 (długość oligonukleotydów)
ACGTACGT # Fragment 1
CGTACGTA # Fragment 2
...
fragment_n
```
gdzie:
- n: liczba fragmentów
- k: parametr k dla odległości Levenshteina
- fragment_i: i-ty fragment DNA

### Format pliku konfiguracji
```json
{
"population_size": 100,
"max_generations": 1000,
"crossover_probability": 0.8,
"mutation_probability": 0.1,
"selection_type": "tournament",
"crossover_type": "adaptive",
"mutation_type": "swap"
}
```

## Użycie programu

### Kompilacja
```bash
mkdir build
cd build
cmake ..
make
```

### Uruchomienie
```bash
./dna_assembly
```

### Format pliku instancji
```
n k
fragment_1
fragment_2
...
fragment_n
```

### Format pliku konfiguracji
```json
{
"population_size": 100,
"max_generations": 1000,
"crossover_probability": 0.8,
"mutation_probability": 0.1,
"selection_type": "tournament",
"crossover_type": "adaptive",
"mutation_type": "swap"
}
```

## Wymagania systemowe
- C++17 lub nowszy
- CMake 3.10 lub nowszy
- Boost (dla testów jednostkowych)

### Naiwny algorytm (naive/)

#### NaiveReconstruction
Implementacja naiwnego podejścia do problemu rekonstrukcji DNA:
```cpp
class NaiveReconstruction {
// Główne metody
std::string reconstructDNA(const std::vector& fragments);

// Metody pomocnicze
double calculateOverlap(const std::string& s1, const std::string& s2);
std::pair findBestMatch(const std::vector& fragments);
void mergePair(std::vector& fragments, int i, int j);
};
```

Algorytm działa poprzez:
1. Znajdowanie par fragmentów o największym pokryciu
2. Łączenie znalezionych par
3. Powtarzanie procesu aż do uzyskania jednej sekwencji

### Szczegóły modułu strojenia (tuning/)

#### ParameterParser
Parsowanie i walidacja parametrów strojenia:
```cpp
class ParameterParser {
// Metody parsowania
ParameterSet parseConfigFile(const std::string& filename);
void validateParameters(const ParameterSet& params);

// Obsługa różnych typów parametrów
int parseIntParameter(const std::string& value, const std::string& name);
double parseDoubleParameter(const std::string& value, const std::string& name);
std::string parseEnumParameter(const std::string& value, const std::vector& allowedValues);
};
```

#### TuningStructures
Struktury danych używane w procesie strojenia:
```cpp
struct ParameterSet {
std::map> parameters;
double fitness;
int evaluations;
};

struct Configuration {
ParameterSet params;
std::vector results;
double mean;
double stdDev;
};

struct TuningResult {
ParameterSet bestParams;
double bestFitness;
int generations;
double tuningTime;
};
```

#### MetaEA
Metaewolucyjny algorytm do strojenia parametrów:
```cpp
class MetaEA {
// Główne metody
void evolveParameters();
void evaluatePopulation();
void selectBestConfigurations();

// Operatory
ParameterSet crossover(const ParameterSet& parent1, const ParameterSet& parent2);
void mutate(ParameterSet& params);

// Parametry meta-algorytmu
const int META_POPULATION_SIZE = 20;
const int META_GENERATIONS = 50;
const double META_MUTATION_RATE = 0.1;
};
```

### Szczegóły implementacji algorytmu genetycznego

#### PopulationCacheImpl
Implementacja cache'owania populacji dla przyspieszenia obliczeń:
```cpp
class PopulationCacheImpl : public IPopulationCache {
// Metody zarządzania cache'm
void addToCache(const std::vector& genes, double fitness);
bool isInCache(const std::vector& genes) const;
double getCachedFitness(const std::vector& genes) const;

// Parametry cache'a
const size_t MAX_CACHE_SIZE = 10000;
void cleanCache();
};
```

#### GeneticAlgorithmRunner
Klasa zarządzająca uruchomieniem algorytmu genetycznego:
```cpp
class GeneticAlgorithmRunner {
// Główne metody
void run(const DNAInstance& instance);
void initialize();
void evolve();
void finalize();

// Metody pomocnicze
void updateStatistics();
void logProgress();
void checkStoppingCriteria();

// Parametry wykonania
const int CHECKPOINT_INTERVAL = 100;
const int LOG_INTERVAL = 10;
};
```

## Przykłady użycia

### Przykład 1: Podstawowe użycie
```cpp
// Inicjalizacja
auto instance = DNAInstance::fromFile("instance.txt");
auto config = GAConfig::fromFile("config.txt");
auto ga = GeneticAlgorithm(std::make_unique(), config);

// Uruchomienie
std::string result = ga.run(instance);
std::cout << "Zrekonstruowana sekwencja: " << result << std::endl;
```

### Przykład 2: Zaawansowana konfiguracja
```cpp
// Konfiguracja operatorów
auto selection = std::make_unique(3);
auto crossover = std::make_unique();
auto mutation = std::make_unique(0.1);

// Konfiguracja algorytmu
GAConfig config;
config.setPopulationSize(100)
.setMaxGenerations(1000)
.setSelection(std::move(selection))
.setCrossover(std::move(crossover))
.setMutation(std::move(mutation));

// Uruchomienie z logowaniem
Logger::getInstance().setLogLevel(Logger::Level::DEBUG);
auto ga = GeneticAlgorithm(std::make_unique(), config);
ga.run(instance);
```

### Przykład 3: Strojenie parametrów
```cpp
// Konfiguracja strojenia
auto tuner = ParameterTuningManager("tuning_results.csv");
tuner.addParameter("population_size", {50, 100, 200})
.addParameter("crossover_rate", {0.7, 0.8, 0.9})
.addParameter("mutation_rate", {0.01, 0.05, 0.1});

// Uruchomienie strojenia
tuner.tune(instance, 30); // 30 iteracji dla każdej konfiguracji
```

## Workflow trybu debug

### 1. Inicjalizacja i konfiguracja
```cpp
// Tworzenie instancji problemu
auto instance = DNAInstance::fromFile("instance.txt");

// Konfiguracja w trybie debug
GAConfig config;
config.setPopulationSize(50) // Mniejsza populacja dla szybszego debugowania
.setMaxGenerations(100) // Mniej generacji
.setDebugMode(true) // Włączenie trybu debug
.setLogLevel(Logger::Level::DEBUG);

// Inicjalizacja loggera
Logger::getInstance().enableFileOutput(true)
.setLogFile("debug_output.txt")
.enableConsoleOutput(true);

// Inicjalizacja profilera
Profiler::getInstance().startSection("main");
```

### 2. Przebieg algorytmu w trybie debug

#### 2.1. Inicjalizacja populacji
```cpp
void GeneticAlgorithm::initializePopulation() {
Logger::debug("Inicjalizacja populacji początkowej");
Profiler::startSection("initialization");

// Tworzenie początkowej populacji
for (int i = 0; i < config.populationSize; i++) {
auto individual = createRandomIndividual();
population.push_back(individual);
Logger::debug(f"Osobnik {i}: {individual->toString()}");
}

Profiler::endSection("initialization");
}
```

#### 2.2. Główna pętla ewolucyjna
```cpp
void GeneticAlgorithm::evolve() {
for (int generation = 0; generation < config.maxGenerations; generation++) {
Profiler::startSection("generation");

// Selekcja rodziców
Logger::debug("Generacja {generation}: Selekcja");
auto parents = selection->select(population, config.selectionSize);

// Krzyżowanie
Logger::debug("Krzyżowanie wybranych osobników");
auto offspring = crossover->crossover(parents);

// Mutacja
Logger::debug("Mutacja potomstwa");
for (auto& child : offspring) {
mutation->mutate(child);
}

// Ewaluacja
Logger::debug("Obliczanie przystosowania");
evaluatePopulation(offspring);

// Wymiana pokoleń
Logger::debug("Wymiana pokoleń");
population = replacement->replace(population, offspring);

// Statystyki i debug info
logDebugInfo(generation);

Profiler::endSection("generation");
}
}
```

#### 2.3. Ewaluacja i statystyki
```cpp
void GeneticAlgorithm::evaluatePopulation() {
Profiler::startSection("evaluation");

for (auto& individual : population) {
// Obliczanie przystosowania
double fitness = fitnessCalculator->calculate(individual);
individual->setFitness(fitness);

// Debug info
Logger::debug(f"Fitness: {fitness}, DNA: {individual->getDNA()}");
}

// Statystyki populacji
double avgFitness = calculateAverageFitness();
double bestFitness = findBestFitness();

Logger::debug(f"Średnie przystosowanie: {avgFitness}");
Logger::debug(f"Najlepsze przystosowanie: {bestFitness}");

Profiler::endSection("evaluation");
}
```

### 3. Narzędzia debugowania

#### 3.1. Logger
Używany do śledzenia przebiegu algorytmu:
```cpp
// Poziomy logowania
Logger::debug("Szczegółowe informacje dla debugowania");
Logger::info("Ogólne informacje o postępie");
Logger::warning("Ostrzeżenia");
Logger::error("Błędy krytyczne");
```

#### 3.2. Profiler
Mierzy wydajność poszczególnych sekcji:
```cpp
// Przykładowy raport profilera
Section | Total Time | Calls | Avg Time
-----------------|------------|-------|----------
initialization | 0.123s | 1 | 0.123s
generation | 15.432s | 100 | 0.154s
evaluation | 10.234s | 100 | 0.102s
selection | 2.345s | 100 | 0.023s
crossover | 1.876s | 100 | 0.019s
mutation | 0.987s | 100 | 0.010s
```

#### 3.3. Wizualizacja postępu
```cpp
void GeneticAlgorithm::visualizeProgress() {
// Wykres fitness w czasie
plotFitnessProgress();

// Wizualizacja różnorodności populacji
plotPopulationDiversity();

// Statystyki operatorów
plotOperatorStatistics();
}
```

### 4. Analiza wyników

#### 4.1. Statystyki końcowe
```cpp
struct DebugStatistics {
double bestFitness;
double averageFitness;
double worstFitness;
double populationDiversity;
int generationsToConvergence;
double executionTime;

std::map operatorEffectiveness;
};
```

#### 4.2. Walidacja rozwiązania
```cpp
void GeneticAlgorithm::validateSolution() {
auto bestSolution = getBestIndividual();

// Sprawdzenie poprawności DNA
bool isValid = validator->validateDNA(bestSolution->getDNA());
Logger::debug(f"Poprawność rozwiązania: {isValid}");

// Szczegółowa analiza błędów
auto errors = validator->analyzeErrors(bestSolution->getDNA());
for (const auto& error : errors) {
Logger::debug(f"Błąd: {error.description} w pozycji {error.position}");
}
}
```

### 5. Przykład użycia trybu debug
```cpp
int main() {
// Inicjalizacja z trybem debug
auto ga = GeneticAlgorithm(config, true);

// Uruchomienie z pełnym logowaniem
Logger::setLogLevel(Logger::Level::DEBUG);
Profiler::getInstance().enable();

// Wykonanie algorytmu
auto result = ga.run(instance);

// Analiza wyników
ga.validateSolution();
ga.visualizeProgress();

// Generowanie raportu
Profiler::getInstance().generateReport("profiling_results.txt");
Logger::saveLog("debug_log.txt");
}
```

## Skrypty testowania i analizy wyników (scripts/)

### Framework testowania (sbh_testing_framework.py)
Framework do automatycznego testowania rozwiązań na różnych instancjach:

```python
class SBHTestingFramework:
def __init__(self, config_path: str):
"""
Inicjalizacja frameworku testowego
:param config_path: Ścieżka do pliku konfiguracyjnego
"""
self.config = self._load_config(config_path)
self.results_db = ResultsDatabase()
self.test_cases = TestCaseManager()

def run_test_suite(self, test_suite: str):
"""
Uruchomienie zestawu testów
:param test_suite: Nazwa zestawu testów (np. 'easy', 'medium', 'hard')
"""
for test_case in self.test_cases.get_suite(test_suite):
self._run_single_test(test_case)
self._collect_metrics(test_case)

def generate_report(self, output_path: str):
"""
Generowanie raportu z testów
:param output_path: Ścieżka do pliku wyjściowego
"""
self.results_db.generate_report(output_path)

class TestCase:
"""Reprezentacja pojedynczego przypadku testowego"""
def __init__(self, dna_length: int, oligo_length: int,
neg_errors: int, pos_errors: int):
self.dna_length = dna_length
self.oligo_length = oligo_length
self.neg_errors = neg_errors
self.pos_errors = pos_errors
self.original_sequence = None
self.fragments = []
```

### System rankingowy (ranking_system.py)
System do tworzenia rankingu rozwiązań:

```python
class RankingSystem:
def __init__(self, results_db_path: str):
"""
Inicjalizacja systemu rankingowego
:param results_db_path: Ścieżka do bazy wyników
"""
self.results = self._load_results(results_db_path)
self.metrics = MetricsCalculator()

def calculate_rankings(self):
"""Obliczanie rankingów dla różnych kategorii"""
return {
'overall': self._calculate_overall_ranking(),
'by_size': self._calculate_size_based_ranking(),
'by_error_type': self._calculate_error_based_ranking(),
'by_time': self._calculate_time_based_ranking()
}

def generate_ranking_report(self, output_path: str):
"""
Generowanie raportu rankingowego
:param output_path: Ścieżka do pliku wyjściowego
"""
rankings = self.calculate_rankings()
self._generate_report(rankings, output_path)

class MetricsCalculator:
"""Kalkulator metryk dla rankingu"""
def calculate_solution_score(self, solution: Solution) -> float:
"""
Obliczanie wyniku dla pojedynczego rozwiązania
Uwzględnia:
- Dokładność rekonstrukcji
- Czas wykonania
- Zużycie pamięci
- Stabilność wyników
"""
accuracy = self._calculate_accuracy(solution)
time_score = self._calculate_time_score(solution)
memory_score = self._calculate_memory_score(solution)
stability = self._calculate_stability(solution)

return self._combine_scores(accuracy, time_score,
memory_score, stability)
```

### Wizualizacja wyników (visualization_manager.py)
Narzędzie do wizualizacji wyników testów:

```python
class VisualizationManager:
def __init__(self, results_data: pd.DataFrame):
"""
Inicjalizacja menedżera wizualizacji
:param results_data: DataFrame z wynikami
"""
self.data = results_data
self.plt_style = self._configure_plot_style()

def plot_performance_comparison(self):
"""Generowanie wykresów porównawczych wydajności"""
self._plot_accuracy_comparison()
self._plot_time_comparison()
self._plot_memory_usage()
self._plot_convergence_rates()

def generate_error_analysis(self):
"""Analiza i wizualizacja błędów"""
self._plot_error_distribution()
self._plot_error_correlation()
self._generate_error_heatmap()
```

### Przykłady użycia skryptów

#### 1. Uruchomienie zestawu testów
```python
# Inicjalizacja i uruchomienie testów
framework = SBHTestingFramework('config/test_config.yaml')
framework.run_test_suite('comprehensive')
framework.generate_report('results/test_report.pdf')
```

#### 2. Generowanie rankingu
```python
# Tworzenie rankingu rozwiązań
ranking = RankingSystem('results/results_database.db')
rankings = ranking.calculate_rankings()
ranking.generate_ranking_report('results/ranking_report.pdf')
```

#### 3. Wizualizacja wyników
```python
# Wizualizacja wyników
results_data = pd.read_csv('results/test_results.csv')
viz = VisualizationManager(results_data)
viz.plot_performance_comparison()
viz.generate_error_analysis()
```

### Format plików konfiguracyjnych

#### test_config.yaml
```yaml
test_suites:
easy:
dna_length: [300, 400]
oligo_length: [7, 8]
neg_errors: [0, 10]
pos_errors: [0, 10]
repetitions: 5

medium:
dna_length: [500, 600]
oligo_length: [8, 9]
neg_errors: [20, 30]
pos_errors: [20, 30]
repetitions: 10

hard:
dna_length: [700, 800]
oligo_length: [9, 10]
neg_errors: [40, 50]
pos_errors: [40, 50]
repetitions: 15
```

#### ranking_config.yaml
```yaml
metrics:
accuracy:
weight: 0.4
threshold: 0.95

time:
weight: 0.3
max_time: 3600

memory:
weight: 0.2
max_memory: 1024

stability:
weight: 0.1
min_repetitions: 5
```

### Generowane raporty

#### Test Report (test_report.pdf)
```
Test Suite Results
-----------------
Suite: Comprehensive
Total test cases: 150
Success rate: 92%

Detailed Results:
1. Easy instances (50 cases)
- Success rate: 98%
- Avg. time: 12.3s
- Avg. memory: 256MB

2. Medium instances (50 cases)
- Success rate: 94%
- Avg. time: 45.7s
- Avg. memory: 512MB

3. Hard instances (50 cases)
- Success rate: 84%
- Avg. time: 187.2s
- Avg. memory: 1024MB
```

#### Ranking Report (ranking_report.pdf)
```
Algorithm Rankings
-----------------
Overall Ranking:
1. AdaptiveGA v2.1 (Score: 0.92)
2. StandardGA v1.5 (Score: 0.87)
3. HybridGA v1.0 (Score: 0.85)

Category Rankings:
1. Best for small instances:
- AdaptiveGA v2.1 (Score: 0.95)

2. Best for large instances:
- HybridGA v1.0 (Score: 0.88)

3. Best time performance:
- StandardGA v1.5 (Score: 0.91)
```

## Google Tests i metodologia testowania

### 1. Struktura testów
```
tests/
├── google_tests/ # Testy jednostkowe z Google Test
│ ├── genetic/ # Testy modułu genetycznego
│ │ ├── crossover_test.cpp # Testy operatorów krzyżowania
│ │ ├── mutation_test.cpp # Testy operatorów mutacji
│ │ ├── selection_test.cpp # Testy metod selekcji
│ │ └── fitness_test.cpp # Testy funkcji przystosowania
│ ├── dna/ # Testy modułu DNA
│ │ ├── instance_test.cpp # Testy instancji DNA
│ │ └── error_test.cpp # Testy wprowadzania błędów
│ └── utils/ # Testy narzędzi
│ ├── random_test.cpp # Testy generatora liczb losowych
│ └── timer_test.cpp # Testy pomiaru czasu
├── integration_tests/ # Testy integracyjne
│ ├── algorithm_test.cpp # Testy przepływu algorytmu
│ └── system_test.cpp # Testy całego systemu
└── performance_tests/ # Testy wydajnościowe
├── benchmark_test.cpp # Testy wydajności
└── stress_test.cpp # Testy obciążeniowe
```

### 2. Przykłady implementacji testów

#### 2.1. Test operatora krzyżowania
```cpp
TEST(CrossoverTest, SinglePointCrossoverMaintainsValidPermutation) {
// Arrange
auto parent1 = std::make_shared(std::vector{1,2,3,4,5});
auto parent2 = std::make_shared(std::vector{5,4,3,2,1});
auto crossover = std::make_unique();

// Act
auto [child1, child2] = crossover->crossover(parent1, parent2);

// Assert
EXPECT_TRUE(isValidPermutation(child1->getGenes()));
EXPECT_TRUE(isValidPermutation(child2->getGenes()));
EXPECT_EQ(child1->getGenes().size(), 5);
EXPECT_EQ(child2->getGenes().size(), 5);
}
```

#### 2.2. Test funkcji przystosowania
```cpp
TEST(FitnessTest, OptimalSolutionHasMaxFitness) {
// Arrange
auto instance = createTestInstance();
auto solution = createOptimalSolution(instance);
auto fitness = std::make_unique();

// Act
double fitnessValue = fitness->calculate(solution->getGenes(), instance);

// Assert
EXPECT_NEAR(fitnessValue, 1.0, 0.001);
}
```

#### 2.3. Test mutacji
```cpp
TEST(MutationTest, SwapMutationChangesExactlyTwoPositions) {
// Arrange
auto individual = std::make_shared(std::vector{1,2,3,4,5});
auto originalGenes = individual->getGenes();
auto mutation = std::make_unique(1.0); // 100% szansa na mutację

// Act
mutation->mutate(individual);
auto mutatedGenes = individual->getGenes();

// Assert
int differences = 0;
for (size_t i = 0; i < originalGenes.size(); ++i) {
if (originalGenes[i] != mutatedGenes[i]) differences++;
}
EXPECT_EQ(differences, 2);
}
```

### 3. Testy wydajnościowe

#### 3.1. Test obciążeniowy
```cpp
TEST(StressTest, HandlesLargeInstances) {
// Arrange
const int NUM_TESTS = 100;
const int DNA_LENGTH = 1000;
auto ga = setupGeneticAlgorithm();

// Act & Assert
for (int i = 0; i < NUM_TESTS; ++i) {
auto instance = generateLargeInstance(DNA_LENGTH);
auto start = std::chrono::high_resolution_clock::now();

auto result = ga.run(instance);

auto end = std::chrono::high_resolution_clock::now();
auto duration = std::chrono::duration_cast
(end - start).count();

EXPECT_LE(duration, 60); // Max 1 minuta na instancję
EXPECT_GE(ga.getBestFitness(), 0.85);
}
}
```

### 4. Automatyzacja testów

#### 4.1. Skrypt do uruchamiania testów
```bash
#!/bin/bash
# run_tests.sh

# Kompilacja
cd build
cmake -DBUILD_TESTING=ON ..
make -j$(nproc)

# Testy jednostkowe
echo "Running unit tests..."
./tests/google_tests/unit_tests --gtest_output="xml:unit_test_results.xml"

# Testy integracyjne
echo "Running integration tests..."
./tests/integration_tests/integration_tests --gtest_output="xml:integration_test_results.xml"

# Testy wydajnościowe
echo "Running performance tests..."
./tests/performance_tests/performance_tests --gtest_output="xml:performance_test_results.xml"

# Analiza wyników
python3 ../scripts/analyze_test_results.py
```

#### 4.2. Skrypt analizy wyników
```python
# analyze_test_results.py
def analyze_test_results():
unit_results = parse_xml_results('unit_test_results.xml')
integration_results = parse_xml_results('integration_test_results.xml')
performance_results = parse_xml_results('performance_test_results.xml')

generate_report(unit_results, integration_results, performance_results)
```

### 5. Konfiguracja CMake dla testów

```cmake
# CMakeLists.txt
enable_testing()

# Google Test
find_package(GTest REQUIRED)
include_directories(${GTEST_INCLUDE_DIRS})

# Testy jednostkowe
add_executable(unit_tests
tests/google_tests/genetic/crossover_test.cpp
tests/google_tests/genetic/mutation_test.cpp
tests/google_tests/genetic/selection_test.cpp
tests/google_tests/genetic/fitness_test.cpp
# ... pozostałe pliki testów
)

target_link_libraries(unit_tests
PRIVATE
GTest::GTest
GTest::Main
${PROJECT_NAME}_lib
)

# Dodanie testów do CTest
add_test(NAME unit_tests COMMAND unit_tests)
add_test(NAME integration_tests COMMAND integration_tests)
add_test(NAME performance_tests COMMAND performance_tests)
```

### 6. Continuous Integration

```yaml
# .github/workflows/tests.yml
name: Tests

on: [push, pull_request]

jobs:
test:
runs-on: ubuntu-latest

steps:
- uses: actions/checkout@v2

- name: Install dependencies
run: |
sudo apt-get update
sudo apt-get install -y libgtest-dev cmake

- name: Build and test
run: |
mkdir build && cd build
cmake -DBUILD_TESTING=ON ..
make
ctest --output-on-failure --verbose
```

### 7. Pokrycie kodu testami

#### 7.1. Konfiguracja lcov
```bash
# Instalacja lcov
sudo apt-get install lcov

# Kompilacja z flagami pokrycia
cmake -DCMAKE_BUILD_TYPE=Debug -DENABLE_COVERAGE=ON ..
make

# Generowanie raportu pokrycia
lcov --capture --directory . --output-file coverage.info
lcov --remove coverage.info '/usr/*' --output-file coverage.info
genhtml coverage.info --output-directory coverage_report
```

#### 7.2. Badge pokrycia w README
```markdown
![Coverage](https://img.shields.io/badge/coverage-94%25-green.svg)
```

### 8. Dobre praktyki testowania

1. **Organizacja testów**
- Jeden plik testowy na jeden plik źródłowy
- Grupowanie testów w logiczne kategorie
- Jasne nazewnictwo testów (Given_When_Then)

2. **Struktura testu**
- Arrange (przygotowanie)
- Act (działanie)
- Assert (sprawdzenie)

3. **Testowanie brzegowych przypadków**
- Puste wejście
- Maksymalne wartości
- Nieprawidłowe dane
- Błędy alokacji pamięci

4. **Mockowanie i stubbing**
- Używanie mock objects dla zewnętrznych zależności
- Stubbing dla deterministycznych testów
- Izolacja testowanego kodu

5. **Wydajność testów**
- Szybkie testy jednostkowe
- Dłuższe testy integracyjne w osobnej grupie
- Testy wydajnościowe uruchamiane na żądanie
```

## Operatory krzyżowania (Crossover)

### 1. Krzyżowanie jednopunktowe (SinglePointCrossover)
```cpp
class SinglePointCrossover : public ICrossover {
std::pair, std::shared_ptr>
crossover(const std::shared_ptr& parent1,
const std::shared_ptr& parent2) override;
};
```

#### Zasada działania:
1. Wybierany jest losowy punkt przecięcia (k) w zakresie [1, n-1], gdzie n to długość chromosomu
2. Pierwszy potomek otrzymuje geny [1..k] od pierwszego rodzica i [k+1..n] od drugiego
3. Drugi potomek otrzymuje geny [1..k] od drugiego rodzica i [k+1..n] od pierwszego
4. Wykonywana jest naprawa permutacji, aby zachować poprawność rozwiązania

#### Przykład:
```
Rodzic 1: [1 2 3 | 4 5 6]
Rodzic 2: [6 5 4 | 3 2 1]
Punkt przecięcia: 3

Przed naprawą:
Potomek 1: [1 2 3 | 3 2 1]
Potomek 2: [6 5 4 | 4 5 6]

Po naprawie:
Potomek 1: [1 2 3 | 6 5 4]
Potomek 2: [6 5 4 | 1 2 3]
```

### 2. Krzyżowanie dwupunktowe (TwoPointCrossover)
```cpp
class TwoPointCrossover : public ICrossover {
std::pair, std::shared_ptr>
crossover(const std::shared_ptr& parent1,
const std::shared_ptr& parent2) override;
};
```

#### Zasada działania:
1. Wybierane są dwa losowe punkty przecięcia (k1, k2) gdzie k1 < k2
2. Pierwszy potomek otrzymuje segmenty [1..k1] i [k2+1..n] od pierwszego rodzica i [k1+1..k2] od drugiego
3. Drugi potomek otrzymuje segmenty [1..k1] i [k2+1..n] od drugiego rodzica i [k1+1..k2] od pierwszego
4. Wykonywana jest naprawa permutacji

#### Przykład:
```
Rodzic 1: [1 2 | 3 4 | 5 6]
Rodzic 2: [6 5 | 4 3 | 2 1]
Punkty przecięcia: 2, 4

Przed naprawą:
Potomek 1: [1 2 | 4 3 | 5 6]
Potomek 2: [6 5 | 3 4 | 2 1]

Po naprawie:
Potomek 1: [1 2 | 4 3 | 5 6]
Potomek 2: [6 5 | 3 4 | 2 1]
```

### 3. Krzyżowanie równomierne (UniformCrossover)
```cpp
class UniformCrossover : public ICrossover {
std::pair, std::shared_ptr>
crossover(const std::shared_ptr& parent1,
const std::shared_ptr& parent2) override;
private:
double crossoverProbability = 0.5;
};
```

#### Zasada działania:
1. Dla każdej pozycji i w chromosomie:
- Z prawdopodobieństwem p (domyślnie 0.5) gen pochodzi od pierwszego rodzica
- Z prawdopodobieństwem (1-p) gen pochodzi od drugiego rodzica
2. Wykonywana jest naprawa permutacji dla obu potomków

#### Przykład:
```
Rodzic 1: [1 2 3 4 5 6]
Rodzic 2: [6 5 4 3 2 1]
Maska: [1 0 1 0 1 0] (1: gen z rodzica 1, 0: gen z rodzica 2)

Przed naprawą:
Potomek 1: [1 5 3 3 5 1]
Potomek 2: [6 2 4 4 2 6]

Po naprawie:
Potomek 1: [1 5 3 4 2 6]
Potomek 2: [6 2 4 3 5 1]
```

### 4. Krzyżowanie adaptacyjne (AdaptiveCrossover)
```cpp
class AdaptiveCrossover : public ICrossover {
std::pair, std::shared_ptr>
crossover(const std::shared_ptr& parent1,
const std::shared_ptr& parent2) override;
private:
void updateCrossoverRates();
void adaptParameters();
std::vector operators;
std::vector successRates;
};
```

#### Zasada działania:
1. Utrzymuje pulę różnych operatorów krzyżowania
2. Monitoruje skuteczność każdego operatora
3. Adaptuje prawdopodobieństwa użycia operatorów na podstawie ich skuteczności
4. Wybiera operator do krzyżowania na podstawie zaktualizowanych prawdopodobieństw

#### Przykład adaptacji:
```
Początkowe prawdopodobieństwa:
- SinglePoint: 0.33
- TwoPoint: 0.33
- Uniform: 0.33
- Cycle: 0.33
- PMX: 0.33
- EdgeRecombination: 0.33

Po 100 generacjach:
- SinglePoint: 0.45 (najlepsze wyniki)
- TwoPoint: 0.35
- Uniform: 0.20 (najgorsze wyniki)
```

### 5. Krzyżowanie cykliczne (CycleCrossover)
```cpp
class CycleCrossover : public ICrossover {
std::pair, std::shared_ptr>
crossover(const std::shared_ptr& parent1,
const std::shared_ptr& parent2) override;
private:
std::vector findCycle(const std::vector& p1,
const std::vector& p2);
};
```

#### Zasada działania:
1. Znajduje cykle w permutacjach rodziców
2. Zachowuje kompletne cykle z pierwszego rodzica dla pierwszego potomka
3. Wypełnia pozostałe pozycje genami z drugiego rodzica
4. Dla drugiego potomka proces jest odwrotny

#### Przykład:
```
Rodzic 1: [1 2 3 4 5 6]
Rodzic 2: [2 4 5 1 6 3]

Cykl 1: 1->2->4->1
Cykl 2: 3->5->6->3

Potomek 1: [1 2 5 4 6 3]
Potomek 2: [2 4 3 1 5 6]
```

### 6. Krzyżowanie porządkowe (OrderCrossover)
```cpp
class OrderCrossover : public ICrossover {
std::pair, std::shared_ptr>
crossover(const std::shared_ptr& parent1,
const std::shared_ptr& parent2) override;
};
```

#### Zasada działania:
1. Wybiera losowy podciąg z pierwszego rodzica
2. Kopiuje ten podciąg do potomka na te same pozycje
3. Wypełnia pozostałe pozycje genami z drugiego rodzica w kolejności ich występowania
4. Dla drugiego potomka proces jest odwrotny

#### Przykład:
```
Rodzic 1: [1 2 3 4 5 6]
Rodzic 2: [6 5 4 3 2 1]
Wybrany podciąg: [2 3 4]

Potomek 1: [6 2 3 4 5 1]
Potomek 2: [1 5 4 3 2 6]
```

### 7. Implementacja naprawy permutacji
```cpp
class PermutationRepair {
public:
static void repair(std::vector& genes) {
std::vector used(genes.size(), false);
std::vector missing;

// Znajdź duplikaty i brakujące elementy
for (int i = 0; i < genes.size(); i++) {
if (used[genes[i]]) {
missing.push_back(i);
} else {
used[genes[i]] = true;
}
}

// Znajdź brakujące wartości
std::vector values;
for (int i = 0; i < used.size(); i++) {
if (!used[i]) {
values.push_back(i);
}
}

// Napraw permutację
for (int i = 0; i < missing.size(); i++) {
genes[missing[i]] = values[i];
}
}
};
```

### 8. Porównanie skuteczności operatorów
```cpp
struct CrossoverEffectiveness {
std::string name;
double avgFitness;
double successRate;
double avgExecutionTime;
int validOffspringRate;
};

std::vector results = {
{"SinglePoint", 0.85, 0.92, 0.12, 95},
{"TwoPoint", 0.87, 0.90, 0.15, 93},
{"Uniform", 0.82, 0.88, 0.18, 90},
{"Adaptive", 0.89, 0.94, 0.20, 96},
{"Cycle", 0.84, 0.89, 0.14, 94},
{"Order", 0.86, 0.91, 0.13, 92}
};
```

### 9. Krzyżowanie PMX (Partially Mapped Crossover)
```cpp
class PMXCrossover : public ICrossover {
std::pair, std::shared_ptr>
crossover(const std::shared_ptr& parent1,
const std::shared_ptr& parent2) override;
private:
void createMapping(const std::vector& section1,
const std::vector& section2,
std::map& mapping);
};
```

#### Zasada działania:
1. Wybiera dwa punkty przecięcia, definiując sekcję do mapowania
2. Kopiuje sekcję z pierwszego rodzica do pierwszego potomka
3. Tworzy mapowanie między elementami w sekcji
4. Używa mapowania do wypełnienia pozostałych pozycji
5. Powtarza proces dla drugiego potomka w odwrotnej kolejności

#### Przykład:
```
Rodzic 1: [1 2 3 | 4 5 6 | 7 8 9]
Rodzic 2: [9 8 7 | 1 3 2 | 6 5 4]
Punkty przecięcia: 3, 6

Mapowanie:
4 ↔ 1
5 ↔ 3
6 ↔ 2

Przed mapowaniem:
Potomek 1: [_ _ _ | 4 5 6 | _ _ _]
Potomek 2: [_ _ _ | 1 3 2 | _ _ _]

Po mapowaniu:
Potomek 1: [3 1 2 | 4 5 6 | 7 8 9]
Potomek 2: [9 8 7 | 1 3 2 | 4 5 6]
```

### 10. Krzyżowanie krawędziowe (Edge Recombination Crossover)
```cpp
class EdgeRecombinationCrossover : public ICrossover {
std::pair, std::shared_ptr>
crossover(const std::shared_ptr& parent1,
const std::shared_ptr& parent2) override;
private:
struct EdgeList {
std::vector> adjacency;
void buildFrom(const std::vector& p1, const std::vector& p2);
std::set getNeighbors(int node) const;
void removeNode(int node);
};
};
```

#### Zasada działania:
1. Tworzy listę krawędzi (sąsiedztwa) z obu rodziców
2. Rozpoczyna od losowego miasta z jednego z rodziców
3. Iteracyjnie wybiera następne miasto z najmniejszą liczbą pozostałych sąsiadów
4. W przypadku remisu, wybiera losowo z dostępnych opcji
5. Aktualizuje listę krawędzi po każdym wyborze

#### Przykład:
```
Rodzic 1: [1 2 3 4 5]
Rodzic 2: [5 3 1 2 4]

Lista sąsiedztwa:
1: {2, 3, 5} // Sąsiedzi z obu rodziców
2: {1, 3, 4}
3: {1, 2, 4, 5}
4: {2, 3, 5}
5: {1, 3, 4}

Proces budowy potomka:
Start: 1
Lista sąsiadów: 2(2), 3(3), 5(2) → Wybierz 2
Lista sąsiadów: 3(2), 4(1) → Wybierz 3
Lista sąsiadów: 4(1), 5(1) → Wybierz 4
Pozostało: 5

Potomek: [1 2 3 4 5]
```

### 11. Krzyżowanie adaptacyjne rozszerzone (Enhanced Adaptive Crossover)
```cpp
class EnhancedAdaptiveCrossover : public ICrossover {
std::pair, std::shared_ptr>
crossover(const std::shared_ptr& parent1,
const std::shared_ptr& parent2) override;
private:
std::vector> m_crossovers;
std::vector m_weights;

void updateWeights(const std::vector& fitnessDiffs);
std::shared_ptr selectOperator();
};
```

#### Zasada działania:
1. Utrzymuje pulę wszystkich dostępnych operatorów krzyżowania:
- SinglePointCrossover
- TwoPointCrossover
- UniformCrossover
- CycleCrossover
- PMXCrossover
- EdgeRecombinationCrossover

2. Adaptacyjnie dostosowuje wagi operatorów na podstawie ich skuteczności:
```cpp
void updateWeights(const std::vector& fitnessDiffs) {
double total = 0.0;
for (size_t i = 0; i < m_crossovers.size(); ++i) {
m_weights[i] = m_weights[i] * 0.9 + fitnessDiffs[i] * 0.1;
total += m_weights[i];
}
// Normalizacja wag
for (auto& weight : m_weights) {
weight /= total;
}
}
```

#### Przykład adaptacji:
```
Początkowe wagi:
- SinglePoint: 0.167
- TwoPoint: 0.167
- Uniform: 0.167
- Cycle: 0.167
- PMX: 0.167
- EdgeRecombination: 0.167

Po 100 generacjach:
- SinglePoint: 0.15
- TwoPoint: 0.12
- Uniform: 0.10
- Cycle: 0.20
- PMX: 0.30
- EdgeRecombination: 0.20
```

### 12. Porównanie skuteczności wszystkich operatorów
```cpp
struct DetailedCrossoverEffectiveness {
std::string name;
double avgFitness;
double successRate;
double avgExecutionTime;
int validOffspringRate;
double diversityMaintenance;
double convergenceSpeed;
};

std::vector extendedResults = {
{"SinglePoint", 0.85, 0.92, 0.12, 95, 0.75, 0.82},
{"TwoPoint", 0.87, 0.90, 0.15, 93, 0.78, 0.85},
{"Uniform", 0.82, 0.88, 0.18, 90, 0.85, 0.78},
{"Cycle", 0.84, 0.89, 0.14, 94, 0.80, 0.83},
{"PMX", 0.89, 0.94, 0.16, 96, 0.88, 0.90},
{"EdgeRecombination", 0.88, 0.93, 0.20, 95, 0.90, 0.87},
{"AdaptiveMix", 0.91, 0.95, 0.22, 97, 0.92, 0.92}
};
```

Wnioski z porównania:
1. PMX i EdgeRecombination najlepiej zachowują strukturę rozwiązania
2. Adaptive Mix osiąga najlepsze wyniki dzięki dynamicznemu doborowi operatorów
3. EdgeRecombination najlepiej zachowuje różnorodność populacji
4. PMX ma najlepszy stosunek jakości do czasu wykonania
5. Operatory proste (SinglePoint, TwoPoint) są najszybsze, ale mniej skuteczne

# Test Coverage Overview

## I. Pliki `.cpp` (z katalogu `src`)

### 1. Benchmark
| Plik źródłowy | Plik testowy | Status |
|-----------------------------------------------|---------------------------------------------------------------------|---------|
| src/benchmark/adaptive_crossover_benchmark.cpp| tests/google_tests/benchmark/adaptive_crossover_benchmark_test.cpp | ❌ |
| src/benchmark/crossover_benchmark.cpp | tests/google_tests/benchmark/crossover_benchmark_test.cpp | ❌ |
| src/benchmark/naive_benchmark.cpp | tests/google_tests/benchmark/naive_benchmark_test.cpp | ❌ |

### 2. Configuration
| Plik źródłowy | Plik testowy | Status |
|--------------------------------------------------------|----------------------------------------------------------------------|---------|
| src/configuration/genetic_algorithm_configuration.cpp | tests/google_tests/configuration/genetic_algorithm_configuration_test.cpp | ❌ |

### 3. DNA
| Plik źródłowy | Plik testowy | Status |
|------------------------------------|------------------------------------------------------------|---------|
| src/dna/dna_generator.cpp | tests/google_tests/dna/dna_generator_test.cpp | ✅ |
| src/dna/dna_instance.cpp | tests/google_tests/dna/dna_instance_test.cpp | ✅ |
| src/dna/dna_instance_builder.cpp | tests/google_tests/dna/dna_instance_builder_test.cpp | ✅ |
| src/dna/dna_instance_io.cpp | tests/google_tests/dna/dna_instance_io_test.cpp | ✅ |
| src/dna/error_introduction.cpp | tests/google_tests/dna/error_introduction_test.cpp | ✅ |
| src/dna/spectrum_generator.cpp | tests/google_tests/dna/spectrum_generator_test.cpp | ✅ |

### 4. Generator
| Plik źródłowy | Plik testowy | Status |
|---------------------------------------|---------------------------------------------------------------|---------|
| src/generator/dna_generator.cpp | tests/google_tests/generator/dna_generator_test.cpp | ✅ |
| src/generator/spectrum_generator.cpp | tests/google_tests/generator/spectrum_generator_test.cpp | ✅ |

### 5. Main
| Plik źródłowy | Plik testowy | Status |
|---------------------------|--------------------------------------------------|---------|
| src/main.cpp | tests/google_tests/main/main_test.cpp | ❌ |

### 6. Metaheuristics
| Plik źródłowy | Plik testowy | Status |
|----------------------------------------------------|-------------------------------------------------------------------|---------|
| src/metaheuristics/adaptive_crossover.cpp | tests/google_tests/metaheuristics/adaptive_crossover_test.cpp | ✅ |
| src/metaheuristics/crossover.cpp | tests/google_tests/metaheuristics/crossover_test.cpp | ❌ |
| src/metaheuristics/crossover_impl.cpp | tests/google_tests/metaheuristics/crossover_impl_test.cpp | ❌ |
| src/metaheuristics/edge_table.cpp | tests/google_tests/metaheuristics/edge_table_test.cpp | ❌ |
| src/metaheuristics/fitness.cpp | tests/google_tests/metaheuristics/fitness_test.cpp | ❌ |
| src/metaheuristics/fitness_impl.cpp | tests/google_tests/metaheuristics/fitness_impl_test.cpp | ❌ |
| src/metaheuristics/genetic_algorithm.cpp | tests/google_tests/metaheuristics/genetic_algorithm_test.cpp | ✅ |
| src/metaheuristics/genetic_algorithm_runner.cpp | tests/google_tests/metaheuristics/genetic_algorithm_runner_test.cpp | ❌ |
| src/metaheuristics/individual.cpp | tests/google_tests/metaheuristics/individual_test.cpp | ❌ |
| src/metaheuristics/mutation.cpp | tests/google_tests/metaheuristics/mutation_test.cpp | ❌ |
| src/metaheuristics/mutation_impl.cpp | tests/google_tests/metaheuristics/mutation_impl_test.cpp | ❌ |
| src/metaheuristics/path_analyzer.cpp | tests/google_tests/metaheuristics/path_analyzer_test.cpp | ❌ |
| src/metaheuristics/permutation_representation.cpp | tests/google_tests/metaheuristics/permutation_representation_test.cpp | ❌ |
| src/metaheuristics/population_cache.cpp | tests/google_tests/metaheuristics/population_cache_test.cpp | ❌ |
| src/metaheuristics/selection.cpp | tests/google_tests/metaheuristics/selection_test.cpp | ❌ |
| src/metaheuristics/selection_impl.cpp | tests/google_tests/metaheuristics/selection_impl_test.cpp | ❌ |
| src/metaheuristics/stopping_criteria.cpp | tests/google_tests/metaheuristics/stopping_criteria_test.cpp | ❌ |

### 7. Naive
| Plik źródłowy | Plik testowy | Status |
|--------------------------------------------|------------------------------------------------------------|---------|
| src/naive/naive_reconstruction.cpp | tests/google_tests/naive/naive_reconstruction_test.cpp | ❌ |

### 8. Tuning
| Plik źródłowy | Plik testowy | Status |
|-----------------------------------------------|----------------------------------------------------------------------|---------|
| src/tuning/parameter_parser.cpp | tests/google_tests/tuning/parameter_parser_test.cpp | ❌ |
| src/tuning/parameter_tuning_manager.cpp | tests/google_tests/tuning/parameter_tuning_manager_test.cpp | ❌ |
| src/tuning/tuning_structures.cpp | tests/google_tests/tuning/tuning_structures_test.cpp | ❌ |

### 9. Utils
| Plik źródłowy | Plik testowy | Status |
|-----------------------------------------------------------|-------------------------------------------------------------|---------|
| src/utils/logging.cpp | tests/google_tests/utils/logging_test.cpp | ❌ |
| src/utils/performance_profilling_framework.cpp | tests/google_tests/utils/performance_profilling_test.cpp | ❌ |
| src/utils/utility_functions.cpp | tests/google_tests/utils/utility_functions_test.cpp | ❌ |

## II. Pliki nagłówkowe `.h` bez plików `.cpp`

### A. `include/common.h`
| Plik nagłówkowy | Plik testowy | Status |
|--------------------------------------|-----------------------------------------------|---------|
| include/common.h | tests/google_tests/common/common_test.cpp | ❌ |

### B. `include/config`
| Plik nagłówkowy | Plik testowy | Status |
|--------------------------------------|--------------------------------------------------|---------|
| include/config/genetic_config.h | tests/google_tests/config/genetic_config_test.cpp| ❌ |

### C. `include/interfaces`
| Plik nagłówkowy | Plik testowy | Status |
|--------------------------------------|-------------------------------------------------------|---------|
| include/interfaces/i_algorithm.h | tests/google_tests/interfaces/i_algorithm_test.cpp | ❌ |
| include/interfaces/i_benchmark.h | tests/google_tests/interfaces/i_benchmark_test.cpp | ❌ |
| include/interfaces/i_crossover.h | tests/google_tests/interfaces/i_crossover_test.cpp | ❌ |
| include/interfaces/i_fitness.h | tests/google_tests/interfaces/i_fitness_test.cpp | ❌ |
| include/interfaces/i_mutation.h | tests/google_tests/interfaces/i_mutation_test.cpp | ❌ |
| include/interfaces/i_population_cache.h | tests/google_tests/interfaces/i_population_cache_test.cpp| ❌ |
| include/interfaces/i_replacement.h | tests/google_tests/interfaces/i_replacement_test.cpp | ❌ |
| include/interfaces/i_representation.h| tests/google_tests/interfaces/i_representation_test.cpp| ❌ |
| include/interfaces/i_selection.h | tests/google_tests/interfaces/i_selection_test.cpp | ❌ |
| include/interfaces/i_stopping.h | tests/google_tests/interfaces/i_stopping_test.cpp | ❌ |

### D. `include/io`
| Plik nagłówkowy | Plik testowy | Status |
|-------------------------------------|----------------------------------------------|---------|
| include/io/instance_io.h | tests/google_tests/io/instance_io_test.cpp | ✅ |

### E. `include/metaheuristics`
| Plik nagłówkowy | Plik testowy | Status |
|---------------------------------------|----------------------------------------------------------------|---------|
| include/metaheuristics/adaptive_mutation.h | tests/google_tests/metaheuristics/adaptive_mutation_test.cpp | ❌ |
| include/metaheuristics/concrete_fitness.h | tests/google_tests/metaheuristics/concrete_fitness_test.cpp | ❌ |
| include/metaheuristics/dna_utils.h | tests/google_tests/metaheuristics/dna_utils_test.cpp | ❌ |
| include/metaheuristics/preprocessed_edge.h | tests/google_tests/metaheuristics/preprocessed_edge_test.cpp | ❌ |
| include/metaheuristics/replacement_impl.h | tests/google_tests/metaheuristics/replacement_impl_test.cpp | ❌ |

### F. `include/tuning`
| Plik nagłówkowy | Plik testowy | Status |
|-----------------------------------------|----------------------------------------------------------|---------|
| include/tuning/meta_ea.h | tests/google_tests/tuning/meta_ea_test.cpp | ❌ |
| include/tuning/parameters.h | tests/google_tests/tuning/parameters_test.cpp | ❌ |
| include/tuning/racing.h | tests/google_tests/tuning/racing_test.cpp | ❌ |

### G. `include/utils`
| Plik nagłówkowy | Plik testowy | Status |
|------------------------------------------------------|-------------------------------------------------------------|---------|
| include/utils/random.h | tests/google_tests/utils/random_test.cpp | ✅ |
| include/utils/timer.h | tests/google_tests/utils/timer_test.cpp | ❌ |
| include/utils/zobrist_hasher.h | tests/google_tests/utils/zobrist_hasher_test.cpp | ❌ |

## Test Coverage Summary

- Total Files: 52
- Files with Tests: 11
- Coverage Percentage: 21.15%

### Coverage by Module
- DNA Module: 100% (6/6)
- Generator Module: 100% (2/2)
- Metaheuristics Module: 11.76% (2/17)
- Utils Module: 33.33% (1/3)
- Other Modules: 0% (0/24)