Added Comments

Das sollte ausführlich genug sein
This commit is contained in:
Jonny007-MKD 2014-01-13 00:44:05 +01:00
parent 3ba70257af
commit 18f5012f4a
19 changed files with 908 additions and 539 deletions

View file

@ -86,7 +86,7 @@ int CParser::yyparse(PrimImplikantCollection* &pic, vector<string>* &variables)
{
case IDENTIFIER:
*IP_List << "Variable " << yylval.s << endl;
variables->push_back(yylval.s.c_str());
variables->push_back(yylval.s.c_str()); // Add variable name to vector
break;
case TERMS:
*IP_List << endl;
@ -99,10 +99,10 @@ int CParser::yyparse(PrimImplikantCollection* &pic, vector<string>* &variables)
{
case STRING1:
*IP_List << "Term Key " << yylval.s << endl;
pic->add(yylval.s.c_str());
pic->add(yylval.s.c_str()); // Add PrimImplikant with string
break;
case INTEGER1:
*IP_List << "Term Key " << (unsigned int)yylval.i << endl;
*IP_List << "Term Key " << (unsigned int)yylval.i << endl; // Add PrimImplikant with int
pic->add(yylval.i);
break;
case (int)'>':
@ -114,14 +114,14 @@ int CParser::yyparse(PrimImplikantCollection* &pic, vector<string>* &variables)
}
break;
case P_TERMS_VALUE:
if (tok == INTEGER1)
if (tok == INTEGER1) // Check whether KNF was already set and then check consitency
{
if (!KNFset)
{
KNF = (yylval.i == 0);
KNFset = true;
}
else if ((yylval.i == 0) ^ KNF)
else if ((yylval.i == 0) != KNF)
{
*IP_Error << "*** FATAL ERROR *** You can only define either KNF or DNF!" << endl;
*IP_Error << "In line " << setw(3) << setfill('0') << IP_LineNumber << ": " << pic->back()->name << '>' << yylval.i << endl;
@ -137,8 +137,8 @@ int CParser::yyparse(PrimImplikantCollection* &pic, vector<string>* &variables)
}
}
dimension = variables->size();
numElements = (unsigned int)pow(2.0f, (int)dimension);
dimension = variables->size(); // set global variable dimension
numElements = (unsigned int)pow(2.0f, (int)dimension); // set global variabl numElements
return 0;
}

View file

@ -6,48 +6,65 @@
using namespace std;
extern uint dimension;
extern uint dimension; // number of variables
/// <summary>
/// Gets all PrimImplikants that cover this Cell from globalPIC
/// </summary>
void Cell::refresh(PrimImplikantCollection* &globalPIC)
{
this->primImplikanten = globalPIC->primImplikantenAt(index);
}
/// <summary>
/// Gets all Cells that lie next to this Cell (Hamming distance = 1)
/// </summary>
/// <returns>A vector with Cells with size: dimension</returna>
vector<Cell*>* Cell::getNeighbors(vector<Cell*> &allCells)
{
vector<Cell*>* neighbors = new vector<Cell*>();
neighbors->resize(dimension);
uint j = 1;
for (unsigned char i = 0; i < dimension; i++)
for (unsigned char i = 0; i < dimension; i++) // for all bits
{
neighbors->push_back(allCells[this->index ^ j]);
neighbors->at(i) = allCells[this->index ^ j]; // add Cell that is different at one bit (j)
j <<= 1;
}
return neighbors;
}
/// <summary>
/// Looks for hazards around this Cell
/// </summary>
/// <returns>A vector with those Cells that lie next to this Cell and to which a hazard may occur</returns>
vector<Cell*>* Cell::getHazards(vector<Cell*> &allCells)
{
vector<Cell*>* hazardous = new vector<Cell*>();
vector<Cell*>* neighbors = this->getNeighbors(allCells);
for (vector<Cell*>::iterator neighbor = neighbors->begin(); neighbor < neighbors->end(); neighbor++)
for (vector<Cell*>::iterator neighbor = neighbors->begin(); neighbor < neighbors->end(); neighbor++) // for each neighbor
{
if ((*neighbor)->value == false)
if ((*neighbor)->value == false) // if the neighbor is not covered by a PrimImpliaknt, no hazard can occur
continue;
if ((*neighbor)->hasOneOfThose(this->primImplikanten) == false)
hazardous->push_back(*neighbor);
if ((*neighbor)->hasOneOfThose(this->primImplikanten) == false) // check whether at least one PrimImplikant that covers this Cell also covers the neighbor cell
hazardous->push_back(*neighbor); // if not, add it to hazardous
}
delete neighbors;
return hazardous;
}
/// <summary>
/// Checks whether this Cell is covered by a PrimImplikant that is member of the specified PrimImplikantCollection (of another Cell)
/// </summary>
/// <returns>True: A PrimImplikant in foreignPic also covers this Cell</returns>
bool Cell::hasOneOfThose(PrimImplikantCollection &foreignPic)
{
for (uint i = 0; i < foreignPic.size(); i++)
if (this->primImplikanten.contains(foreignPic[i]))
for (uint i = 0; i < foreignPic.size(); i++) // for each foreign PrimImplikant
if (this->primImplikanten.contains(foreignPic[i])) // check whether it also covers this Cell
return true;
return false;
}

View file

@ -1,30 +1,36 @@
#pragma once
#include <string>
#include <vector>
#include "PrimImplikantCollection.h"
using namespace std;
#ifndef CELL
#define CELL
class Cell {
public:
bool value;
unsigned int index;
bool value; // DNF value
unsigned int index; // position of this Cell
vector<Cell*>* getNeighbors(vector<Cell*> &allCells); // returns numElements Cells
vector<Cell*>* getNeighbors(vector<Cell*> &allCells); // returns all Cells which's Hamming distance 1
vector<Cell*>* getHazards(vector<Cell*> &allCells); // returns the neighbor Cells which are hazardous
bool hasOneOfThose(PrimImplikantCollection &foreignPIC);
void refresh(PrimImplikantCollection* &globalPIC); // refreshes the local primImplikantCollection
bool hasOneOfThose(PrimImplikantCollection &foreignPIC); // returns whether this Cell is covered by a PrimImplikant of the specified foreignPIC
void refresh(PrimImplikantCollection* &globalPIC); // refreshes the local primImplikantCollection from globalPIC
Cell(unsigned int index, PrimImplikantCollection* &globalPIC)
/// <summary>
/// Constructor of Cell
/// </summary>
Cell(uint index, PrimImplikantCollection* &globalPIC)
{
this->index = index;
this->refresh(globalPIC);
this->value = this->primImplikanten.size() > 0;
this->value = this->primImplikanten.size() > 0; // if a PrimImplikant covers this Cell, it is true in DNF
}
PrimImplikantCollection primImplikanten;
PrimImplikantCollection primImplikanten; // all PrimImplikants that cover this Cell
};
#ifndef CELLITERATOR
#define CELLITERATOR
typedef vector<Cell*>::iterator CellIt;
#endif

View file

