Commit 30c4159e by Szeberényi Imre

Genetika

parents
#
# Egyszerű makefile (GNU)
# Feltételezi, hogy minden forrás fugg minden headertől
#
CCX = g++
CXXFLAGS = -std=c++11 -Wall -Werror -Wdeprecated -pedantic -DMEMTRACE -g
TARGET := genetika_teszt
HEADERS := $(wildcard *.h) $(wildcard *.hpp)
SOURCES := $(wildcard *.cpp)
OBJECTS := $(SOURCES:%.cpp=%.o)
$(TARGET): $(OBJECTS)
$(CCX) $^ -g -o $@ -ldl
%.o: %.c $(HEADERS)
$(CCX) $(CXXFLAGS) -c $<
clean:
rm -rf $(OBJECTS) genetika_teszt
\ No newline at end of file
# Egy kis genetika
**Szorgalmi feladat Karsa Zoltántól**. (extra pont: 2)
# Egy kis genetika
Genetikai kódunkat a következő 4 bázis alkotja:
* Adenin (A)
* Citozin (C)
* Guanin (G)
* Timin (T)
A genetikai vizsgálatunkhoz egy olyan programot kell írni, ami egy előre meghatározott leírásból (továbbiakban konfiguráció) képes létrehozni egy állapotgépet és egy DNS lánc elemzését el tudja végezni a konfiguráció alapján.
## Emlékeztető
Emlékezz vissza a Programozás alapjai 1 illetve a Digitális technikák tárgyon használt állapotgépekre (véges automaták), mire voltak elegendőek? Hogyan működtek?
A korábbi tantárgyakkal ellentétben itt az egyes állapotátmeneteknél nem lesz elvégzendő tevékenység (pl.: ly számláló esetén a számláló növelése, ha ly-t találtunk), hanem lesznek érvényes, "elfogadó" állapotok, azaz miután a bemenet elfogyott, és ebben az állapotban (vagy állapotokban) van az automata, elfogadunk, a bemenet jó volt, különben nem. Ezzel gyakorlatilag a véges automaták matematikai modelljéhez jutunk (Bővebben majd algoritmuselmélet tárgyon). Emiatt a korábban megismert ly számláló mását (pl. AC számláló) nem lehet megvalósítani, csak azt tudjuk eldönteni hogy van-e benne AC szakasz, vagy van-e benne 3db AC szakasz, számlálni nem lehet.
## Konfiguráció
Konfigurációs fájl első sora az állapotok számát kódolja (N), a következő N sorban, soronként az állapotok típusa (elfogadó - I, nem elfogadó - H) és az állapotok nevei (max 20 karakter) találhatóak, szóközzel elválasztva. Az első megadott állapot a felsorolásban a kezdőállapot. Ezután az állapotátmeneteket tartalmazó NxN-es mátrix következik a következő formában (a fejléc és az első oszlop nem része a konfigurációnak):
Állapotok | A_1 | A_2 | ... | A_N |
--- | --- | --- | --- |--- |
A_1 | A_1->A_1 | A_1->A_2 | ... | A_1->A_N |
A_2 | A_2->A_1 | A_2->A_2 | ... | A_2->A_N |
... | ... | ... | ... | ... |
A_N | A_N->A_1 | A_N->A_2 | ... | A_N->A_N |
Az első sor (A_1-hez tartozó) a mátrixban az első állapotból induló átmeneteket mutatja az előző felsorolás sorrendjében, mely bemeneti bázis esetén mely állapotba kerül onnan az automata. A mátrix 2. (A_2) sorában és 3. (A_3) oszlopában találhatóak azon bázisok, melyek hatására a 2. állapotból a 3.-ba kell kerüljön az automata... A celábban a bázisok a rövidítésekkel vannak feltüntetve elválasztó jelek nélkül (pl. CAT), a mátrix soraiban több és eltérő db szóköz gondoskodik a szeparálásról. Ha valahol nincs átmenet, ott nulla ('0') szerepel.
Beolvasáshoz ajánlott a `std::ifstream` használata, hasonlóan használható, mint az `std::cin`, azaz `>>`-val történő beolvaásákor eldobja a felesleges whitespace-eket.
Minden egyes sorban pontosan egyszer fordulhatnak elő valahol az ACGT betűk, így nem lehet olyan, hogy egy állapotból több állapotba is tudnánk menni egy bázis hatására vagy nem tudnánk eldönteni hova kellene lépni (= az automata determinisztikus és teljes).
## Skeleton program
A beadáshoz készetettem egy testprogramot (*genetika_teszt*.cpp) és megadtam, hogy az **Allapotgep** osztály miyen publikus interfésszel rendelkezik
(*allapotgep.h*):
```c++
// A bázisokhoz tartozó enum.
enum Bazis {
Adenin, Citozin, Guanin, Timin
};
// Állapotgép publikis interfésze
class Allapotgep {
public:
//konfig fájl beolvasása, ha a fájl nem létezik/nem lehet megnyitni eldobja a NEPTUN-kódot
//újra felépíti az állapotgépet, a korábbit törli ha volt
void konfigural(const char* fajlnev);
//visszaadja melyik állapot aktív
const char* aktualisallapot();
//éppen elfogadó állapotban van az állapotgép
bool elfogad();
//beérkező bázis hatására, mi történjen
void atmenet(Bazis b);
//a lánc feldolgozás után elfogadunk-e, nem áll vissza alaphelyzetbe
bool feldolgoz(Bazis *b, int n);
//visszaállítás a kezdő állapotba
void alaphelyzet();
};
```
Két globális függvényt is készítettem az enum kezeléséhez (`cast`-`cast`), ami a `char -> Bazis` és `Bazis -> char` konverziót segíti elő.
A megolshoz az **Allapotgep** belső logikája, mezői szabadon megváltoztathatóak, a publikus interfész azonben nem változtatható és nem bővíthető. Új osztályok azonban szabadon felvehetők az `allapothep.h` fájlba. Tipikusan legalább még 1-2 osztály felvétele szükséges a szép megoldáshoz. Az osztályok tagfüggvényeit `allapotgep.cpp` fájlban kell megvalósítani.
A `konfigural(const char* fajlnev)` függvény kivételt dob, ha a fájlt nem lehet megnyitni, a kivétel során a neptun kódodat kell eldobni. A konfiguráció minden esetben a fenti leírásnak megfelelő, más hibakezelést nem kell támogatni.
## Példa
A konfigurációs fájl:
```
2
I ParosTimin
H ParatlanTimin
ACG T
T ACG
```
Ezen fájlhoz tartozó állapotgép diagramja:
![állapotgép](statechart.png)
Példa bemenet: `{Adenin, Guanin, Timin, Citozin, Citozin, Timin}`, ekkor elfogadunk. Ezen bemenet végeztével az `aktualisallapot()` függvény `ParosTimin` karakterláncot adja vissza.
## Megoldás
A Git tárolóból letölthető [https://git.ik.bme.hu/Prog2/szorgalmi_feladat/genetike](https://git.ik.bme.hu/Prog2/szorgalmi_feladat/genetika)
fájlok felhasználásával hozzon létre a lokális fejlesztőkörnyezetében egy C++ projektet! Ehhez felhasználhatja a *Makefile* -t, amiben megtalálja a fordítási opciókat. Tervezzen, fejlesszen, teszteljen, majd adja tölse fel a megoldását a Jporta rendszerbe!
## Beadás
Beadandó az `allapotgep.cpp` és `allapotgep.h`, a genetika_teszt.cpp kell beadni, az a teszteléshez van. A Jporta nagyon hasonló módon fog tesztelni.
\ No newline at end of file
/**
* \file allapotgep.cpp
*
* Ebben a fájlban kell megvalósítania az Allapotgép osztány
* metódusait, valamint mindazon további osztályokat, melyek szükségesek
* a feladat megvalósításához.
*
* Ezt a fájlt be kell adni (fel kell tölteni) a megoldással.
*/
#include <iostream>
#include <fstream>
#include "allapotgep.h"
#include "memtrace.h"
/**
* \file allapotgep.h
*
* Ebben a fájlban találja az Allapotgép osztály kezdeti definicióját
* és két segédfüggvényt.
*
* A fájlt tetszés szerint múdosíthatja, azzal a megkütéssel, hogy
* nem hozhat létre globális függvényt és nem változtathatja az Allapotgép osztáy
* publikus interfészét.
*
* Új osztályokat, típusokat felvehet
*
* Ezt a fájlt be kell adni (fel kell tölteni) a megoldással.
*/
#ifndef ALLAPOTGEP_H
#define ALLAPOTGEP_H
#include <ctype.h>
#include <cstring>
#include <iostream>
#include <exception>
#include "memtrace.h"
/**
* Bázisok
*/
enum Bazis {
Adenin, Citozin, Guanin, Timin
};
/**
* Állapotgép publikus interfésze
* A privát részt szabadon változtathatja, de a publikus részt
* ne változtassa, ne bővítse!
*/
class Allapotgep {
public:
//visszaadja melyik állapot aktív
const char* aktualisallapot();
//éppen elfogadó állapotban van az állapotgép
bool elfogad();
//beérkező bázis hatására, mi történjen
void atmenet(Bazis b);
//a lánc feldolgozás után elfogadunk-e
bool feldolgoz(Bazis *b, int n);
//konfig fájl beolvasása
void konfigural(const char* fajlnev);
//visszaállítás a kezdő állapotba
void alaphelyzet();
~Allapotgep();
};
/**
* Segédfüggvény, karakterből enummá konvertál
* @param: b - bázis 1 betűs jele
* @return: Bazis enum kontans
*/
inline Bazis cast(char b) {
char k = tolower(b);
Bazis ret;
switch(k) {
case 'a': ret = Adenin; break;
case 'c': ret = Citozin; break;
case 'g': ret = Guanin; break;
case 't': ret = Timin; break;
default: throw "Format!!"; break;
}
return ret;
}
/**
* Segédfüggvény, Bazis konstansból karakterré konvertál
* @param: b - bazis enmu konstansa
* @param: upper - nagybetűs legyen-e
* @return: bázis 1 betűs jele
*/
inline char cast(Bazis b, bool upper = true) {
char ret = '0';
switch (b)
{
case Adenin: ret = 'a'; break;
case Citozin: ret = 'c'; break;
case Guanin: ret = 'g'; break;
case Timin: ret = 't'; break;
}
if(upper)
ret = toupper(ret);
return ret;
}
#endif
/**
* \file genetika_teszt.cpp
*
* Genetika nevű szorgalmi feladat tesztjei gtest_lite eszközkészletével megvalósítva.
* A szorgalmi feladat megoldásához ezt az állományt nem kell beadni (feltölteni).
*
* A ELKESZULT makró vezérli az egyes tesztesetek fordítását, ezzel lehetővé válik
* hogy kisebb lépésekben teszteljünk.
* Kezdetben ez 0, azaz nem tesztel semmit!
*
*/
#include <iostream>
#include "gtest_lite.h"
#include "allapotgep.h"
#include "memtrace.h"
#define ELKESZULT 0
int main() {
GTINIT(std::cin); // Csak C(J)PORTA működéséhez kell
#if ELKESZULT > 0
/// Azt vizsgálja, hogy dob-e hibát a fájl megnyitásakor
TEST(Konfig, KonfigHiba) {
Allapotgep gep;
try {
EXPECT_THROW_THROW(gep.konfigural("nincs_ilyen_fajl"), const char* p);
} catch (const char *p) {
#ifdef CPORTA
EXPECT_ENVCASEEQ("ORG_ID", p);
#endif
}
} END
#endif // ELKESZULT > 0
#if ELKESZULT > 1
/// Azt vizsgálja, hogy be tudja-e olvasni a konfiguráiós fájlt
TEST(ParosTrimin, fajbolkonfig1) {
Allapotgep gep;
ASSERT_NO_THROW(gep.konfigural("paros.txt"));
EXPECT_STREQ("ParosTimin", gep.aktualisallapot());
} END
#endif // ELKESZULT > 1
#if ELKESZULT > 1
/// Kipróbálja az egyik pédakonfigot
TEST(ParosTrimin, fajbolkonfig1) {
Allapotgep gep;
ASSERT_NO_THROW(gep.konfigural("paros.txt"));
EXPECT_STREQ("ParosTimin", gep.aktualisallapot());
Bazis demo[] = {Timin, Citozin, Guanin, Adenin, Timin};
EXPECT_EQ(true, gep.feldolgoz(demo, 5));
gep.alaphelyzet();
EXPECT_STREQ("ParosTimin", gep.aktualisallapot());
EXPECT_EQ(true, gep.elfogad());
EXPECT_EQ(false, gep.feldolgoz(demo, 4));
} END
#endif
#if ELKESZULT > 2
/// Kipróbálja az másik pédakonfigot
TEST(Implikacio: AA->CC, fajbolkonfig2) {
Allapotgep gep;
ASSERT_NO_THROW(gep.konfigural("implikacio.txt"));
EXPECT_STREQ("Alap", gep.aktualisallapot());
Bazis demo[] = {Adenin, Adenin, Timin, Citozin, Adenin, Citozin, Citozin, Guanin};
EXPECT_EQ(true, gep.feldolgoz(demo, 8));
gep.alaphelyzet();
gep.atmenet(Citozin);
EXPECT_STREQ("C1", gep.aktualisallapot());
gep.atmenet(Adenin);
gep.atmenet(Timin);
EXPECT_STREQ("A1", gep.aktualisallapot());
Bazis test[] = {Citozin, Citozin, Timin, Adenin, Guanin, Citozin};
gep.feldolgoz(test, 6);
EXPECT_STREQ("C2", gep.aktualisallapot());
} END
#endif
/// Itt a vége
if (ELKESZULT < 3)
ADD_FAILURE() << "\nNem futott minden testeset!" << std::endl;
GTEND(std::cerr); // Csak C(J)PORTA működéséhez kell
return 0;
}
This diff is collapsed. Click to expand it.
7
I Alap
I A1
H A2
H C'1
I C'2
I C1
I C2
TG A 0 0 0 C 0
0 TG A 0 0 C 0
0 0 TGA C 0 0 0
0 0 A TG C 0 0
0 0 0 0 ACGT 0 0
0 A 0 0 0 TG C
0 0 0 0 0 0 ACGT
This diff is collapsed. Click to expand it.
/*********************************
Memoriaszivargas-detektor
Keszitette: Peregi Tamas, BME IIT, 2011
petamas@iit.bme.hu
Kanari: Szeberenyi Imre, 2013.,
VS 2012: Szeberényi Imre, 2015.,
mem_dump: 2016.
inclue-ok: 2017., 2018. 2019.
*********************************/
#ifndef MEMTRACE_H
#define MEMTRACE_H
#if defined(MEMTRACE)
/*ha definiálva van, akkor a hibakat ebbe a fajlba írja, egyébkent stderr-re*/
/*#define MEMTRACE_ERRFILE MEMTRACE.ERR*/
/*ha definialva van, akkor futas kozben lancolt listat epit. Javasolt a hasznalata*/
#define MEMTRACE_TO_MEMORY
/*ha definialva van, akkor futas kozben fajlba irja a foglalasokat*/
/*ekkor nincs ellenorzes, csak naplozas*/
/*#define MEMTRACE_TO_FILE*/
/*ha definialva van, akkor a megallaskor automatikus riport keszul */
#define MEMTRACE_AUTO
/*ha definialva van, akkor malloc()/calloc()/realloc()/free() kovetve lesz*/
#define MEMTRACE_C
#ifdef MEMTRACE_C
/*ha definialva van, akkor free(NULL) nem okoz hibat*/
#define ALLOW_FREE_NULL
#endif
#ifdef __cplusplus
/*ha definialva van, akkor new/delete/new[]/delete[] kovetve lesz*/
#define MEMTRACE_CPP
#endif
#if defined(__cplusplus) && defined(MEMTRACE_TO_MEMORY)
/*ha definialva van, akkor atexit helyett objektumot hasznal*/
/*ajanlott bekapcsolni*/
#define USE_ATEXIT_OBJECT
#endif
/******************************************/
/* INNEN NE MODOSITSD */
/******************************************/
#ifdef NO_MEMTRACE_TO_FILE
#undef MEMTRACE_TO_FILE
#endif
#ifdef NO_MEMTRACE_TO_MEMORY
#undef MEMTRACE_TO_MEMORY
#endif
#ifndef MEMTRACE_AUTO
#undef USE_ATEXIT_OBJECT
#endif
#ifdef __cplusplus
#define START_NAMESPACE namespace memtrace {
#define END_NAMESPACE } /*namespace*/
#define TRACEC(func) memtrace::func
#include <new>
#else
#define START_NAMESPACE
#define END_NAMESPACE
#define TRACEC(func) func
#endif
// THROW deklaráció változatai
#if defined(_MSC_VER)
// VS rosszul kezeli az __cplusplus makrot
#if _MSC_VER < 1900
// * nem biztos, hogy jó így *
#define THROW_BADALLOC
#define THROW_NOTHING
#else
// C++11 vagy újabb
#define THROW_BADALLOC noexcept(false)
#define THROW_NOTHING noexcept
#endif
#else
#if __cplusplus < 201103L
// C++2003 vagy régebbi
#define THROW_BADALLOC throw (std::bad_alloc)
#define THROW_NOTHING throw ()
#else
// C++11 vagy újabb
#define THROW_BADALLOC noexcept(false)
#define THROW_NOTHING noexcept
#endif
#endif
START_NAMESPACE
int allocated_blocks();
END_NAMESPACE
#if defined(MEMTRACE_TO_MEMORY)
START_NAMESPACE
int mem_check(void);
END_NAMESPACE
#endif
#if defined(MEMTRACE_TO_MEMORY) && defined(USE_ATEXIT_OBJECT)
#include <cstdio>
START_NAMESPACE
class atexit_class {
private:
static int counter;
static int err;
public:
atexit_class() {
#if defined(CPORTA) && !defined(CPORTA_NOSETBUF)
if (counter == 0) {
setbuf(stdout, 0);
setbuf(stderr, 0);
}
#endif
counter++;
}
int check() {
if(--counter == 0)
err = mem_check();
return err;
}
~atexit_class() {
check();
}
};
static atexit_class atexit_obj;
END_NAMESPACE
#endif/*MEMTRACE_TO_MEMORY && USE_ATEXIT_OBJECT*/
/*Innentol csak a "normal" include eseten kell, kulonben osszezavarja a mukodest*/
#ifndef FROM_MEMTRACE_CPP
#include <stdlib.h>
#ifdef __cplusplus
#include <iostream>
/* ide gyűjtjük a nemtrace-vel összeakadó headereket, hogy előbb legyenek */
#include <fstream> // VS 2013 headerjében van deleted definició
#include <sstream>
#include <vector>
#include <list>
#include <map>
#include <algorithm>
#include <functional>
#include <memory>
#include <iomanip>
#include <locale>
#include <typeinfo>
#include <ostream>
#include <stdexcept>
#endif
#ifdef MEMTRACE_CPP
namespace std {
typedef void (*new_handler)();
}
#endif
#ifdef MEMTRACE_C
START_NAMESPACE
#undef malloc
#define malloc(size) TRACEC(traced_malloc)(size,#size,__LINE__,__FILE__)
void * traced_malloc(size_t size, const char *size_txt, int line, const char * file);
#undef calloc
#define calloc(count,size) TRACEC(traced_calloc)(count, size, #count","#size,__LINE__,__FILE__)
void * traced_calloc(size_t count, size_t size, const char *size_txt, int line, const char * file);
#undef free
#define free(p) TRACEC(traced_free)(p, #p,__LINE__,__FILE__)
void traced_free(void * p, const char *size_txt, int line, const char * file);
#undef realloc
#define realloc(old,size) TRACEC(traced_realloc)(old,size,#size,__LINE__,__FILE__)
void * traced_realloc(void * old, size_t size, const char *size_txt, int line, const char * file);
void mem_dump(void const *mem, size_t size, FILE* fp = stdout);
END_NAMESPACE
#endif/*MEMTRACE_C*/
#ifdef MEMTRACE_CPP
START_NAMESPACE
#undef set_new_handler
#define set_new_handler(f) TRACEC(_set_new_handler)(f)
void _set_new_handler(std::new_handler h);
void set_delete_call(int line, const char * file);
END_NAMESPACE
void * operator new(size_t size, int line, const char * file) THROW_BADALLOC;
void * operator new[](size_t size, int line, const char * file) THROW_BADALLOC;
void * operator new(size_t size) THROW_BADALLOC;
void * operator new[](size_t size) THROW_BADALLOC;
void operator delete(void * p) THROW_NOTHING;
void operator delete[](void * p) THROW_NOTHING;
/* Visual C++ 2012 miatt kell, mert háklis, hogy nincs megfelelő delete, bár senki sem használja */
void operator delete(void *p, int, const char *) THROW_NOTHING;
void operator delete[](void *p, int, const char *) THROW_NOTHING;
#define new new(__LINE__, __FILE__)
#define delete memtrace::set_delete_call(__LINE__, __FILE__),delete
#ifdef CPORTA
#define system(...) // system(__VA_ARGS__)
#endif
#endif /*MEMTRACE_CPP*/
#endif /*FROM_MEMTRACE_CPP*/
#else
#pragma message ( "MEMTRACE NOT DEFINED" )
#endif /*MEMTRACE*/
#endif /*MEMTRACE_H*/
2
I ParosTimin
H ParatlanTimin
ACG T
T ACG
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or sign in to comment