source: cpp/frams/genetics/genman.cpp @ 1316

Last change on this file since 1316 was 1316, checked in by Maciej Komosinski, 5 months ago

Fixed the reported fraction of parent1 and parent2 genes in the child, when the second child is chosen (the fractions were previously swapped in this case, i.e, they did not match the order of parent names)

  • Property svn:eol-style set to native
File size: 26.1 KB
Line 
1// This file is a part of Framsticks SDK.  http://www.framsticks.com/
2// Copyright (C) 1999-2024  Maciej Komosinski and Szymon Ulatowski.
3// See LICENSE.txt for details.
4
5#include "genman.h"
6#include <frams/vm/classes/genoobj.h>
7#include GEN_CONFIG_FILE //configuration of active genetic operators
8#include "common/log.h"
9#include "common/nonstd_math.h"
10#include "common/util-string.h"
11#include <common/loggers/loggers.h>
12
13
14#define GENMAN_REPEAT_FAILED 100 //how many times GenMan tries to repeat a mutation or crossover when the operator does not return an acceptable genotype
15#define STRINGIFY_1(x) #x
16#define STRINGIFY(x) STRINGIFY_1(x) //this second-level macro allows the parameter to be a macro itself and to stringify its value, not its name
17#define GENMAN_REPEAT_FAILED_STR STRINGIFY(GENMAN_REPEAT_FAILED)
18
19
20#ifdef USE_GENMAN_f0
21#include "f0/f0_oper.h"
22#endif
23#ifdef USE_GENMAN_f0s
24#include "f0s/f0s_oper.h"
25#endif
26#ifdef USE_GENMAN_f0FUZZY
27#include "f0/f0Fuzzy_oper.h"
28#endif
29#ifdef USE_GENMAN_f1
30#include "f1/f1_oper.h"
31#endif
32#ifdef USE_GENMAN_f2
33#include "f2/f2_oper.h"
34#endif
35#ifdef USE_GENMAN_f2
36#include "f3/f3_oper.h"
37#endif
38#ifdef USE_GENMAN_f4
39#include "f4/f4_oper.h"
40#endif
41#ifdef USE_GENMAN_f5
42#include "f5/f5_oper.h"
43#endif
44#ifdef USE_GENMAN_f6
45#include "f6/f6_oper.h"
46#endif
47#ifdef USE_GENMAN_f7
48#include "f7/f7_oper.h"
49#endif
50#ifdef USE_GENMAN_f8
51#include "f8/f8_oper.h"
52#endif
53#ifdef USE_GENMAN_f9
54#include "f9/f9_oper.h"
55#endif
56#ifdef USE_GENMAN_fF
57#include "fF/fF_oper.h"
58#endif
59#ifdef USE_GENMAN_fn
60#include "fn/fn_oper.h"
61#endif
62#ifdef USE_GENMAN_fT
63#include "fT/fTest_oper.h"
64#endif
65#ifdef USE_GENMAN_fB
66#include "fB/fB_oper.h"
67#endif
68#ifdef USE_GENMAN_fH
69#include "fH/fH_oper.h"
70#endif
71#ifdef USE_GENMAN_fL
72#include "fL/fL_oper.h"
73#endif
74#ifdef USE_GENMAN_fS
75#include "fS/fS_oper.h"
76#endif
77
78using namespace std; //string, vector
79
80//old code needs update:
81//#include "gengroups.h"
82//extern GenGroup *listaGen;
83//   GENGROUP(0)->l_del.add(sim->GM.onDelGen,&sim->GM); //before delete
84//   GENGROUP(0)->l_del.remove(sim->GM.onDelGen,&sim->GM); //before delete
85
86
87#define FIELDSTRUCT GenMan
88
89static ParamEntry GMparam_tab[] =
90{
91        { "Genetics", 1, 11, "GenMan", },
92        { "gen_hist", 0, PARAM_DONTSAVE, "Remember history of genetic operations", "d 0 1 0", FIELD(history), "Required for phylogenetic analysis", },
93        { "gen_hilite", 0, 0, "Use syntax highlighting", "d 0 1 1", FIELD(hilite), "Use colors for genes?\n(slows down viewing/editing of huge genotypes)", },
94        { "gen_extmutinfo", 0, 0, "Extended mutation info", "d 0 2 0 ~Off~Method ID~Method description", FIELD(extmutinfo), "If active, information about employed mutation method will be stored in the 'info' field of each mutated genotype.", },
95        { "operReport", 0, PARAM_DONTSAVE, "Operators report", "p()", PROCEDURE(p_report), "Show available genetic operators", },
96        { "toHTML", 0, PARAM_DONTSAVE, "HTMLize a genotype", "p s(s)", PROCEDURE(p_htmlize), "returns genotype expressed as colored HTML", },
97        { "toHTMLshort", 0, PARAM_DONTSAVE, "HTMLize a genotype, shorten if needed", "p s(s)", PROCEDURE(p_htmlizeshort), "returns genotype (abbreviated if needed) in colored HTML format", },
98        { "toLaTeX", 0, PARAM_DONTSAVE, "LaTeXize a genotype", "p s(s)", PROCEDURE(p_latexize), "returns genotype in colored LaTeX format", },
99        { "validate", 0, PARAM_DONTSAVE | PARAM_USERHIDDEN, "Validate", "p oGeno(oGeno)", PROCEDURE(p_validate), "returns validated (if possible) Geno object from supplied Geno", },
100        { "mutate", 0, PARAM_DONTSAVE | PARAM_USERHIDDEN, "Mutate", "p oGeno(oGeno)", PROCEDURE(p_mutate), "returns mutated Geno object from supplied Geno", },
101        { "crossOver", 0, PARAM_DONTSAVE | PARAM_USERHIDDEN, "Crossover", "p oGeno(oGeno,oGeno)", PROCEDURE(p_crossover), "returns crossed over genotype", },
102        { "getSimplest", 0, PARAM_DONTSAVE | PARAM_USERHIDDEN, "Get simplest genotype", "p oGeno(s format)", PROCEDURE(p_getsimplest), "returns the simplest genotype for a given encoding (format). \"0\" means f0, \"4\" means f4, etc.", },
103        { 0, },
104};
105
106static ParamEntry GMstats_tab[] =
107{
108        { "Genetics", 1, 12, "GenManStats", "Statistics for genetic operations." },
109        { "gen_count", 0, PARAM_READONLY, "Number of genetic operations so far", "d", FIELD(count), "", },
110        { "gen_mvalid", 0, PARAM_READONLY, "Mutations valid", "d", FIELD(valid_m), "", },
111        { "gen_mvalidated", 0, PARAM_READONLY, "Mutations validated", "d", FIELD(validated_m), "", },
112        { "gen_minvalid", 0, PARAM_READONLY, "Mutations invalid", "d", FIELD(invalid_m), "couldn't be repaired", },
113        { "gen_mfailed", 0, PARAM_READONLY, "Mutations failed", "d", FIELD(failed_m), "couldn't be performed", },
114        { "gen_xovalid", 0, PARAM_READONLY, "Crossovers valid", "d", FIELD(valid_xo), "", },
115        { "gen_xovalidated", 0, PARAM_READONLY, "Crossovers validated", "d", FIELD(validated_xo), "", },
116        { "gen_xoinvalid", 0, PARAM_READONLY, "Crossovers invalid", "d", FIELD(invalid_xo), "couldn't be repaired", },
117        { "gen_xofailed", 0, PARAM_READONLY, "Crossovers failed", "d", FIELD(failed_xo), "couldn't be performed", },
118        { "gen_mutimpr", 0, PARAM_READONLY, "Mutations total effect", "f", FIELD(mutchg), "total cumulative mutation change", },
119        { "gen_xoimpr", 0, PARAM_READONLY, "Crossovers total effect", "f", FIELD(xochg), "total cumulative crossover change", },
120        { "clrstats", 0, PARAM_DONTSAVE, "Clear stats and history", "p()", PROCEDURE(p_clearStats), "", },
121        { 0, },
122};
123
124#undef FIELDSTRUCT
125
126GenMan::GenMan() : localpar(GMparam_tab, this), localstats(GMstats_tab, this),
127seloperpar("GenOperators", "Genetics: Active operators"),
128neuronsparam("Genetics: Neurons to add", "neuronsAdd", "neuadd_"),
129par("GenMan", "Manages various genetic operations, using appropriate operators for the argument genotype format.")
130{
131        history = 0;
132        hilite = 1;
133        clearStats();
134
135#ifdef USE_GENMAN_f0
136        oper_fx_list.push_back(new Geno_f0);
137#endif
138#ifdef USE_GENMAN_f0s
139        oper_fx_list.push_back(new Geno_f0s);
140#endif
141#ifdef USE_GENMAN_f0FUZZY
142        oper_fx_list.push_back(new Geno_f0Fuzzy);
143#endif
144#ifdef USE_GENMAN_f1
145        oper_fx_list.push_back(new Geno_f1);
146#endif
147#ifdef USE_GENMAN_f2
148        oper_fx_list.push_back(new Geno_f2);
149#endif
150#ifdef USE_GENMAN_f3
151        oper_fx_list.push_back(new Geno_f3);
152#endif
153#ifdef USE_GENMAN_f4
154        oper_fx_list.push_back(new Geno_f4);
155#endif
156#ifdef USE_GENMAN_f5
157        oper_fx_list.push_back(new Geno_f5);
158#endif
159#ifdef USE_GENMAN_f6
160        oper_fx_list.push_back(new Geno_f6);
161#endif
162#ifdef USE_GENMAN_f7
163        oper_fx_list.push_back(new Geno_f7);
164#endif
165#ifdef USE_GENMAN_f8
166        oper_fx_list.push_back(new Geno_f8);
167#endif
168#ifdef USE_GENMAN_f9
169        oper_fx_list.push_back(new GenoOper_f9);
170#endif
171#ifdef USE_GENMAN_fF
172        oper_fx_list.push_back(new GenoOper_fF);
173#endif
174#ifdef USE_GENMAN_fn
175        oper_fx_list.push_back(new GenoOper_fn);
176#endif
177#ifdef USE_GENMAN_fT
178        oper_fx_list.push_back(new GenoOper_fTest);
179#endif
180#ifdef USE_GENMAN_fB
181        oper_fx_list.push_back(new Geno_fB);
182#endif
183#ifdef USE_GENMAN_fH
184        oper_fx_list.push_back(new Geno_fH);
185#endif
186#ifdef USE_GENMAN_fL
187        oper_fx_list.push_back(new Geno_fL);
188#endif
189#ifdef USE_GENMAN_fS
190        oper_fx_list.push_back(new GenoOper_fS);
191#endif
192
193        seloper = new int[oper_fx_list.size()]; //may result in a little overhead if some of the operators on the oper_fx_list concern the same genetic format
194        int selopercount = 0;
195        for (unsigned int i = 0; i < oper_fx_list.size(); i++)
196        {
197                if (findOperFormatIndex(oper_fx_list[i]->supported_format) != -1) continue;
198                string type = string("~") + oper_fx_list[i]->name;
199                int dup = 0;
200                for (unsigned int j = i + 1; j < oper_fx_list.size(); j++)
201                        if (oper_fx_list[i]->supported_format == oper_fx_list[j]->supported_format)
202                        {
203                                type += "~";
204                                type += oper_fx_list[j]->name;
205                                dup++;
206                        }
207                type = ssprintf("d 0 %d ", dup) + type;
208                string id = ssprintf("genoper_f%s", oper_fx_list[i]->supported_format.c_str());
209                string name = ssprintf("Operators for f%s", oper_fx_list[i]->supported_format.c_str());
210                seloper[selopercount] = 0;
211                operformats += &oper_fx_list[i]->supported_format;
212                //printf("%x %s %s %s\n",&seloper[selopercount],(const char*)id,(const char*)type,(const char*)name);
213                seloperpar.addProperty(&seloper[selopercount++], id.c_str(), type.c_str(), name.c_str(), "", PARAM_READONLY * (dup == 0));
214        }
215
216        par += &localpar;
217        par += &seloperpar;
218        par += &neuronsparam;
219        for (unsigned int i = 0; i < oper_fx_list.size(); i++)
220                if (oper_fx_list[i]->par.getParamTab()) par += &oper_fx_list[i]->par;
221
222        setDefaults(); //use Param to initialize all values of fields in the paramtab of this object and genetic operators on oper_fx_list
223}
224
225GenMan::~GenMan()
226{
227        for (unsigned int i = 0; i < oper_fx_list.size(); i++) delete oper_fx_list[i];
228        delete[] seloper;
229}
230
231int GenMan::findOperFormatIndex(const SString& format)
232{
233        for (int i = 0; i < operformats.size(); i++)
234                if (*operformats(i) == format)
235                        return i;
236        return -1;
237}
238
239void GenMan::setDefaults()
240{
241        for (unsigned int i = 0; i < oper_fx_list.size(); i++)
242        {
243                oper_fx_list[i]->par.setDefault();
244                oper_fx_list[i]->setDefaults();
245        }
246        localpar.setDefault();
247        //...and we do not reset others that are linked to 'par',
248        //because there quite a few of them, and not every of them defines defaults for each of its parameters.
249}
250
251int GenMan::testValidity(Geno &g, bool &canvalidate)
252{
253        SString ggs = g.getGenes();
254        const char *gg = ggs.c_str();
255        GenoOperators *gf = getOper_f(g.getFormat());
256        int check1;
257        if (!gf) { canvalidate = false; return GENOPER_NOOPER; }
258        else check1 = gf->checkValidity(gg, g.getName().c_str());
259        if (!canvalidate) return check1; //just checking
260        if (check1 == GENOPER_OK) { canvalidate = false; return check1; }
261        char *g2 = strdup(gg);
262        if (gf->validate(g2, g.getName().c_str()) == GENOPER_NOOPER) { free(g2); canvalidate = false; return check1; }
263        if (check1 == GENOPER_NOOPER) //disaster: cannot check because there is no check operator
264        {
265                g.setGenesAssumingSameFormat(g2); free(g2); canvalidate = false; return GENOPER_NOOPER;
266        }
267        int check2 = gf->checkValidity(g2, "validated");
268        if (check2 == GENOPER_OK) g.setGenesAssumingSameFormat(g2);
269        free(g2);
270        if (check2 == GENOPER_OK) return check1;
271        canvalidate = false;
272        return check1; //could not validate.
273}
274
275int GenMan::testGenoValidity(Geno& g)
276{
277        bool fix = false;
278        switch (testValidity(g, fix))
279        {
280        case GENOPER_OK: return 1;
281        case GENOPER_NOOPER: return -1;
282        default: return 0;
283        }
284}
285
286Geno GenMan::validate(const Geno& geny)
287{
288        SString format = geny.getFormat();
289        GenoOperators *gf = getOper_f(format);
290        if (gf == NULL)
291                return Geno("", Geno::FORMAT_INVALID, "", SString::sprintf("GENOPER_NOOPER: Validate(): don't know how to handle genetic format %s", format.c_str()));
292        char *g2 = strdup(geny.getGenes().c_str()); //copy for validation
293        int res = gf->validate(g2, geny.getName().c_str());
294        SString sg2 = g2;
295        free(g2);
296        if (res == GENOPER_OK)
297                return Geno(sg2, format, geny.getName(), geny.getComment());
298        else
299                return Geno("", Geno::FORMAT_INVALID, "", SString::sprintf("GENOPER_NOOPER: validate() for format %s returned invalid value", format.c_str()));
300}
301
302Geno GenMan::mutate(const Geno& g)
303{
304        float chg; //how many changes
305        int method; //mutation method
306        SString format = g.getFormat();
307        GenoOperators *gf = getOper_f(format);
308        if (gf == NULL)
309                return Geno("", Geno::FORMAT_INVALID, "", SString::sprintf("GENOPER_NOOPER: Mutate(): don't know how to handle genetic format %s", format.c_str()));
310        Geno gv = g;
311        bool canvalidate = true;
312        if (testValidity(gv, canvalidate) > 0 && canvalidate == false)
313                return Geno("", Geno::FORMAT_INVALID, "", "GENOPER_OPFAIL: Mutate(): cannot validate invalid source genotype");
314        bool ok = false;
315        int pcount = count;
316        while (!ok)
317        {
318                char *gn = strdup(gv.getGenes().c_str()); //copy for mutation
319                chg = 0;
320                if (gf->mutate(gn, chg, method) == GENOPER_OK)
321                {
322                        LoggerToMemory eh(LoggerBase::Enable | LoggerToMemory::StoreFirstMessage); //mute testValidity()
323                        Geno G(gn, gv.getFormat(), "", "");
324                        canvalidate = true;
325                        int res = testValidity(G, canvalidate);
326                        if (res == GENOPER_OK && canvalidate == false) { valid_m++; ok = true; }
327                        else
328                                if (res > 0 && canvalidate == false) invalid_m++; else
329                                {
330                                        validated_m++; ok = true;
331                                }
332                        if (ok) gv = G;
333                }
334                else failed_m++;
335                free(gn);
336                count++;
337                if (!ok && (count - pcount > GENMAN_REPEAT_FAILED))
338                {
339                        logPrintf("GenMan", "Mutate", LOG_WARN, "Tried " GENMAN_REPEAT_FAILED_STR "x and failed: %s", g.getGenes().c_str());
340                        return Geno("", -1, "", "GENOPER_OPFAIL: Mutate() tried " GENMAN_REPEAT_FAILED_STR "x and failed");
341                }
342        }
343        mutchg += chg;
344        if (history) saveLink(g.getGenes().c_str(), "", gv.getGenes().c_str(), chg);
345        SString mutinfo;
346        if (extmutinfo == 0) mutinfo = SString::sprintf("%.2f%% mutation of '%s'", 100 * chg, g.getName().c_str()); else
347                if (extmutinfo == 1) mutinfo = SString::sprintf("%.2f%% mutation(%d) of '%s'", 100 * chg, method, g.getName().c_str()); else
348                        mutinfo = SString::sprintf("%.2f%% mutation(%s) of '%s'", 100 * chg, gf->mutation_method_names ? gf->mutation_method_names[method] : "unspecified method name", g.getName().c_str());
349        gv.setComment(mutinfo);
350        return gv;
351}
352
353Geno GenMan::crossOver(const Geno& g1, const Geno& g2)
354{
355        SString format = g1.getFormat();
356        if (format != g2.getFormat()) return Geno("", Geno::FORMAT_INVALID, "", SString::sprintf("GENOPER_NOOPER: CrossOver(): does not work for parents with differing genetic formats (%s and %s)", format.c_str(), g2.getFormat().c_str()));
357        GenoOperators *gf = getOper_f(format);
358        if (gf == NULL)
359                return Geno("", Geno::FORMAT_INVALID, "", SString::sprintf("GENOPER_NOOPER: CrossOver(): no operators found for genetic format %s", format.c_str()));
360        Geno g1v = g1, g2v = g2;
361
362        {
363                LoggerToMemory eh(LoggerBase::Enable | LoggerToMemory::StoreFirstMessage); //mute testValidity()
364                bool canvalidate = true;
365                if (testValidity(g1v, canvalidate) > 0 && canvalidate == false)
366                        return Geno("", Geno::FORMAT_INVALID, "", "GENOPER_OPFAIL: CrossOver(): cannot validate invalid source genotype #1");
367                canvalidate = true;
368                if (testValidity(g2v, canvalidate) > 0 && canvalidate == false)
369                        return Geno("", Geno::FORMAT_INVALID, "", "GENOPER_OPFAIL: CrossOver(): cannot validate invalid source genotype #2");
370        }
371
372        float chg; //fraction of parent1 genes in the child
373        bool ok = false;
374        int pcount = count;
375
376        while (!ok)
377        {
378                float chg1, chg2;
379                char *g1n = strdup(g1.getGenes().c_str()); //copy for crossover
380                char *g2n = strdup(g2.getGenes().c_str()); //copy for crossover
381                chg1 = chg2 = 0;
382                if (gf->crossOver(g1n, g2n, chg1, chg2) == GENOPER_OK)
383                {
384                        char *gn;
385                        if (g1n[0] && g2n[0]) if (rndUint(2) == 0) g1n[0] = 0; else g2n[0] = 0; //both provided? we want only one
386                        if (g1n[0]) { gn = g1n; chg = chg1; }
387                        else { gn = g2n; chg = 1 - chg2; }
388                        LoggerToMemory eh(LoggerBase::Enable | LoggerToMemory::StoreFirstMessage); //mute testValidity()
389                        Geno G(gn, g1v.getFormat(), "", "");
390                        bool canvalidate = true;
391                        int res = testValidity(G, canvalidate);
392                        if (res == GENOPER_OK && canvalidate == false) { valid_xo++; ok = true; }
393                        else
394                                if (res > 0 && canvalidate == false) invalid_xo++; else
395                                {
396                                        validated_xo++; ok = true;
397                                }
398                        if (ok) g1v = G;
399                }
400                else failed_xo++;
401                free(g1n);
402                free(g2n);
403                count++;
404                if (!ok && (count - pcount > GENMAN_REPEAT_FAILED))
405                {
406                        logPrintf("GenMan", "CrossOver", LOG_WARN, "Tried " GENMAN_REPEAT_FAILED_STR "x and failed: %s and %s", g1.getGenes().c_str(), g2.getGenes().c_str());
407                        return Geno("", Geno::FORMAT_INVALID, "", "GENOPER_OPFAIL: CrossOver() tried " GENMAN_REPEAT_FAILED_STR "x and failed");
408                }
409        }
410        // result in g1v
411        xochg += chg;
412        if (history) saveLink(g1.getGenes().c_str(), g2.getGenes().c_str(), g1v.getGenes().c_str(), chg);
413        SString xoinfo = SString::sprintf("Crossing over of '%s' (%.2f%%) and '%s' (%.2f%%)",
414                g1.getName().c_str(), 100 * chg, g2.getName().c_str(), 100 * (1 - chg));
415        g1v.setComment(xoinfo);
416        return g1v;
417}
418
419float GenMan::similarity(const Geno& g1, const Geno& g2)
420{
421        SString format = g1.getFormat();
422        if (format != g2.getFormat()) return GENOPER_NOOPER;
423        GenoOperators *gf = getOper_f(format);
424        if (!gf) return GENOPER_NOOPER; else return gf->similarity(g1.getGenes().c_str(), g2.getGenes().c_str());
425}
426
427uint32_t GenMan::getStyle(const char *g, const Geno *G, int pos)
428{
429        SString format = G->getFormat();
430        if (format == Geno::FORMAT_INVALID)
431                return GENSTYLE_RGBS(64, 64, 64, 0); // gray & "valid" (unknown format so we don't know what is valid and what is not)
432        if ((pos = G->mapStringToGen(pos)) == -1) return GENSTYLE_COMMENT;
433        GenoOperators *gf = getOper_f(format);
434        if (!gf) return GENSTYLE_CS(0, 0); //black & valid
435        else return gf->style(G->getGenes().c_str(), pos);
436}
437
438uint32_t GenMan::getStyle(const char *g, int pos)
439{
440        Geno G(g);
441        return getStyle(g, &G, pos);
442}
443
444void GenMan::getFullStyle(const char *g, const Geno *G, uint32_t *styletab)
445{
446        SString format = G->getFormat();
447        if (format == Geno::FORMAT_INVALID)
448        {
449                for (unsigned int pos = 0; pos < strlen(g); pos++)
450                        styletab[pos] = GENSTYLE_RGBS(64, 64, 64, 0); // gray & "valid" (unknown format so we don't know what is valid and what is not)
451                return;
452        }
453        GenoOperators *gf = getOper_f(format);
454        SString geny = G->getGenes();
455        for (unsigned int pos = 0; pos < strlen(g); pos++)
456        {
457                int posmapped = G->mapStringToGen(pos);
458                if (posmapped == -1) styletab[pos] = GENSTYLE_COMMENT;
459                else if (!gf) styletab[pos] = GENSTYLE_CS(0, 0); //black & valid
460                else styletab[pos] = gf->style(geny.c_str(), posmapped);
461                //logPrintf("GenMan", "getFullStyle", LOG_INFO, "%d  char='%c' (%d)  format=0x%08x", pos, g[pos], g[pos], styletab[pos]);
462        }
463}
464
465void GenMan::getFullStyle(const char *g, uint32_t *styletab)
466{
467        Geno G(g);
468        getFullStyle(g, &G, styletab);
469}
470
471string GenMan::HTMLize(const char *g) { return HTMLize(g, false); }
472
473string GenMan::HTMLizeShort(const char *g) { return HTMLize(g, true); }
474
475string GenMan::HTMLize(const char *g, bool shorten)
476{
477        char buf[50];
478        int len = int(strlen(g));
479        int chars = 0, lines = 0;
480        bool shortened = false;
481        uint32_t *styletab = new uint32_t[len];
482        getFullStyle(g, styletab);
483        string html = "<style>"
484                "span.geno{background:white; padding:0.2em; font-family:arial,helvetica,sans-serif}"
485                "</style>\n\n";
486        html += "<span class=\"geno\">";
487        uint32_t prevstyle, prevcolor, style = 0, color = 0;
488        for (int i = 0; i < len; i++)
489        {
490                if (shorten && ((lines == 0 && chars > 160) || (lines > 5 || chars > 300))) { shortened = true; break; }
491                if (g[i] == '\r') continue;
492                if (g[i] == '\n') { html += "<br>\n"; lines++; continue; }
493                chars++;
494                prevstyle = style;
495                prevcolor = color;
496                style = GENGETSTYLE(styletab[i]);
497                color = GENGETCOLOR(styletab[i]);
498                if ((i != 0 && (color != prevcolor))) html += "</font>";
499                if ((style & GENSTYLE_INVALID) != (prevstyle & GENSTYLE_INVALID))
500                {
501                        html += "<"; if (!(style & GENSTYLE_INVALID)) html += "/"; html += "u>";
502                }
503                if ((style & GENSTYLE_BOLD) != (prevstyle & GENSTYLE_BOLD))
504                {
505                        html += "<"; if (!(style & GENSTYLE_BOLD)) html += "/"; html += "b>";
506                }
507                if ((style & GENSTYLE_ITALIC) != (prevstyle & GENSTYLE_ITALIC))
508                {
509                        html += "<"; if (!(style & GENSTYLE_ITALIC)) html += "/"; html += "i>";
510                }
511                if ((i == 0 || (color != prevcolor)))
512                {
513                        sprintf(buf, "<font color=#%02x%02x%02x>", GENGET_R(color), GENGET_G(color), GENGET_B(color)); html += buf;
514                }
515                if (g[i] == '<') html += "&lt;"; else if (g[i] == '>') html += "&gt;"; else html += g[i];
516                if ((i % 3) == 0 && g[i] == ' ') html += "\n"; //for readability, insert some newlines into html...
517        }
518        delete[] styletab;
519        html += "</u></b></i></font>";
520        if (shortened) html += " [etc...]";
521        html += "</span>\n";
522        return html;
523}
524
525void GenMan::p_htmlize(ExtValue *args, ExtValue *ret)
526{
527        ret->setString(HTMLize(args->getString().c_str()).c_str());
528}
529
530void GenMan::p_htmlizeshort(ExtValue *args, ExtValue *ret)
531{
532        ret->setString(HTMLizeShort(args->getString().c_str()).c_str());
533}
534
535string GenMan::LaTeXize(const char *g)
536{
537        char buf[50];
538        int len = int(strlen(g));
539        int chars = 0, lines = 0; //currently not used
540        uint32_t *styletab = new uint32_t[len];
541        getFullStyle(g, styletab);
542        string latex = "\\usepackage{xcolor}\n% Using \\texttt{} may be beneficial for some genetic encodings, but then you may lose bold/italic.\n\\noindent \\sloppy";
543        uint32_t prevstyle, prevcolor, style = 0, color = 0;
544        for (int i = 0; i < len; i++)
545        {
546                if (g[i] == '\r') continue;
547                if (g[i] == '\n') { latex += "\\\\\n"; lines++; continue; }
548                chars++;
549                prevstyle = style;
550                prevcolor = color;
551                style = GENGETSTYLE(styletab[i]);
552                color = GENGETCOLOR(styletab[i]);
553
554                // Unfortunately, LaTeX (as opposed to HTML) uses the same closing tags "}" for color, bold, italic, underline - so they cannot intersect.
555                // Therefore we have to "turn off" everything on every change of style or color, and then "turn on" (to avoid problems with e.g. red-bold-blue-unbold or bold-italic-unbold-unitalic).
556                // This could be optimized by a more complex logic and tracking which color/style section starts and ends within another section.
557
558                if (((style & GENSTYLE_INVALID) != (prevstyle & GENSTYLE_INVALID))
559                        ||
560                        ((style & GENSTYLE_BOLD) != (prevstyle & GENSTYLE_BOLD))
561                        ||
562                        ((style & GENSTYLE_ITALIC) != (prevstyle & GENSTYLE_ITALIC))
563                        ||
564                        ((i == 0 || (color != prevcolor))))
565                {
566                        if (prevstyle & GENSTYLE_INVALID) latex += "}";
567                        if (prevstyle & GENSTYLE_BOLD) latex += "}";
568                        if (prevstyle & GENSTYLE_ITALIC) latex += "}";
569                        if (i != 0) latex += "}"; //for color
570                        if (style & GENSTYLE_INVALID) latex += "\\underline{";
571                        if (style & GENSTYLE_BOLD) latex += "\\textbf{";
572                        if (style & GENSTYLE_ITALIC) latex += "\\textit{";
573                        sprintf(buf, "\\textcolor[rgb]{%.2g,%.2g,%.2g}{", GENGET_R(color) / 255.0, GENGET_G(color) / 255.0, GENGET_B(color) / 255.0); latex += buf;
574                }
575                if (g[i] == '<') latex += "$<$"; else if (g[i] == '>') latex += "$>$"; else
576                        if (g[i] == '-') latex += "$-$"; else if (g[i] == '|') latex += "$|$"; else
577                                if (g[i] == '$') latex += "\\$"; else if (g[i] == '%') latex += "\\%"; else
578                                        if (g[i] == '#') latex += "\\#"; else latex += g[i];
579                if ((i % 3) == 0 && g[i] == ' ') latex += "\n"; //for readability, insert some newlines into latex...
580                if (i % 10 == 0) latex += "{\\hskip 0pt}"; // https://tex.stackexchange.com/questions/33526/automatic-line-breaking-of-long-lines-of-text
581        }
582        delete[] styletab;
583        latex += "}"; //for color (it was used at least once)
584        if (style & GENSTYLE_INVALID) latex += "}";
585        if (style & GENSTYLE_BOLD) latex += "}";
586        if (style & GENSTYLE_ITALIC) latex += "}";
587        latex += "\n";
588        return latex;
589}
590
591void GenMan::p_latexize(ExtValue *args, ExtValue *ret)
592{
593        ret->setString(LaTeXize(args->getString().c_str()).c_str());
594}
595
596Geno GenMan::getSimplest(const SString& format)
597{
598        GenoOperators *gf = getOper_f(format);
599        if (!gf) return Geno();
600        string info = "The simplest genotype of format f"; info += format.c_str();
601        info += " for operators '"; info += gf->name; info += "'.";
602        return Geno(gf->getSimplest(), format, "Root", info.c_str());
603}
604
605void GenMan::p_getsimplest(ExtValue *args, ExtValue *ret)
606{
607        SString format = GenoObj::formatFromExtValue(args[0]);
608        if (!getOper_f(format))
609                ret->setEmpty();
610        else
611                *ret = GenoObj::makeDynamicObjectAndDecRef(new Geno(getSimplest(format)));
612}
613
614const char *GenMan::getOpName(const SString& format)
615{
616        GenoOperators *gf = getOper_f(format);
617        if (!gf) return "n/a"; else return gf->name.c_str();
618}
619
620GenoOperators* GenMan::getOper_f(const SString& format)
621{
622        int ind = findOperFormatIndex(format);
623        if (ind == -1) return NULL;
624        int which_oper_of_format = seloper[ind];
625        for (unsigned int i = 0; i < oper_fx_list.size(); i++)
626                if (oper_fx_list[i]->supported_format == format)
627                        if (which_oper_of_format == 0) return oper_fx_list[i]; else which_oper_of_format--;
628        return NULL; //should never happen
629}
630
631void GenMan::saveLink(const string parent1, const string parent2, const string child, const float chg)
632{
633        GenoLink l;
634        l.count = count;
635        l.parent1 = parent1;
636        l.parent2 = parent2;
637        l.child = child;
638        l.chg = chg;
639        l.fit = 0; //temporarily. Will be set when the genotype dies
640        //logPrintf("GenMan","saveLink",0,"#%d: [%d] '%s' + '%s' -> '%s'",GenoLinkList.size(),count,parent1.c_str(),parent2.c_str(),child.c_str());
641        GenoLinkList.push_back(l);
642}
643
644void GenMan::onDelGen(void *obj, intptr_t n)
645{
646        //old code needs update:
647        //   ((SpeciesList*)obj)->przyDodaniu(i);
648        /* !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
649           GenMan *gm=(GenMan*)obj;
650           Genotype *gt=(Genotype*)(*listaGen)(n); //there is no more "listaGen"
651           string g=(const char*)gt->genotype.getGene();
652           float fit=gt->getFinalFitness();
653           for(int i=0;i<gm->GenoLinkList.size();i++) //find genotype
654           if (gm->GenoLinkList[i].g1==g) {gm->GenoLinkList[i].fit=fit; break;}
655           */
656}
657
658void GenMan::clearStats()
659{
660        count = 0;
661        valid_m = valid_xo = validated_m = validated_xo = invalid_m = invalid_xo = failed_m = failed_xo = 0;
662        mutchg = xochg = 0;
663        GenoLinkList.clear();
664}
665
666void GenMan::p_clearStats(ExtValue *args, ExtValue *ret) { clearStats(); }
667
668void GenMan::p_report(ExtValue *args, ExtValue *ret)
669{                      //should be updated to handle multiple operators for a single format
670        char *g, *g2;
671        float f1, f2;
672        int m;
673        logMessage("GenMan", "Report", 0, "The following genetic operators are available:");
674        for (unsigned int i = 0; i < oper_fx_list.size(); i++)
675        {
676                string l;
677                if (oper_fx_list[i]->checkValidity("", "") != GENOPER_NOOPER) l += " checkValidity";
678                if (oper_fx_list[i]->getSimplest())
679                {
680                        g = strdup(oper_fx_list[i]->getSimplest());
681                        g2 = strdup(g);
682                        if (oper_fx_list[i]->validate(g, "") != GENOPER_NOOPER) l += " validate";
683                        if (oper_fx_list[i]->mutate(g, f1, m) != GENOPER_NOOPER) l += " mutate";
684                        if (oper_fx_list[i]->crossOver(g, g2, f1, f2) != GENOPER_NOOPER) l += " crossover";
685                        l += " getSimplest";
686                        free(g); free(g2);
687                }
688                //      if (oper_fx_list[i]->similarity("","")!=GENOPER_NOOPER) l+=" similarity";
689                logPrintf("GenMan", "Report", LOG_INFO, "format f%s (%s):%s",
690                        oper_fx_list[i]->supported_format.c_str(), oper_fx_list[i]->name.c_str(), l.c_str());
691        }
692}
693
694void GenMan::p_validate(ExtValue *args, ExtValue *ret)
695{
696        Geno *g = GenoObj::fromObject(args[0]);
697        if (g == NULL)
698                ret->setEmpty();
699        else
700                *ret = GenoObj::makeDynamicObjectAndDecRef(new Geno(validate(*g)));
701}
702
703void GenMan::p_mutate(ExtValue *args, ExtValue *ret)
704{
705        Geno *g = GenoObj::fromObject(args[0]);
706        if (g == NULL)
707                ret->setEmpty();
708        else
709                *ret = GenoObj::makeDynamicObjectAndDecRef(new Geno(mutate(*g)));
710}
711
712void GenMan::p_crossover(ExtValue *args, ExtValue *ret)
713{
714        Geno *g1 = GenoObj::fromObject(args[1]);
715        Geno *g2 = GenoObj::fromObject(args[0]);
716        if (g1 == NULL || g2 == NULL)
717                ret->setEmpty();
718        else
719                *ret = GenoObj::makeDynamicObjectAndDecRef(new Geno(crossOver(*g1, *g2)));
720}
721
Note: See TracBrowser for help on using the repository browser.