@ -6,43 +6,52 @@
using namespace std;
extern uint dimension;
extern uint numElements;
extern uint dimension; // number of variables
extern uint numElements; // number of Cells/possible numbers
/// <summary>
/// Add a Cell to the collection
/// </summary>
void CellCollection::add(Cell* &cell)
{
this->cells.push_back(cell);
}
void CellCollection::init(PrimImplikantCollection* &globalPIC)
/// <summary>
/// Creates all Cells that exist with the specified number of variables
/// </summary>
void CellCollection::init()
{
this->globalPIC = globalPIC;
this->cells.resize(numElements);
for (uint i = 0; i < numElements; i++)
this->cells[i] = new Cell(i, globalPIC);
this->cells[i] = new Cell(i, this->globalPIC);
}
/// <summary>
/// <para>The hazard detection algorithm</para>
/// <para>We look at every second Cell and if this Cell's value is true (DNF) we asksits neighbors whether there is a PrimImplikant that covers both Cells. If not, we have found a hazard and can create a PrimImplikant that solves it.
/// </summary>
void CellCollection::findHazards()
{
for (uint i = 0; i < numElements; i += 2) // we only need to check every 2nd as long as it's gray
for (uint i = 0; i < numElements; i += 2) // only every 2nd Cell because hazards are checked on all sides of the Cell
{
uint I = i ^ (i/2); // transform to gray code --> Schachbrettmuster
Cell* currentCell = cells[I]; // this is the cell we are currently checking
if (currentCell->value == false) // no hazard can occur
if (currentCell->value == false) // no hazard can occur because no PrimImplikant covers this Cell
continue;
cout << " Checking cell " << I << endl;
vector<Cell*>* hazardousNeighbors = currentCell->getHazards(this->cells);
vector<Cell*>* hazardousNeighbors = currentCell->getHazards(this->cells); // get neighbor Cells with hazards
if (hazardousNeighbors->size() == 0) // no hazard found
if (hazardousNeighbors->size() == 0) // no hazard was found
{
delete hazardousNeighbors;
continue;
}
for (vector<Cell*>::iterator nc = hazardousNeighbors->begin(); nc < hazardousNeighbors->end(); nc++)
for (CellIt nc = hazardousNeighbors->begin(); nc < hazardousNeighbors->end(); nc++) // foreach neighbor Cell with hazard
{
printf("Hazard found! Cell %d <--> Cell %d\n", I, (*nc)->index);
this->globalPIC->add(I, (*nc)->index); // add PI that solves hazard. Not quite smart...
@ -56,35 +65,54 @@ void CellCollection::findHazards()
/// <summary>
/// Deletes all Cell instances in this collection
/// <para>Beware: Only do this at the end! All collections are storing pointers to the Cells and maybe some other object is still using them. Dispose() may only be called by the last instance of this class (which we could check programmatically and then integrate it into the destructor)</para>
/// </summary>
void CellCollection::Dispose()
{
for (uint i = 0; i < this->cells.size(); i++)
delete cells[i];
for (CellIt i = this->cells.begin(); i < this->cells.end(); i++)
delete (*i);
this->cells.clear();
}
/// <summary>
/// Returns the number of Cells in this Collection
/// </summary>
uint CellCollection::size()
{
return cells.size();
}
/// <summary>
/// Returns the last Cell in here
/// </summary>
Cell* CellCollection::back()
{
return cells.back();
}
/// <summary>
/// Returns the first Cell in here
/// </summary>
Cell* CellCollection::front()
{
return cells.front();
}
Cell* CellCollection::at(uint index)
/// <summary>
/// Returns the Cell at the specified index
/// </summary>
Cell* CellCollection::at(const uint index)
{
return cells.at(index);
}
Cell * CellCollection::operator[](uint &index)
/// <summary>
/// Returns the Cell at the specified index
/// </summary>
Cell * CellCollection::operator[](const uint &index)
{
return cells.at(index);
}

View file

@ -6,34 +6,38 @@
using namespace std;
#ifndef _CELLCOLLEC_H
#define _CELLCOLLEC_H
class CellCollection {
/// <summary>
/// <para>This class contains a number of Cells and provides some methods to operate on/with those</para>
/// </summary>
class CellCollection
{
private:
void init(); // creates a CellCollection with numElements Cells and adds the associated PrimImplikants to each of those
public:
void add(Cell* &cell);
void init(PrimImplikantCollection* &globalPIC);
void findHazards();
void add(Cell* &cell); // adds a Cell to this collection
void findHazards(); // the hazard detection algorithm
void Dispose();
void Dispose(); // delete all referenced Cell objects
uint size();
Cell* back();
Cell* front();
Cell* at(uint index);
Cell* operator[](uint &index);
uint size(); // the number of Cells in this collection
Cell* back(); // the last Cell in here
Cell* front(); // the first Cell in here
Cell* at(const uint index); // the Cell at the specified index
Cell* operator[](const uint &index);// the Cell at the specified index
/// <summary>
/// Constructor of CellCollection
/// </summary>
CellCollection(PrimImplikantCollection* &globalPIC)
{
this->init(globalPIC);
this->globalPIC = globalPIC;
this->init();
this->hazardsFound = false;
};
vector<Cell*> cells;
PrimImplikantCollection* globalPIC;
bool hazardsFound;
};
#endif
vector<Cell*> cells; // vector with Cells
PrimImplikantCollection* globalPIC; // a reference to the global PrimImplikantCollection
bool hazardsFound; // whether findHazards() found hazards =)
};

View file

@ -6,30 +6,41 @@
#include "CParser.h"
#include "PrimImplikant.h"
#include "PrimImplikantCollection.h"
#include "Cell.h"
#include "CellCollection.h"
#include "Wertetabelle.h"
#include "KV.h"
using namespace std;
uint dimension = 0; // = variables.size()
uint numElements = 0; // = 2 ^ dimension
bool KNF = false;
bool fileChosen = false;
char fnInput[256];
uint dimension = 0; // number of variables = variables.size()
uint numElements = 0; // number of elements/cells = 2 ^ dimension
bool KNF = false; // Is the output in KNF or DNF. This is only used for output. All calc is done in DNF
bool fileChosen = false; // Whether the input file shall be opened again next time
char fnInput[256]; // The path to the input file
/// <summary>
/// <para>Takes care of opening the input and output file streams.</para>
/// <para>It also asks the user to select the input file using GetOpenFileName</para>
/// </summary>
/// <param name="input">The input file where we will read the data from</param>
/// <param name="error">The parser error log file</param>
/// <param name="list">The parser listing log file</param>
/// <param name="wt">The output file for the Wertetabelle</param>
/// <returns>An error code:
/// - 0, 9: Everything fine
/// - 1: File open error
/// - 2: User aborted GetOpenFileName
/// </returns>
int open_files(ifstream &input, ofstream &error, ofstream &list, ofstream &wt)
{
if (fileChosen == true) // don't reopen files
if (fileChosen == true) // do not reopen files
return 9;
GetCurrentDirectory(sizeof(fnInput), fnInput);
GetCurrentDirectory(sizeof(fnInput), fnInput); // returns the current working directory
if (!error.is_open())
if (!error.is_open()) // if we have not opened the parser error log file before
{
char fnError[256];
char fnError[256]; // create path: .\res\errorParser.txt
strcpy_s(fnError, (string(fnInput) + "\\res\\errorParser.txt").c_str());
error.open(fnError, ofstream::out|ofstream::app);
if (!error.is_open())
@ -38,9 +49,9 @@ int open_files(ifstream &input, ofstream &error, ofstream &list, ofstream &wt)
return 1;
}
}
if (!list.is_open())
if (!list.is_open()) // if we have not opened the parser listing log file before
{
char fnLists[256];
char fnLists[256]; // create path: .\res\listParser.txt
strcpy_s(fnLists, (string(fnInput) + "\\res\\listParser.txt").c_str());
list.open(fnLists, ofstream::out|ofstream::trunc);
if (!list.is_open())
@ -49,9 +60,9 @@ int open_files(ifstream &input, ofstream &error, ofstream &list, ofstream &wt)
return 1;
}
}
if (!wt.is_open())
if (!wt.is_open()) // if we have not opened the Wertetabelle file before
{
char fnWt[256];
char fnWt[256]; // create path: .\res\Wertetabelle.txt
strcpy_s(fnWt, (string(fnInput) + "\\res\\Wertetabelle.txt").c_str());
wt.open(fnWt, ofstream::out|ofstream::trunc);
if (!wt.is_open())
@ -61,134 +72,134 @@ int open_files(ifstream &input, ofstream &error, ofstream &list, ofstream &wt)
}
}
strcpy_s(fnInput, (string(fnInput) + "\\res\\input.txt").c_str());
strcpy_s(fnInput, (string(fnInput) + "\\res\\input.txt").c_str()); // create initial input path: .\res\input.txt
OPENFILENAME ofn;
ZeroMemory(&ofn, sizeof(ofn));
ofn.lStructSize = sizeof(ofn);
ofn.hwndOwner = NULL;
ofn.lpstrFile = fnInput;
ofn.nMaxFile = sizeof(fnInput);
ofn.lpstrFilter = "All\0*.*\0Text\0*.TXT\0";
ofn.nFilterIndex = 1;
ofn.lpstrFileTitle = NULL;
OPENFILENAME ofn; // create OPENFILENAME structure for Windows method
ZeroMemory(&ofn, sizeof(ofn)); // zero everything
ofn.lStructSize = sizeof(ofn); // tell windows the size of the struct
ofn.hwndOwner = NULL; // we do not have a window handle (perhaps GDE does?)
ofn.lpstrFile = fnInput; // input file path
ofn.nMaxFile = sizeof(fnInput); // maximum input file path length
ofn.lpstrFilter = "All\0*.*\0Text\0*.TXT\0";// selection filter
ofn.nFilterIndex = 1; // default selected filter
ofn.lpstrFileTitle = NULL;
ofn.nMaxFileTitle = 0;
ofn.lpstrInitialDir = NULL;
ofn.Flags = OFN_PATHMUSTEXIST | OFN_FILEMUSTEXIST;
if (GetOpenFileName(&ofn) != TRUE)
if (GetOpenFileName(&ofn) != TRUE) // if the user aborted GetOpenFileName or something else went wrong
{
cout << "Auswahl der Inputdatei abgebrochen!";
return 2;
}
fileChosen = true;
fileChosen = true; // do not reload input file next time again
if (input.is_open())
input.close();
input.open(fnInput, ifstream::in);
if (input.is_open()) // if a input file was opened before
input.close(); // close it
input.open(fnInput, ifstream::in); // and then open the new file
if (!input.is_open())
{
perror("Fehler beim Lesen der Inputdatei");
return 1;
}
return 0;
}
void pause()
{
#ifdef DEBUG
system("pause");
#endif
}
/// <summary>
/// <para>The main user function that is called by the GDE.</para>
/// <para>It is running in a global while and performs all calculation.</para>
void user_main(void)
{
ifstream fInput;
ofstream fError, fList, fWt;
KV* kv;
ifstream fInput; // the input file
ofstream fError, fList, fWt; // some output files: parser error, parser listing, Wertetabelle
KV* kv; // pointer to KV class
while(1)
{
switch(open_files(fInput, fError, fList, fWt))
switch(open_files(fInput, fError, fList, fWt)) // try to open the file streams
{
case 1: // some error
case 1: // some error
fileChosen = false;
perror("Error while opening a file (1)");
continue;
case 2: // user aborted
ExitProcess(2);
case 2: // user aborted GetOpenFileName
ExitProcess(2); // we do not tolerate those users! :>
break;
case 9: // same input as before
// We could skip recalculation, but then the GDE is not redrawn (updatescr doesn't help) :/
case 0: // new file opened
case 9: // same input file as before
// We could skip recalculation, but then the GDE is not redrawn (updatescr only doesn't help. And since we are not storing the PrimImplikantCollection without solved Hazards we have to do everything again) :/
case 0: // new file opened
{
cout << endl << endl << endl << endl;
PrimImplikantCollection* globalPIC = new PrimImplikantCollection();
vector<string>* variables = new vector<string>();
PrimImplikantCollection* globalPIC = new PrimImplikantCollection(); // a new collection of PrimImplikants
vector<string>* variables = new vector<string>(); // a collection with the variable names
fInput.clear();
fInput.seekg(0, fInput.beg);
CParser* parser = new CParser(fInput, fError, fList);
int parseFailure = parser->yyparse(globalPIC, variables);
delete parser;
fInput.seekg(0, fInput.beg); // rewind fInput
CParser* parser = new CParser(fInput, fError, fList); // init our parser
int parseFailure = parser->yyparse(globalPIC, variables); // parse the specified file, write data into globalPIC and variables
delete parser; // we do not need it anymore
parser = NULL;
if (parseFailure != 0)
if (parseFailure != 0) // something went wrong
{
fileChosen = false;
string error = "Error while parsing the input (";
fileChosen = false; // let the user select a new file next time
string error = "Error while parsing the input ("; // create a string with the error
char buf[5];
_itoa_s(parseFailure, buf, 10);
error += buf;
error += ")";
perror(error.c_str());
fError << error << endl;
continue;
continue; // start over again
}
// initialize Cells
CellCollection* allCells = new CellCollection(globalPIC);
CellCollection* allCells = new CellCollection(globalPIC); // initialize our Cells collection
fWt.seekp(0, fWt.beg);
fWt.seekp(0, fWt.beg); // rewind fWt
// print Wertetabelle and KV of imported data
Wertetabelle* wt = new Wertetabelle(allCells, variables, fWt);
wt->Print();
Wertetabelle* wt = new Wertetabelle(allCells, variables, fWt); // init Wertetabelle
wt->Print(); // print Wertetabelle to console and fWt
kv = new KV(globalPIC, allCells, 30,variables);
kv->Print(30);
kv = new KV(globalPIC, allCells, 30,variables); // init KV
kv->Print(30); // print KV diagram at offset 30,30
// find and solve Hazards
allCells->findHazards();
allCells->findHazards(); // find and solve Hazards
// this is the actual hazard detection and resolving algorithm
if (allCells->hazardsFound)
// print Wertetabelle and KV of corrected data
wt->Print();
wt->Print(); // print Wertetabelle of corrected data
kv->Print(30 + kv->width() + 30, 30); // Diagramm neben dem vorherigen
kv->Print(30 + kv->width() + 30, 30); // print KV of corrected data
// this KV is next to previous KV
kv->Buttons();
delete wt;
// if we would not recalculate everything we could save this stuff:
delete wt; // but as it is now we do not need it anymore. Let's delete it so it won't take any memory
wt = NULL;
globalPIC->Dispose();
delete globalPIC;
globalPIC->Dispose(); // delete all PrimImplikanten in globalPIC (= all PrimImplikanten)
delete globalPIC; // Dispose() could not be moved to ~destructor since we are using this class at several other points where it get's destroyed again. And we want to keep our PrimImplikanten
globalPIC = NULL;
allCells->Dispose();
allCells->Dispose(); // it's the same with our Cells
delete allCells;
allCells = NULL;
delete variables;
delete variables; // also the variables can be deleted
variables = NULL;
break;}
kv->Buttons(); // Print the GDE buttons and wait for user input
}
}
if (kv->StopProcess())
if (kv->StopProcess()) // user want's to stop us
{
if (kv != NULL)
delete kv;
if (kv != NULL) // delete KV class here, we did need it for the buttons
delete kv;
kv = NULL;
fInput.close();
fList.close();
@ -197,5 +208,9 @@ void user_main(void)
fileChosen = false;
break;
}
if (kv != NULL) // delete KV class here, we did need it for the buttons
delete kv;
kv = NULL;
}
}

View file

@ -6,29 +6,40 @@
#include "Tools.h"
#include "KV.h"
extern uint dimension;
extern uint numElements;
extern bool KNF;
extern bool fileChosen;
extern uint dimension; // number of variables
extern uint numElements; // number of elements/fields
extern bool KNF; // KNF/DNF
extern bool fileChosen; // set false to open a new input file
using namespace std;
/// <summary>
/// Clears the GDE screen and adjusts the drawing area
/// </summary>
void KV::Clear()
{
int ww, hh;
get_windowsize(&ww,&hh);
set_drawarea(ww,hh); // Setzen des Zeichenbereiches
clrscr(); // Clear screen
set_drawarea(ww,hh);
clrscr();
}
/// <summary>
/// Prints a KV diagram at position [offset | offset]
/// </summary>
/// <param name="">The X and Y offset in px </param>
void KV::Print(uint offset)
{
this->Print(offset, offset);
}
/// <summary>
/// Prints a KV diagram at position [offsetX | offsetY]
/// </summary>
/// <param name="offsetX">Free space to the left side in Pixels</param>
/// <param name="offsetY">Free space to the upper side in Pixels</param>
void KV::Print(uint offsetX, uint offsetY)
{
if (this->numVarX == 0 || this->numVarY == 0)
if (this->numVarX == 0 || this->numVarY == 0) // Import failed
return;
this->offsetX = offsetX;
@ -40,46 +51,57 @@ void KV::Print(uint offsetX, uint offsetY)
this->PrintCellValues();
this->PrintPrimImplikanten();
updatescr(); // make this f****** GDE update, does not work everytime :/
updatescr();
}
/// <summary>
/// Returns the width of a KV diagram
/// </summary>
uint KV::width()
{
return this->widthPx;
}
/// <summary>
/// Returns the height of a KV diagram
/// </summary>
uint KV::height()
{
return this->heightPx;
}
/// <summary>
/// <para>Sets the variables VarXY_Length and string_VarXY</para>
/// <para>The variable names are separated by X/Y position. Then the size of the first X row and first Y column is calculated</para>
/// </summary>
void KV::Setstring_Var()
{
this->string_VarY = "";
this->string_VarX = "";
this->string_VarY = "";
for (uint i = 0; i < this->variables->size(); i++)
for (uint i = 0; i < this->variables->size(); i++) // für alle Variablen
{
if (i >= this->numVarY)
if (i >= this->numVarY) // wenn X-Zeile
this->string_VarX += this->variables->at(i) + " ";
else
else // wenn Y-Spalte
this->string_VarY += this->variables->at(i) + " ";
}
this->string_VarX = this->string_VarX.substr(0, this->string_VarX.size()-1);
this->string_VarY = this->string_VarY.substr(0, this->string_VarY.size()-1);
this->string_VarX = this->string_VarX.substr(0, this->string_VarX.size()-1); // letztes Leerzeichen löschen
this->string_VarY = this->string_VarY.substr(0, this->string_VarY.size()-1); // letztes Leerzeichen löschen
// Weitere Initialisierung der restlichen privaten Klassenelemente.
this->VarX_Length = max(this->edgeLength+1, this->string_VarX.size() * 9);
this->VarX_Length = max(this->edgeLength+1, this->string_VarX.size() * 9); // berechnen der Größe. Pro Buchstabe werden 9 Pixel geschätzt.
this->VarY_Length = max(this->edgeLength+1, this->string_VarY.size() * 9);
}
void KV::PrintRaster() // Erstellt die Felder: ▯▯▯
{ // ▯▯▯
// ▯▯▯
this->Line(this->VarY_Length, 0, this->VarY_Length, this->heightPx, BLACK); // first vertical line, one edge shorter
this->Line(0, this->VarX_Length, 0, this->heightPx, BLACK); // second vertical line
for (uint w = 1; w <= this->numFieldX ; w++) // vertical lines. Periodic with (edgeLength + 1)
/// <summary>
/// Generates the skeleton of a KV diagram:
/// ▯▯▯
/// ▯▯▯
/// ▯▯▯
/// </summary>
void KV::PrintRaster()
{
this->Line(0, this->VarX_Length, 0, this->heightPx, BLACK); // first vertical line, one edge shorter
for (uint w = 0; w <= this->numFieldX ; w++) // vertical lines. Periodic with (edgeLength + 1)
{
uint X = w * (this->edgeLength + 1) + VarY_Length; // X position of the line
this->Line(X, 0, X, this->heightPx, BLACK);
@ -87,194 +109,219 @@ void KV::PrintRaster() // Erstellt die Felder: ▯▯▯
this->Line(this->VarY_Length, 0, this->widthPx, 0, BLACK); // first horizontal line, one edge shorter
this->Line(0, this->VarX_Length, this->widthPx, this->VarX_Length, BLACK); // +10 to avoid the strings collision
// second horizontal line
for (uint h = 1; h <= this->numFieldY ; h++) // horizontal lines. Periodic with (edgeLength + 1)
for (uint h = 0; h <= this->numFieldY ; h++) // horizontal lines. Periodic with (edgeLength + 1)
{
uint Y = h * (this->edgeLength + 1) + this->VarX_Length; // Y position of the line
this->Line(0, Y, this->widthPx, Y, BLACK);
}
}
/// <summary>
/// Generates the variable names in the first cell
/// █ ▯▯
/// ▯▯▯
/// ▯▯▯
/// </summary>
void KV::PrintString_Var()
{
char* valueY = (char*)this->string_VarY.c_str();
char* valueX= (char*)this->string_VarX.c_str();
uint x1_valueY = 2; // coordinante of ValueY
uint y1_valueY = this->VarX_Length-16;
uint x_valueX = this->VarY_Length-16; // coordinante of variables in first row (X)
uint y_valueX = this->VarX_Length-12;
uint x1_valueX = this->VarY_Length-16; // coordinante of ValueX
uint y1_valueX = this->VarX_Length-12;
uint x_valueY = 2; // coordinante of variables in first column (Y)
uint y_valueY = this->VarX_Length-16;
this->Text(x1_valueX, y1_valueX, 10, BLACK, WHITE, 90, 0, valueX);
this->Text(x1_valueY, y1_valueY, 10, BLACK, WHITE, 00, 0, valueY);
this->Text(x_valueX, y_valueX, 10, BLACK, WHITE, 90, (char*)this->string_VarX.c_str()); // 90°, Black
this->Text(x_valueY, y_valueY, 10, BLACK, WHITE, 00, (char*)this->string_VarY.c_str()); // 0°, Black
}
void KV::PrintVariables() // Erstellt die Werte der Variablen in der ersten X- und Y-Spalte: ▯ 0 1
{ // 0 ▯▯
// 1 ▯▯
for (uint w = 0; w < this->numFieldX; w++) // horizontal variable text
/// <summary>
/// Generates the variable values in the first row (X) and column (Y)
/// ▯ 0 1
/// 0 ▯▯
/// 1 ▯▯
/// </summary>
void KV::PrintVariables()
{
for (uint w = 0; w < this->numFieldX; w++) // horizontal variable text (X)
{
uint XL = w * (this->edgeLength + 1) + this->VarY_Length;
uint XR = XL + this->edgeLength;
char* value = Tools::BinaryToChars(w ^ (w / 2), this->numVarX); // in Gray und String umwandeln
this->TextBoxBold(XL, 0, XR, this->VarX_Length, 10, BLACK, TRANS, TRANS, SINGLE_LINE|CENTER_ALIGN|BOTTOM_ALIGN, value);
uint XL = w * (this->edgeLength + 1) + this->VarY_Length; // left side = position of cell (see PrintRaster)
uint XR = XL + this->edgeLength; // right side = left side + cell size
uint YT = 0; // upper side = 0 (first row)
uint YB = this->VarX_Length; // lower side = height of first row
char* value = Tools::BinaryToChars(w ^ w/2, this->numVarX); // convert w in Gray and in String
this->TextBoxBold(XL, YT, XR, YB, 10, BLACK, TRANS, TRANS, SINGLE_LINE|CENTER_ALIGN|BOTTOM_ALIGN, value);
delete value;
}
for (uint h = 0; h < this->numFieldY; h++) // vertical variable text
for (uint h = 0; h < this->numFieldY; h++) // vertical variable text (Y)
{
uint YT = h * (this->edgeLength + 1) + this->VarX_Length + 1;
uint YB = YT + this->edgeLength;
char* value = Tools::BinaryToChars(h ^ (h / 2), this->numVarY); // in Gray und String umwandeln
this->TextBoxBold(0, YT, this->VarY_Length-5, YB, 10, BLACK, TRANS, TRANS, SINGLE_LINE|RIGHT_ALIGN|VCENTER_ALIGN, value);
uint XL = 0; // left side = 0 (first column)
uint XR = this->VarY_Length-5; // right side = width of column - offset to border
uint YT = h * (this->edgeLength + 1) + this->VarX_Length + 1; // upper side = position of cell (see PrintRaster)
uint YB = YT + this->edgeLength; // lower side = upper side + cell size
char* value = Tools::BinaryToChars(h ^ (h / 2), this->numVarY); // convert w in Gray and in String
this->TextBoxBold(XL, YT, XR, YB, 10, BLACK, TRANS, TRANS, SINGLE_LINE|RIGHT_ALIGN|VCENTER_ALIGN, value);
delete value;
}
}
void KV::PrintCellValues() // Erstellt die Werte der jeweiligen Zellen: ▯▯▯
{ // ▯ x x
// ▯ x x
for (uint h = 0; h < this->numFieldY; h++) // jede Spalte durchgehen
/// <summary>
/// Generates the values of the inner cells
/// ▯▯▯
/// ▯ x x
/// ▯ x x
/// </summary>
void KV::PrintCellValues()
{
for (uint h = 0; h < this->numFieldY; h++) // für jede Spalte
{
uint YT = h * (this->edgeLength + 1)+ this->VarX_Length; // Y Positionen berechnen
uint YT = h * (this->edgeLength + 1)+ this->VarX_Length; // Y-Positionen berechnen
uint YB = YT + this->edgeLength;
for (uint w = 0; w < this->numFieldX; w++) // jede Zeile durchgehen
for (uint w = 0; w < this->numFieldX; w++) // für jede Zeile
{
uint XL = w * (this->edgeLength + 1) + this->VarY_Length; // X Positionen berechnen
uint XL = w * (this->edgeLength + 1) + this->VarY_Length; // X-Positionen berechnen
uint XR = XL + this->edgeLength;
uint i = ((h^h / 2) << this->numVarX) | (w^w / 2); // w und h müssen getrennt in Gray umgewandelt werden (weil sie so aufgetragen wurden)
// zusammengesetzt ergeben sie dann unsere aktuelle Position
uint i = ((h ^ h/2) << this->numVarX) | (w ^ w/2); // nun muss noch die aktuelle Position berechnet werden
// hierbei werden Y und X getrennt in Gray umgewandelt und dann kombiniert
// Dies sind die Zellnummern:
/*
char* I = new char[(int)(ceil(log10((float)numElements)))+1];
itoa(i, I, 10);
this->TextBox(XL, YT, XR, YB, 10, BLACK, TRANS, TRANS, CENTER, I);
itoa(i, I, 10); // aktuelle Position zu String
this->TextBox(XL, YT, XR, YB, 10, BLACK, TRANS, TRANS, CENTER, I); // schreiben
*/
// Dies sind die Zellwerte:
///*
char* I = new char[2];
_itoa_s(this->allCells->at(i)->value ^ KNF, I, 2, 10);
this->TextBox(XL, YT, XR, YB, 10, BLACK, TRANS, TRANS, CENTER, I);
char* I = new char[2]; // nur ein Charakter
_itoa_s(this->allCells->at(i)->value ^ KNF, I, 2, 10); // value der Zelle XOR KNF in String
this->TextBox(XL, YT, XR, YB, 10, BLACK, TRANS, TRANS, CENTER, I); // schreiben
delete I;
//*/
}
}
}
/// <summary>
/// <para>Generates KV_PiGroups for every PrimImplikant and lets PrintPrimImplikantenGroup() print it</para>
/// <para>We have to use these Groups because we can only draw (and see) 2D images but we need more dimensions to display the Cells next to all their neighbors. Due to this limitation not cells may not be next to all of their neighbors which results in several groups that represent a PrimImplikant</para>
/// </summary>
void KV::PrintPrimImplikanten()
{
srand((uint)time(NULL) ^ rand());
vector<KV_PiGroup*> piGroups;
srand((uint)time(NULL) ^ rand()); // give us some randomity =)
vector<KV_PiGroup*> piGroups; // our vector with groups
for (uint i = 0; i < this->globalPic->size(); i++) // for each PrimImplikant
for (uint i = 0; i < this->globalPic->size(); i++) // for each PrimImplikant, main loop
{
PrimImplikant* currentPI = this->globalPic->at(i);
uint color;
uint color; // define a color for this PrimImplikant
char random;
if (currentPI->name.find("|") != string::npos) // define a color for this PI
if (currentPI->name.find("|") != string::npos) // this PrimImplikant solves a hazard
{
random = -1;
random = -1; // save this fact in random
uint r = rand() % 128 + 128;
uint gb = rand() % 100;
color = RGB(r, gb, gb); // some red color
color = RGB(r, gb, gb); // some red color (r > gb, g == b)
}
else
{
random = rand() % 10;
if (currentPI->elements.size() == 1)
color = GREEN;
else
random = rand() % 10; // get some random number [0;9]
uint r, g, b;
do
{
uint r, g, b;
do
{
r = rand() % 256;
g = rand() % 256;
b = rand() % 256;
}
while (
(r + g + b) / 3 > 200 || // avoid light colors
r > g + b); // avoid red colors
color = RGB(r, g, b);
r = rand() % 256; // get some random colors
g = rand() % 256;
b = rand() % 256;
}
while (
(r + g + b) / 3 > 200 || // but avoid too light colors
r > g + b && (int)abs((int)g - (int)b) < 50); // and also avoid red colors
color = RGB(r, g, b); // these rules are not professional
}
vector<KV_PiEleLoc*>* locations = currentPI->locations();
for (uint j = 0; j < locations->size(); j++) // for each Element in PrimImplikant
vector<KV_PiEleLoc*>* locations = currentPI->locations(); // get XY values for each element in currentPI
for (uint j = 0; j < locations->size(); j++) // for each of these
{
KV_PiEleLoc* currentEl = locations->at(j);
bool foundGroup = false;
for (uint k = 0; k < piGroups.size(); k++) // for each Group/Kuller of this PrimImplikant
for (uint k = 0; k < piGroups.size(); k++) // for each existing Group (Kuller) of this PrimImplikant
{
KV_PiGroup* currentGroup = piGroups[k];
if (currentGroup->LiesNextTo(currentEl))
if (currentGroup->LiesNextTo(currentEl)) // if this element lies next to the Group
{
currentGroup->Add(currentEl); // sort Element into group
foundGroup = true;
foundGroup = true; // we have found an appropriate group
break;
}
} // for each Group
if (foundGroup == false) // element was not added to a group
{
KV_PiGroup* newGroup = new KV_PiGroup();
KV_PiGroup* newGroup = new KV_PiGroup(); // we have to create a new group for this el
newGroup->Add(currentEl);
piGroups.push_back(newGroup);
}
} // for each Element in PrimImplikant
// now we have created all groups for this PrimImplikant
for (uint k = 0; k < piGroups.size(); k++) // for each Group/Kuller of this PrimImplikant
{
this->PrintPrimImplikantenGroup(piGroups[k], random, color); // draw it
delete piGroups[k];
delete piGroups[k]; // and then let's delete it
piGroups[k] = NULL;
}
piGroups.clear();
piGroups.clear(); // clear the group vector
} // for each PrimImplikant
}
// Prints the Kuller of a KV_PiGroup
/// <summary>
/// Prints the KV_PiGroups that PrintPrimImplikanten generated
/// </summary>
/// <param name="group">A pointer to the group that shall be printed</param>
/// <param name="random">Some random number for the rectangle size, or -1 if the PI solves a hazard</param>
/// <param name="color">Some random color for the rectangles</param>
void KV::PrintPrimImplikantenGroup(KV_PiGroup* &group, char random, uint &color)
{
group->MakeCoords(this->edgeLength, this->VarX_Length, this->VarY_Length); // makes X1, X2, Y1, Y2
uint X1 = group->X1;
uint X2 = group->X2;
uint Y1 = group->Y1;
uint Y2 = group->Y2;
uint X1, Y1, X2, Y2; // coordinates for the rectangle of this group
group->MakeCoords(this->edgeLength, this->VarX_Length, this->VarY_Length, &X1, &Y1, &X2, &Y2); // makes X1, X2, Y1, Y2
if (random == -1) // make hazard groups as small as possible
if (random == -1) // make hazard groups as small as possible, but add a little ransom
{
random = rand() % 2;
random = rand() % 2; // [0;1]
X1 += 12 - random;
X2 -= 12 - random;
random = rand() % 2;
random = rand() % 2; // [0;1]
Y1 += 9 - random;
Y2 -= 9 - random;
}
else // make size random, so the groups won't overlap
{
X1 += random;
X2 -= random;
Y1 += random;
Y2 -= random;
X1 += random; // lower upper bound --> smaller
X2 -= random; // higher lower bound --> smaller
Y1 += random; // higher left bound --> smaller
Y2 -= random; // lower right bound --> smaller
}
this->Rechteck(X1, Y1, X2, Y2, color, TRANS);
this->Rectangle(X1, Y1, X2, Y2, color, TRANS);
}
/// <summary>
/// Generates the Buttons to restart and to open a new file and then waits for a mouse click on one of those
/// </summary>
void KV::Buttons()
{
int b, h, x, y;
@ -286,48 +333,104 @@ void KV::Buttons()
updatescr();
while (
!(mouseclick(&x,&y) == 1 && (y > h-40 && y < h-5) && (
(x > b-120 && x < b-5) ||
(x > b-240 && x < b-125)
)))
!(mouseclick(&x,&y) == 1 && // wait for mouse click
(y > h-40 && y < h-5) && ( // if y fits into button
(x > b-120 && x < b-5) || // if x fits into button "Restart"
(x > b-240 && x < b-125) // or x fits into button "Other file"
))) // then end this loop and resume operation
{
printf(".");
if(stopProcess())break;
if(stopProcess())break; // if stop was pressed the loop will also be quit
};
if ((x > b-240 && x < b-125) && (y > h-40 && y < h-5))
if ((x > b-240 && x < b-125) && (y > h-40 && y < h-5)) // if button "Other file" was clicked: tell the main loop
fileChosen = false;
}
/// <summary>
/// Checks whether stopProcess() is true. This is a wrapper for all users of KV class
/// </summary>
bool KV::StopProcess()
{
return (bool)stopProcess();
return stopProcess() == TRUE;
}
/// <summary>
/// Prints a line from [x1,y1] to [x2,y2] adding the global offset
/// </summary>
/// <param name="x1">Left starting point (X)</param>
/// <param name="y1">Upper starting point (Y)</param>
/// <param name="x2">Right ending point (X)</param>
/// <param name="y2">Lower ending point (Y)</param>
/// <param name="color">The color of the line</param>
void KV::Line(uint x1, uint y1, uint x2, uint y2, int color)
{
line(x1 + this->offsetX, y1 + this->offsetY, x2 + this->offsetX, y2 + this->offsetY, color);
}
void KV::Text(uint x, uint y, uint size, int color, int bkcolor, int angle, int align, char* theText)
/// <summary>
/// Prints theText at the specified [x,y] position adding the global offset
/// </summary>
/// <param name="x">Left position where text starts (X)</param>
/// <param name="y">Upper position where text starts (Y)</param>
/// <param name="size">Text size</param>
/// <param name="color">The color of the text</param>
/// <param name="bkcolor">Background color of the text rectangle</param>
/// <param name="angle">Angle to rotate the text</param>
/// <param name="theText">String that shall be printed</param>
void KV::Text(uint x, uint y, uint size, int color, int bkcolor, int angle, char* theText)
{
text(x + this->offsetX, y + this->offsetY, size, color, bkcolor, angle, align, theText);
text(x + this->offsetX, y + this->offsetY, size, color, bkcolor, angle, NULL, theText);
}
/// <summary>
/// Prints a rectangle that containts text adding the global offset
/// </summary>
/// <param name="x1">Left starting point (X)</param>
/// <param name="y1">Upper starting point (Y)</param>
/// <param name="x2">Right ending point (X)</param>
/// <param name="y2">Lower ending point (Y)</param>
/// <param name="size">Text size</param>
/// <param name="ctext">Color of the text</param>
/// <param name="cframe">Color of the border of the textbox</param>
/// <param name="cfill">Background color of the rectangle that makes up the textbox</param>
/// <param name="flags">Some alignment flags</param>
/// <param name="theText">String that shall be printed</param>
void KV::TextBox(uint x1, uint y1, uint x2, uint y2, uint size, int ctext, int cframe, int cfill, int flags, char* theText)
{
textbox(x1 + this->offsetX + 1, y1 + this->offsetY, x2 + this->offsetX + 1, y2 + this->offsetY, size, ctext, cframe, cfill, flags, theText);
}
/// <summary>
/// Prints a rectangle that containts bold text adding the global offset
/// </summary>
/// <param name="x1">Left starting point (X)</param>
/// <param name="y1">Upper starting point (Y)</param>
/// <param name="x2">Right ending point (X)</param>
/// <param name="y2">Lower ending point (Y)</param>
/// <param name="size">Text size</param>
/// <param name="ctext">Color of the text</param>
/// <param name="cframe">Color of the border of the textbox</param>
/// <param name="cfill">Background color of the rectangle that makes up the textbox</param>
/// <param name="flags">Some alignment flags</param>
/// <param name="theText">String that shall be printed</param>
void KV::TextBoxBold(uint x1, uint y1, uint x2, uint y2, uint size, int ctext, int cframe, int cfill, int flags, char* theText)
{
textbox(x1 + this->offsetX + 1, y1 + this->offsetY, x2 + this->offsetX + 1, y2 + this->offsetY, size, ctext, cframe, cfill, flags, theText);
textbox(x1 + this->offsetX + 2, y1 + this->offsetY, x2 + this->offsetX + 2, y2 + this->offsetY, size, ctext, TRANS, TRANSPARENT, flags, theText); // write twice to simulate bold font
}
void KV::Rechteck(uint x1, uint y1, uint x2, uint y2, int cframe, int cfill)
/// <summary>
/// Prints a rectangle at the specified position adding the global offset
/// </summary>
/// <param name="x1">Left starting point (X)</param>
/// <param name="y1">Upper starting point (Y)</param>
/// <param name="x2">Right ending point (X)</param>
/// <param name="y2">Lower ending point (Y)</param>
/// <param name="cframe">Border color</param>
/// <param name="cfill">Background color</param>
void KV::Rectangle(uint x1, uint y1, uint x2, uint y2, int cframe, int cfill)
{
rectangle(x1 + this->offsetX + 1, y1 + this->offsetY + 1, x2 + this->offsetX + 1, y2 + this->offsetY + 1, cframe, cfill);
}

View file

@ -14,39 +14,14 @@ extern bool KNF;
class KV
{
public:
void Print(uint offset); // Ausgabe-Methode, KV-Diagramm an der Position [offset | offset]
void Print(uint offsetX, uint offsetY); // Ausgabe-Methode, KV-Diagramm an der Position [offsetX | offsetY]
uint width(); // Gibt die Breite eines KV-Diagramms zurück (widthPx)
uint height(); // Gibt die Höhe eines KV-Diagramms zurück (heightPx)
void Buttons();
bool StopProcess();
// Konstruktor
KV(PrimImplikantCollection* globalPic, CellCollection* allCells, uint size, vector<string>* &variables)
: edgeLength(size),
numVarX(((uint)floor(dimension / 2.0f))), numVarY(((uint)ceil(dimension / 2.0f))),
numFieldX((uint)pow(2, (float)numVarX)), numFieldY((uint)pow(2, (float)numVarY))
{
this->globalPic = globalPic;
this->allCells = allCells;
this->variables = variables;
Setstring_Var();
this->widthPx = numFieldX * (this->edgeLength + 1) + this->VarY_Length;
this->heightPx = numFieldY * (this->edgeLength + 1) + this->VarX_Length;
this->Clear();
}
private:
PrimImplikantCollection* globalPic;
CellCollection* allCells;
vector<string>* variables;
PrimImplikantCollection* globalPic; // Globale PrimImplikantCollection
CellCollection* allCells; // Alle Zellen
vector<string>* variables; // Variablennamen
uint offsetX; // Der freie Platz nach links in Pixeln
uint offsetY; // Der freie Platz nach rechts in Pixeln
uint offsetX; // Der freie Platz links vom KV-Diagramm in Pixeln
uint offsetY; // Der freie Platz oben vom KV-Diagramm in Pixeln
const uint edgeLength; // Die Kantenlänge der einzelnen Felder
@ -56,31 +31,64 @@ private:
const uint numFieldY; // Wieviele Felder in Y-Richtung gezeichnet werden = pow(2, numVarY)
uint widthPx; // Breite des KV-Diagramms in Pixeln
uint heightPx; // Höhe des KV-Diagramms in Pixeln
uint VarX_Length; // Höhe der Variablen in X-Richtung in Pixeln
uint VarY_Length; // Breite der Variablen in Y-Richtung in Pixeln
string string_VarX; // Variables_String in X-Richtung
string string_VarY; // Variables_String in Y-Richtung
uint VarX_Length; // Höhe der Variablenzeile (oben) in Pixeln
uint VarY_Length; // Breite der Variablenspalte (links) in Pixeln
string string_VarX; // Variablen String oben
string string_VarY; // Variablen String links
void Setstring_Var(); // Einfuegen von String_Varx & String_VarY mit Variables.
void PrintRaster(); // Erstellt die Felder
void PrintVariables(); // Erstellt die Werte der Variablen in der ersten X- und Y-Spalte
void PrintCellValues(); // Erstellt die Werte der jeweiligen Zellen
void Setstring_Var(); // Initialisieren von VarX/Y_Length und string_VarX/Y
void PrintRaster(); // Erstellt die Felder/das Raster
void PrintVariables(); // Erstellt die Werte der Variablen in der ersten Zeile und der ersten Spalte
void PrintCellValues(); // Erstellt die Werte in den jeweiligen Zellen
void PrintPrimImplikanten(); // Generiert die einzelnen PrimImplikanten-Kuller (Gruppen)
void PrintPrimImplikantenGroup(KV_PiGroup* &group, char random, uint &color); // Erstellt die einzelnen PrimImplikanten-Kuller
void PrintString_Var(); // Erstellt den horizontalen TextVariable & vertikalen Textvariable
void PrintPrimImplikantenGroup(KV_PiGroup* &group, char random, uint &color); // Druckt die einzelnen PrimImplikanten-Kuller
void PrintString_Var(); // Erstellt den horizontalen & vertikalen Text mit Variablennamen
void Clear();
void Clear(); // Löscht die GDE
void Line(uint x1, uint y1, uint x2, uint y2, int color); // Zeichnet eine Linie mit Offset
void Text(uint x, uint y, uint size, int color, int bkcolor, int angle, int align, char* theText); // Zeichnet einen Text mit Offset
void KV::TextBox(uint x1, uint y1, uint x2, uint y2, uint size, int ctext, int cframe, int cfill, int flags, char* theText); // Zeichnet eine TextBox mit Offset
void KV::TextBoxBold(uint x1, uint y1, uint x2, uint y2, uint size, int ctext, int cframe, int cfill, int flags, char* theText); // Zeichnet eine TextBox mit Offset und fetter Schrift
void KV::Rechteck(uint x1, uint y1, uint x2, uint y2, int cframe, int cfill); // Zeichnet ein Rechteck mit Offset und fetter Schrift
void Line(uint x1, uint y1, uint x2, uint y2, int color); // Zeichnet eine Linie mit Offset
void Text(uint x, uint y, uint size, int color, int bkcolor, int angle, char* theText); // Zeichnet einen Text mit Offset
void KV::TextBox(uint x1, uint y1, uint x2, uint y2, uint size, int ctext, int cframe, int cfill, int flags, char* theText); // Zeichnet eine TextBox mit Offset
void KV::TextBoxBold(uint x1, uint y1, uint x2, uint y2, uint size, int ctext, int cframe, int cfill, int flags, char* theText); // Zeichnet eine TextBox mit Offset und fetter Schrift
void KV::Rectangle(uint x1, uint y1, uint x2, uint y2, int cframe, int cfill); // Zeichnet ein Rechteck mit Offset
public:
void Print(uint offset); // Ausgabe-Methode, KV-Diagramm an der Position [offset | offset]
void Print(uint offsetX, uint offsetY); // Ausgabe-Methode, KV-Diagramm an der Position [offsetX | offsetY]
uint width(); // Gibt die Breite eines KV-Diagramms zurück (widthPx)
uint height(); // Gibt die Höhe eines KV-Diagramms zurück (heightPx)
void Buttons(); // Zeichnet Buttons und wartet auf user input
bool StopProcess(); // Prüft das stop flag der GDE
/// <summary>
/// Konstruktor von KV
/// </summary>
/// <param name="globalPic">Globale PrimImplikantCollection</param>
/// <param name="allCells">Alle Zellen (CellCollection)</param>
/// <param name="size">Die Kantenlänge eines Feldes (Rastergröße)</param>
/// <param name="variables">Variablennamen</param>
KV(PrimImplikantCollection* globalPic, CellCollection* allCells, uint size, vector<string>* &variables)
: edgeLength(size), // Kantenlänge festlegen
numVarX(((uint)floor(dimension / 2.0f))), // Anzahl der Variablen in X- und Y-Richtung festlegen
numVarY(((uint) ceil(dimension / 2.0f))),
numFieldX((uint)pow(2, (float)numVarX)), // Anzahl der Felder in X- und Y-Richtung festlegen
numFieldY((uint)pow(2, (float)numVarY)) // = 2 ^ numVar
{
this->globalPic = globalPic;
this->allCells = allCells;
this->variables = variables;
this->Setstring_Var(); // Initialisiert VarY_Length und VarX_Length
this->widthPx = numFieldX * (this->edgeLength + 1) + this->VarY_Length; // Breite eines KV-Diagramms
this->heightPx = numFieldY * (this->edgeLength + 1) + this->VarX_Length;// Höhe eines KV-Diagramms
this->Clear(); // GDE löschen
}
char* Binary(uint x, char length); // Wie itoa(x, char[], 2), allerdings mit fester Breite
};
#define CENTER SINGLE_LINE|CENTER_ALIGN|VCENTER_ALIGN
#ifndef CENTER
#define CENTER SINGLE_LINE|CENTER_ALIGN|VCENTER_ALIGN
#endif

View file

@ -7,23 +7,31 @@ using namespace std;
extern uint dimension;
/// <summary>
/// This class saves the X and Y values in a KV diagram for the specified i
/// </summary>
class KV_PiEleLoc
{
public:
uint i;
uint w;
uint h;
/// <summary>
/// Constructor of KV_PiEleLoc
/// </summary>
KV_PiEleLoc(uint &i)
{
const uint numVarX = (uint)floor(dimension / 2.0f);
const uint numVarX = (uint)floor(dimension / 2.0f); // get the number of variables in X direction
this->i = i;
this->w = i & ((0x1 << (numVarX)) - 1); // get x coord
this->w = Tools::GrayToBinary(w);
// we need numVarX ones here
// example: numVarX = 3 --> (0001 << 3) - 1 = 1000 - 1 = 0111
this->w = i & ((0x1 << (numVarX)) - 1); // get x coord out of i (lower numVarX bits)
this->w = Tools::GrayToBinary(w); // convert from gray to binary
this->h = i >> numVarX; // get y coord
this->h = Tools::GrayToBinary(h);
this->h = i >> numVarX; // get y coord out of i (higher bits)
this->h = Tools::GrayToBinary(h); // convert from gray to binary
}
};
};

View file

@ -5,57 +5,77 @@
using namespace std;
/// <summary>
/// <para>Checks whether the specified el lies next to this group (in 2D, not Hamming distance)</para>
/// </summary>
/// <param name="el">The element that shall be checked</param>
bool KV_PiGroup::LiesNextTo(KV_PiEleLoc* &el)
{
for (uint i = 0; i < this->elements.size(); i++)
{
for (uint i = 0; i < this->elements.size(); i++) // for each element in this group
{ // (there should be a better way)
KV_PiEleLoc* elG = this->elements[i];
if (elG->h - el->h == 0 && abs((int)elG->w - (int)el->w) == 1 ||
elG->w - el->w == 0 && abs((int)elG->h - (int)el->h) == 1)
if (elG->h - el->h == 0 && abs((int)elG->w - (int)el->w) == 1 || // if el lies next to elG in X direction
elG->w - el->w == 0 && abs((int)elG->h - (int)el->h) == 1) // or el lies next to elG in Y direction
return true;
}
return false;
}
/// <summary>
/// Add the specified KV_PiElelLoc el to this group
/// </summary>
void KV_PiGroup::Add(KV_PiEleLoc* &el)
{
this->elements.push_back(el);
}
void KV_PiGroup::MakeCoords(uint edgeLength, uint VarX_Length, uint VarY_Length)
/// <summary>
/// Calculate the X and Y coordinates with all elements
/// </summary>
void KV_PiGroup::MakeCoords(uint edgeLength, uint VarX_Length, uint VarY_Length, uint* XX1, uint* YY1, uint* XX2, uint* YY2)
{
uint x1, x2, y1, y2;
uint X1 = -1, X2 = 0, Y1 = -1, Y2 = 0;
KV_PiEleLoc* loc;
for (uint i = 0; i < this->elements.size(); i++)
uint x1, x2, y1, y2; // coords for each single element
uint X1 = -1, X2 = 0, Y1 = -1, Y2 = 0; // resulting group coords with initial maximum/minimum values
for (uint i = 0; i < this->elements.size(); i++) // for all locations in this group
{
loc = this->elements[i];
x1 = loc->w * (edgeLength + 1) + VarY_Length; // Upper coord
x2 = x1 + edgeLength; // Lower coord
y1 = loc->h * (edgeLength + 1) + VarX_Length; // Left coord
y2 = y1 + edgeLength; // Right coord
KV_PiEleLoc* loc = this->elements[i]; // current location
x1 = loc->w * (edgeLength + 1) + VarY_Length; // Upper coord for rectangle around loc
x2 = x1 + edgeLength; // Lower coord for rectangle around loc
y1 = loc->h * (edgeLength + 1) + VarX_Length; // Left coord for rectangle around loc
y2 = y1 + edgeLength; // Right coord for rectangle around loc
X1 = min(X1, x1);
X2 = max(X2, x2);
Y1 = min(Y1, y1);
Y2 = max(Y2, y2);
X1 = min(X1, x1); // Store it if upper coord is higher than previous X1
X2 = max(X2, x2); // Store it if lower coord is lower than previous X2
Y1 = min(Y1, y1); // Store it if left coord is lefter than previous Y1
Y2 = max(Y2, y2); // Store it if right coord is righter than previous Y2
}
this->X1 = X1;
this->X2 = X2;
this->Y1 = Y1;
this->Y2 = Y2;
*XX1 = X1;
*YY1 = Y1;
*XX2 = X2;
*YY2 = Y2;
}
/// <summary>
/// Returns the KV_PiEleLoc at the specified index
/// </summary>
KV_PiEleLoc* KV_PiGroup::operator[](uint &index)
{
return this->elements.at(index);
}
/// <summary>
/// Returns the KV_PiEleLoc at the specified index
/// </summary>
KV_PiEleLoc* KV_PiGroup::at(uint &index)
{
return this->elements.at(index);
}
/// <summary>
/// Returns the size of this KV_PiGroup
/// </summary>
uint KV_PiGroup::size()
{
return this->elements.size();

View file

@ -8,18 +8,19 @@ using namespace std;
extern uint dimension;
/// <summary>
/// This class stores several KV_PiEleLoc objects and thus represents one "Kuller" of the PrimImplikant
/// </summary>
class KV_PiGroup
{
private:
vector<KV_PiEleLoc*> elements;
vector<KV_PiEleLoc*> elements; // locations
public:
bool LiesNextTo(KV_PiEleLoc* &el);
void Add(KV_PiEleLoc* &el);
void MakeCoords(uint edgeLength, uint VarX_Length, uint VarY_Length);
bool LiesNextTo(KV_PiEleLoc* &el); // whether the specified el lies next to this group
void Add(KV_PiEleLoc* &el); // add a location to this group
void MakeCoords(uint edgeLength, uint VarX_Length, uint VarY_Length, uint* X1, uint* Y1, uint* X2, uint* Y2); // Generates the coordinates for this group
KV_PiEleLoc* operator[](uint &index);
KV_PiEleLoc* at(uint &index);
uint size();
uint X1, X2, Y1, Y2;
KV_PiEleLoc* operator[](uint &index); // location at index
KV_PiEleLoc* at(uint &index); // location at index
uint size(); // number of locations
};

View file

@ -7,65 +7,89 @@
using namespace std;
bool PrimImplikant::valueAt(uint pos) {
for (vector<uint>::iterator i = elements.begin(); i < elements.end(); ++i)
if (*i == pos)
return true;
uint PrimImplikant::globalCount = 0;
/// <summary>
/// Checks whether this PrimImplikant covers the specified position
/// </summary>
/// <param name="position">The position that shall be checked</param>
bool PrimImplikant::valueAt(uint position) {
for (vector<uint>::iterator i = elements.begin(); i < elements.end(); ++i) // for each element
if (*i == position) // if it is matched
return true; // this PI covers this position
return false;
}
void PrimImplikant::parser(string input) { // Analyser
/// <summary>
/// Converts the specified input string to a number of elements by replacing a x by 0 and 1 and then calling itself again
/// </summary>
/// <param name="input">The input string from CParser that defines this PrimImplikant</param>
void PrimImplikant::parser(string input) {
uint implikant = 0;
string text0 = "";
string text1 = "";
for (uint i = 0; i < input.size(); i++)
for (uint i = 0; i < input.size(); i++) // for each character
{
char c = input[i];
if (c == 'x' || c == 'X')
char c = input[i]; // can we get a pointer to this char?
if (c == 'x' || c == 'X') // we found an X
{
text0 = input;
text1 = input;
text0[i] = '0';
text1[i] = '1';
parser(text0);
parser(text1);
input[i] = '0'; // replace X by 0 and call parse again
parser(input);
input[i] = '1'; // replace X by 1 and call parse again
parser(input);
return;
}
if (c != '0' && c != '1')
if (c != '0' && c != '1') // if the character is neither X nor 0 nor 1: error!
{
printf("**** FATAL ERROR **** %s is not binary\n", input);
printf("**** FATAL ERROR **** %s is not binary\n", input); // perhaps we should log to error file
return;
}
implikant <<= 1; // *2
implikant += (uint)c - (uint)'0';
implikant <<= 1; // no X found yet
implikant |= (uint)(c - '0'); // convert the string to a number
}
elements.push_back(implikant);
this->elements.push_back(implikant); // add the converted number
}
/// <summary>
/// <para>Sort elements using Tools:compareAsGray. They will be ordered in Gray order ascending</para>
/// <para>algorithm.h uses InsertionSort</para>
/// </summary>
void PrimImplikant::sort()
{
std::sort(this->elements.begin(), this->elements.end(), &PrimImplikant::compareGray);
}
bool PrimImplikant::compareGray(uint a, uint b)
{
return Tools::GrayToBinary(a) < Tools::GrayToBinary(b);
std::sort(this->elements.begin(), this->elements.end(), &Tools::compareAsGray);
}
/// <summary>
/// Creates a KV_PiEleLoc for each _element. Therefore it has to sort elements first (see this->sort()) and then fills _locations
/// </summary>
void PrimImplikant::makeLocations()
{
this->sort();
this->_locations = new vector<KV_PiEleLoc*>();
this->_locations->resize(this->elements.size());
for (uint i = 0; i < this->elements.size(); i++)
<<<<<<< HEAD
this->_locations->at(i) = new KV_PiEleLoc(this->elements[i]); // zu fragen
=======
this->_locations->at(i) = new KV_PiEleLoc(this->elements[i]);
>>>>>>> Added Comments
}
/// <summary>
/// Lazy initialisation of this->_locations
/// </summary>
vector<KV_PiEleLoc*>* PrimImplikant::locations()
{
if (this->_locations == NULL)
this->makeLocations();
return this->_locations;
}
/// <summary>
/// Returns the number of Cells that this PrimImplikant covers
/// </summary>
uint PrimImplikant::size()
{
return this->elements.size();
}

View file

@ -6,53 +6,84 @@
using namespace std;
/// <summary>
/// This class represents a PrimImplikant. It contains a vector with all covered positions/locations
/// <summary>
class PrimImplikant
{
private:
static bool compareGray(uint a, uint b);
void makeLocations();
vector<uint> elements; // The positions this PrimImplikant covers
vector<KV_PiEleLoc*>* _locations; // The XY coordinates in a KV for each position
vector<KV_PiEleLoc*>* _locations;
static uint globalCount; // A counter used for ID generation
public:
string name;
uint id;
vector<uint> elements;
PrimImplikant(string input)
/// <summary>
/// Sets default values for id and _locations
/// </summary>
void init()
{
this->name = input;
this->parser(input);
this->id = PrimImplikant::globalCount++;
this->_locations = NULL;
}
void makeLocations(); // Generates _locations
void parser(string input); // Parses an input string to fill elements
public:
string name; // The name of the PrimImplikant as imported
uint id; // The unique identifier (see ::globalCount)
/// <summary>
/// Sets name and calls this->parser(input)
/// </summary>
/// <param name="input">The imported string that defines this PrimImplikant</param>
PrimImplikant(string input)
{
init();
this->name = input;
this->parser(input);
}
/// <summary>
/// Creates a PrimImplikant that covoers only the specified input position
/// </summary>
/// <param name="input">The imported position</param>
PrimImplikant(uint input)
{
init();
char nameC[sizeof(uint)*8+1];
_itoa_s(input, nameC, sizeof(uint)*8+1, 10);
this->name = nameC;
this->elements.push_back(input);
this->_locations = NULL;
}
/// <summary>
/// <para>Creates a PrimImplikant that covers two positions. This is used to solve detected hazards</para>
/// <para>Beware: No checks are done here, you could easily add a PrimImplikant that cannot exist logically!</para>
/// </summary>
/// <param name="input1">A number</param>
/// <param name="input2">A number which's Hanning distance to input1 is only 1</param>
PrimImplikant(uint input1, uint input2)
{
char nameC[sizeof(uint)*8+1];
_itoa_s(input1, nameC, sizeof(uint)*8+1, 10);
init();
char nameC[sizeof(uint)*8+1]; // generate the name
_itoa_s(input1, nameC, sizeof(uint)*8+1, 10); // convert input1
this->name = nameC;
_itoa_s(input2, nameC, sizeof(uint)*8+1, 10);
this->name.append("|");
this->name.append("|"); // add delimiter
_itoa_s(input2, nameC, sizeof(uint)*8+1, 10); // convert inpiut2
this->name.append(nameC);
this->elements.push_back(input1);
this->elements.push_back(input1); // add both input1 and input2 to elements
this->elements.push_back(input2);
this->_locations = NULL;
}
bool valueAt(uint position);
void parser(string input);
void sort();
vector<KV_PiEleLoc*>* locations();
//vector<uint>* elements(); // returns elements
uint size(); // returns the number of elements in elements
bool valueAt(uint position); // returns whether this PrimImplikant covers the specified position
void sort(); // sort elements as Gray numbers
vector<KV_PiEleLoc*>* locations(); // get the locations of elements in a KV
/// <summary>
/// Deletes all KV_PiLocs and _locations itself
/// </summary>
~PrimImplikant()
{
if (this->_locations)
@ -64,4 +95,11 @@ public:
this->_locations = NULL;
}
}
};
};
#ifndef PRIMIMPLIKANTITERATOR
#define PRIMIMPLIKANTITERATOR
typedef vector<PrimImplikant*>::iterator PrimImplikantIt;
#endif

View file

@ -5,87 +5,129 @@
using namespace std;
uint PrimImplikantCollection::globalCount = 0;
/// <summary>
/// Adds the specified PrimImplikant PI to the collection
/// </summary>
/// <param name="PI">The PrimImplikant that shall be added to the collection</param>
void PrimImplikantCollection::add(PrimImplikant* &PI)
{
PIVector.push_back(PI);
}
/// <summary>
/// Adds a PrimImplikant with the specified input to the collection
/// </summary>
/// <param name="input">The parsed data from CParser out of the input file</param>
void PrimImplikantCollection::add(string input)
{
PrimImplikant* PI = new PrimImplikant(input);
PI->id = PrimImplikantCollection::globalCount++;
this->add(PI);
}
/// <summary>
/// Adds a PrimImplikant with the specified input to the collection
/// </summary>
/// <param name="input">The parsed data from CParser out of the input file</param>
void PrimImplikantCollection::add(uint input)
{
PrimImplikant* PI = new PrimImplikant(input);
PI->id = PrimImplikantCollection::globalCount++;
this->add(PI);
}
/// <summary>
/// <para>Adds a PrimImplikant which covers both input1 and input2.</para>
/// <para>Beware: No checks are done here, you could easily add a PrimImplikant that cannot exist logically!</para>
/// </summary>
/// <param name="input1">Some number</param>
/// <param name="input2">Some other number</param>
void PrimImplikantCollection::add(uint input1, uint input2)
{
PrimImplikant* PI = new PrimImplikant(input1, input2);
PI->id = PrimImplikantCollection::globalCount++;
this->add(PI);
}
/// <summary>
/// Returns whether a PrimImplikant covers the specified position
/// </summary>
/// <param name="position">The position you want to check. It is a normal binary number</param>
/// <returns>True: A PrimImplikant was found. False: No was not found at this position</returns>
bool PrimImplikantCollection::valueAt(uint position)
{
for (vector<PrimImplikant*>::iterator i = PIVector.begin(); i < PIVector.end(); i++)
if ((*i)->valueAt(position))
return true;
return false;
for (PrimImplikantIt i = PIVector.begin(); i < PIVector.end(); i++) // for each PrimImplikant
if ((*i)->valueAt(position)) // if one is true
return true; // the collection is true, too
return false; // nothing found, the collection is false
}
/// <summary>
/// Generates a new PrimImplikantCollection with a subset of the saved PrimImplikants: All those that cover the specified position.
/// </summary>
/// <param name="position">The position. It is a number</param>
/// <returns>A new PrimImplikantCollection with all found PrimImplikants
PrimImplikantCollection PrimImplikantCollection::primImplikantenAt(uint position)
{
PrimImplikantCollection pic;
for (vector<PrimImplikant*>::iterator i = PIVector.begin(); i < PIVector.end(); i++)
if ((*i)->valueAt(position))
pic.add(*i);
for (PrimImplikantIt i = PIVector.begin(); i < PIVector.end(); i++) // for every PrimImplikant
if ((*i)->valueAt(position)) // if it is true
pic.add(*i); // add it to the new collection
return pic;
}
/// <summary>
/// <para>Looks for the specified PrimImplikant foreign in this collection</para>
/// </summary>
/// <returns>True: foreign was found in here and is not foreign. False: foreign is indeed foreign</returns>
bool PrimImplikantCollection::contains(PrimImplikant* foreign)
{
for (vector<PrimImplikant*>::iterator i = PIVector.begin(); i < PIVector.end(); i++)
if ((*i)->id == foreign->id)
return true;
for (PrimImplikantIt i = PIVector.begin(); i < PIVector.end(); i++) // for all PrimImplikants
if ((*i)->id == foreign->id) // if ID matches
return true; // we found it
return false;
}
/// <summary>
/// Returns the number of PrimImplikants in this collection
/// </summary>
uint PrimImplikantCollection::size()
{
return this->PIVector.size();
}
/// <summary>
/// Returns the last added PrimImplikant
/// </summary>
PrimImplikant* PrimImplikantCollection::back()
{
return this->PIVector.back();
}
/// <summary>
/// Returns the first added PrimImplikant
/// </summary>
PrimImplikant* PrimImplikantCollection::front()
{
return this->PIVector.front();
}
PrimImplikant* PrimImplikantCollection::at(uint &index)
/// <summary>
/// Returns the PrimImplikant at the specified index
/// </summary>
PrimImplikant* PrimImplikantCollection::at(const uint &index)
{
return this->PIVector.at(index);
}
PrimImplikant* PrimImplikantCollection::operator[](uint &index){
if (index < PIVector.size())
return this->PIVector.at(index);
return 0;
/// <summary>
/// Returns the PrimImplikant at the specified index
/// </summary>
PrimImplikant* PrimImplikantCollection::operator[](const uint &index){
return this->PIVector.at(index);
}
/// <summary>
/// <para>Deletes all PrimImplikant instances in this collection.</para>
/// <para>Beware: Only do this at the end! All collections are storing pointers to the PrimImplikants and maybe some other object is still using them. Dispose() may only be called by the last instance of this class (which we could check programmatically and then integrate it into the destructor)</para>
/// </summary>
void PrimImplikantCollection::Dispose()
{
for (uint i = 0; i < this->size(); i++)
delete this->at(i);
this->PIVector.clear();
}

View file

@ -5,31 +5,30 @@
#include "PrimImplikant.h"
using namespace std;
extern uint dimension;
extern uint numElements;
extern bool KNF;
class PrimImplikantCollection{
/// <summary>
/// This class contains a vector with pointers to instances of PrimImplikant and also provides some methods to operate on those data
/// </summary>
class PrimImplikantCollection
{
private:
vector<PrimImplikant*> PIVector; // vector with PrimImplikants
public:
void add(PrimImplikant* &PI);
void add(string input);
void add(uint input);
void add(uint input1, uint input2);
void add(PrimImplikant* &PI); // adds the specified PrimImplikant to the collection
void add(string input); // imports the specified input
void add(uint input); // imports the specified input
void add(uint input1, uint input2); // imports the specified input1 and input2
bool valueAt(uint position);
PrimImplikantCollection primImplikantenAt(uint position);
bool contains(PrimImplikant* foreign);
bool valueAt(uint position); // looks for any PrimImplikant that touches the specified position
PrimImplikantCollection primImplikantenAt(uint position); // returns the PrimImplikanten that touch the specified position
bool contains(PrimImplikant* foreign); // looks for the specified PrimImplikant in this colleciton
void Dispose();
void Dispose(); // delete all PrimImplikants in here
uint size();
PrimImplikant* back();
PrimImplikant* front();
PrimImplikant* at(uint &index);
PrimImplikant* operator[](uint &index);
private:
vector<PrimImplikant*> PIVector;
static uint globalCount;
uint size(); // size of vector PIVector
PrimImplikant* back(); // last element of PIVector
PrimImplikant* front(); // first element of PIVector
PrimImplikant* at(const uint &index); // element at specified index of PIVector
PrimImplikant* operator[](const uint &index); // element at specified index of PIVector
};

View file

@ -3,70 +3,105 @@
using namespace std;
extern uint numElements;
extern uint numElements; // 2 ^ dimesion
uint* Tools::GrayToBinaryTable = NULL;
uint Tools::GrayToBinaryTableSize = 0;
// convert the binary representation of x to a string with the specified length
/// <summary>
/// <para>Converts the binary representation of x to a string with the specified length</para>
/// <para>The difference to itoa() is the fixed length</para>
/// <summary>
/// <param name="x">The number that shall be converted</param>
/// <param name="length">The length of the char[] (= number of variables)</param>
/// <returns>A pointer to a new char[]</returns>
char* Tools::BinaryToChars(uint x, char length)
{
// warning: this breaks for numbers with more than 64 bits (= variables)
char* c = new char[length+1];
c += length; // last char
char* c = new char[length+1]; // allocate memory
c += length; // point to last char (at length + 1 - 1)
*c = 0;
*c = 0; // '\0'
do
{
*--c = '0' + (x & 1); // 0 or 1 at the specified position
x >>= 1;
*--c = '0' + (x & 1); // 0 or 1 at the specified position, convert to char
x >>= 1; // next position
} while (--length);
return c;
return c; // return char[] now pointing to the beginning again
}
/// <summary>
/// <para>Converts the specified number x from gray back to binary</para>
/// <para>To boost the performance it inits a lookup table on first run. When the number of variables changes (different input file) it changes the size of the lookup table, too. This could be done a little more efficient.
/// </summary>
uint Tools::GrayToBinary(uint x)
{
if (Tools::GrayToBinaryTableSize < numElements && Tools::GrayToBinaryTable != NULL)
if (Tools::GrayToBinaryTableSize < numElements && Tools::GrayToBinaryTable != NULL) // number of variables was increased
{
delete[] Tools::GrayToBinaryTable;
Tools::InitGrayToBinaryTable();
delete[] Tools::GrayToBinaryTable; // delete old table
Tools::InitGrayToBinaryTable(); // make new table. It would be better to increase the allocated amount of memory
}
else if (Tools::GrayToBinaryTable == NULL)
Tools::InitGrayToBinaryTable();
else if (Tools::GrayToBinaryTable == NULL) // no table existed
Tools::InitGrayToBinaryTable(); // make new table
return Tools::GrayToBinaryTable[x];
return Tools::GrayToBinaryTable[x]; // do the lookup
}
/// <summary>
/// Allocates memory for the GrayToBinaryTable and sets its values
/// </summary>
void Tools::InitGrayToBinaryTable()
{
Tools::GrayToBinaryTable = new uint[numElements];
Tools::GrayToBinaryTableSize = numElements;
for (uint i = 0; i < numElements; i++)
Tools::GrayToBinaryTable[i] = Tools::CalcGrayToBinary(i);
Tools::GrayToBinaryTable = new uint[numElements]; // make uint[]
Tools::GrayToBinaryTableSize = numElements; // save size to detect changes
for (uint i = 0; i < numElements; i++) // for all possible numbers
Tools::GrayToBinaryTable[i] = Tools::ConvertGrayToBinary(i); // convert gray to binary
}
// converts a gray number to its binary representation
uint Tools::CalcGrayToBinary(uint x)
/// <summary>
/// <para>Converts a gray number to its binary representation by converting to gray a special number of times.</para>
/// <para>31 is the maximum number of loops because uint only has 32 bits and works for every x. Calculation of r on the base of x is more efficient).
/// </summary>
/// <returns>The binary number that is associated with the gray x</returns>
uint Tools::ConvertGrayToBinary(uint x)
{
uint x1 = x;
char r = 0; // r = ceil(ld(x))
do
r++;
while (x1 >>= 1);
if ((r & (r-1)) != 0) // keine Potenz von 2
{
char r1 = 0; // r1 = ceil(ld(r))
char r = 0; // r shall contain the position of the first positive bit + 1 in x
do // do while --> ceil. while do --> floor.
r++;
while (x1 >>= 1); // r = ceil(ld(x))
// r = 0 | x = 3 r = 0 | x = 5
// 1 | 011 1 | 101
// 2 | 001 2 | 010
// 3 | 000 3 | 001
// 4 | 000
if ((r & (r-1)) != 0) // if r is no multiple of 2 <-- 100 & 011 = 000 == 0 101 & 100 = 100 != 0
{ // we need to round r up to the next multiple of 2. Let's use same algorithm as above.
char r1 = 0; // r1 shall contain the position of the first positive bit + 1 in r
do
r1++;
while (r >>= 1);
while (r >>= 1); // r1 = ceil(ld(r))
r = 1 << r1; // aufrunden auf Zweierpotenz
r = 1 << r1; // r = 2^(ceil(ld(r))) > 2^(ld(r)) (== r)
}
for (char i = 1; i < r; i++) // Umwandeln von Gray in Binary
for (char i = 1; i < r; i++) // do gray conversion r times --> binary. Do gray conversion r+1 times --> gray again
x ^= x / 2;
return x;
}
/// <summary>
/// Compare to gray numbers. Since computers can only compare binary numbers we have to convert them first
/// </summary>
/// <param name="a">Number that InsertionSort is processing (and that may be repositioned)</param>
/// <param name="b">Number that a is compared to (precendants of a)</param>
/// <returns>True: a should be positioned in front of b</returns>
bool Tools::compareAsGray(uint a, uint b)
{
return Tools::GrayToBinary(a) < Tools::GrayToBinary(b);
}

View file

@ -1,14 +1,19 @@
#pragma once
/// <summary>
/// This is a static class that provides some methods that could be used anywhere
/// </summary>
class Tools
{
public:
static char* Tools::BinaryToChars(uint x, char length);
static char* Tools::BinaryToChars(uint x, char length); // convert a number to a string in it's binary representation
static uint GrayToBinary(uint x);
static uint GrayToBinary(uint x); // convert a gray number back to binary using a lookup table
static bool compareAsGray(uint a, uint b); // compary towo gray numbers (convert it first)
private:
static void InitGrayToBinaryTable();
static uint* GrayToBinaryTable;
static uint GrayToBinaryTableSize;
static uint Tools::CalcGrayToBinary(uint x);
static uint* GrayToBinaryTable; // gray to binary lookup table
static uint GrayToBinaryTableSize; // size of GrayToBinaryTable
static void InitGrayToBinaryTable(); // init GrayToBinaryTable
static uint Tools::ConvertGrayToBinary(uint x); // convert a gray number back to binary
};

View file

@ -13,95 +13,109 @@ extern uint dimension;
extern uint numElements;
extern bool KNF;
/// <summary>
/// Prints the complete truth table
/// </summary>
void Wertetabelle::Print()
{
printHeader();
this->makeHeader();
this->printHeader(); // print the header lines
ushort w = (ushort)ceil(log10((float)numElements)); // calculate width of decimal maximum number
int w = (uint)ceil(log10((float)numElements));
for (uint i = 0; i < numElements; i++)
{
cout << "| "; // => |
cout << setfill(' ') << setw(w) << i; // => 4
cout << setfill(' ') << setw(w) << i; // => 5
cout << " |"; // => |
*fot << "| "; // => |
*fot << setfill(' ') << setw(w) << i; // => 4
*fot << " |"; // => |
this->printI(i); // => 0 1 0 0
*fot << "| ";
*fot << setfill(' ') << setw(w) << i;
*fot << " |";
this->printI(i); // => 0 1 0 1
cout << "| "; // => |
cout << ((*this->cells)[i]->value ^ KNF); // => 1
cout << " |"; // => |
*fot << "| "; // => |
*fot << ((*this->cells)[i]->value ^ KNF); // => 1
*fot << " |"; // => |
this->printPrimImplikanten(i); // => 0 0x1 4
cout << endl; // ==> | 4 | 0 1 0 0 | 1 | 0 0x1 4
*fot << endl; // ==> | 4 | 0 1 0 0 | 1 | 0 0x1 4
*fot << "| ";
*fot << ((*this->cells)[i]->value ^ KNF);
*fot << " |";
this->printPrimImplikanten(i); // => 0 x01 5|3
cout << endl; // ==> | 5 | 0 1 0 1 | 1 | 0 x01 5|3
*fot << endl;
if (i > 0 && i % 31 == 0 && numElements - i > 5) // reprint header so you dont have to scroll
printHeader();
if (i > 0 && i % 31 == 0 && numElements - i > 5) // reprint header so you do not have to scroll
this->printHeader();
}
cout << string(this->width, '-') << endl;
*fot << string(this->width, '-') << endl;
}
string Wertetabelle::makeHeader()
/// <summary>
/// Generates the header line of the truth table with the variable names
/// </summary>
void Wertetabelle::makeHeader()
{
bool setPad = padding.size() == 0;
ushort w = (ushort)ceil(log10((float)numElements)); // calculate width of decimal maximum number
this->header = "|" + string(w + 2, ' ') + "|"; // spare out line number
string row2 = "|" + string((uint)ceil(log10((float)numElements)) + 2, ' ') + "|";
for (vector<string>::iterator v = variables->begin(); v < variables->end(); v++)
for (vector<string>::iterator v = variables->begin(); v < variables->end(); v++) // for each variable
{
row2 += " " + *v;
if (setPad)
padding.push_back((v->size()-1) / 2.0f);
this->header += " " + *v; // add variable name to string
padding.push_back((v->size()-1) / 2.0f); // calculate the padding (spaces left & right) depending on string length
}
row2 += " | y |";
this->header += " | y |"; // output variable
this->width = row2.size();
this->width = this->header.size(); // set global with of truth table (for horizontal lines)
row2 += " PrimImplikanten";
return row2;
this->header += " PrimImplikanten"; // add header for PIs
}
/// <summary>
/// Print the header lines
/// </summary>
void Wertetabelle::printHeader()
{
string row2 = this->makeHeader();
{
cout << string(this->width, '-') << endl; // repeat '-' several times => ---------------------
cout << row2 << endl; // print header row => | a bärchen c d | y | PrimtImpl.
cout << this->header << endl; // print header row => | a bärchen c d | y | PrimtImpl.
cout << string(this->width, '-') << endl; // repeat '-' several times => ---------------------
*fot << string(this->width, '-') << endl; // repeat '-' several times => ---------------------
*fot << row2 << endl; // print header row => | a bärchen c d | y | PrimtImpl.
*fot << string(this->width, '-') << endl; // repeat '-' several times => ---------------------
*fot << string(this->width, '-') << endl;
*fot << this->header << endl;
*fot << string(this->width, '-') << endl;
}
/// <summary>
/// <para>Print the binary repesentation of i</para>
/// <para>This method also takes care of the padding around the single bits (depending on the length of their variable names)</para>
/// </summary>
void Wertetabelle::printI(uint i)
{
string row = " ";
for (int j = dimension - 1; j >= 0; j--) // Variablen rückwärts durchlaufen (s.u.)
for (int j = dimension - 1; j >= 0; j--) // iterate variables backwards for shifting i rightwards
{
char iAtJ = (i & 0x1) + '0'; // Maskierung (aktuelle Stelle j, die ausgegeben wird)
i >>= 1; // Schieben für nächstes Mal
// ' ' + Padding left (' ') + 1 | 0 + Padding right (' ') + row
char iAtJ = (i & 0x1) + '0'; // masking current bit (position j is being printed) and converting to char
i >>= 1; // Shift right for next round
// ' ' + Padding left (' ') + 1 | 0 + Padding right (' ') + row
row = string((uint)ceil(padding[j]) + 1, ' ') + iAtJ + string((uint)floor(padding[j]), ' ') + row;
}
cout << row;
*fot << row;
}
/// <summary>
/// Prints the names of all PrimImplikants at the current position
/// </summary>
void Wertetabelle::printPrimImplikanten(uint i)
{
cout << ' ';
*fot << ' ';
Cell* cell = cells->at(i);
Cell* cell = cells->at(i); // get current Cell
for (uint pi = 0; pi < cell->primImplikanten.size(); pi++) // for every PrimImplikant in Cell
for (uint pi = 0; pi < cell->primImplikanten.size(); pi++) // for each PrimImplikant in Cell
{
cout << cell->primImplikanten[pi]->name << " ";
*fot << cell->primImplikanten[pi]->name << " ";
cout << ' ' << cell->primImplikanten[pi]->name; // print name
*fot << ' ' << cell->primImplikanten[pi]->name;
}
}

View file

@ -10,32 +10,34 @@
using namespace std;
#ifndef WERTETABELLE
#define WERTETABELLE
/// <summary>
/// This class is responsible for the printing of truth tables to cout and the output file
/// </summary>
class Wertetabelle
{
public:
void Print();
void Print(); // print the complete truth table
/// <summary>
/// Constructor of Wertetabelle
/// </summary>
Wertetabelle(CellCollection* cells, vector<string>* variables, ofstream &fWt)
{
this->cells = cells;
this->cells = cells; // store a reference to allCells (thus we will get all changes)
this->variables = variables;
this->fot = &fWt;
}
private:
string makeHeader();
void printHeader();
void printI(uint i);
void printPrimImplikanten(uint i);
void makeHeader(); // Generates the header lines
void printHeader(); // Prints the header lines
void printI(uint i); // Prints the binary representation of the specified i in table format
void printPrimImplikanten(uint i); // Print all PrimImplikants that cover the specified position i
CellCollection* cells;
vector<string>* variables;
vector<float> padding;
uint width;
ofstream* fot;
};
#endif
CellCollection* cells; // all cells
vector<string>* variables; // variable names
vector<float> padding; // padding depending on length of variable names
uint width; // with of truth table
ofstream* fot; // output file stream
string header; // header line
};