Advertisement
Guest User

Untitled

a guest
Jun 13th, 2019
232
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
text 253.72 KB | None | 0 0
  1. // Copyright (c) 2009-2018, Andreas Wettstein
  2. // All rights reserved.
  3. //
  4. // Redistribution and use in source and binary forms, with or without
  5. // modification, are permitted provided that the following conditions are met:
  6. //
  7. // - Redistributions of source code must retain the above copyright notice,
  8. // this list of conditions and the following disclaimer.
  9. // - Redistributions in binary form must reproduce the above copyright
  10. // notice, this list of conditions and the following disclaimer in the
  11. // documentation and/or other materials provided with the distribution.
  12. //
  13. // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
  14. // AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
  15. // IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
  16. // ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
  17. // LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
  18. // CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
  19. // SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
  20. // INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
  21. // CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
  22. // ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
  23. // POSSIBILITY OF SUCH DAMAGE.
  24.  
  25. constexpr char opt_version[] = "1.267";
  26.  
  27. //--------------- src/konstanten.hh ---------------
  28. #ifndef BELEGUNGSOPTIMIERER_KONSTANTEN_H
  29. #define BELEGUNGSOPTIMIERER_KONSTANTEN_H
  30.  
  31. #include <string>
  32.  
  33. // Umlaute für die Verwendung in der Ausgabe; diese kann entweder in 8-Bit
  34. // Codierung (Latin-1) oder UTF-8-Codierung erfolgen.
  35.  
  36. #ifdef AUSGABE_8BIT
  37. #define strAe "\xE4"
  38. #define strAE "\xC4"
  39. #define strOe "\xF6"
  40. #define strUe "\xFC"
  41. #define strNBS "\xA0"
  42. #else
  43. #define strAe "\u00e4"
  44. #define strAE "\u00c4"
  45. #define strOe "\u00f6"
  46. #define strUe "\u00fc"
  47. #define strNBS "\u00A0"
  48. #endif // !AUSGABE_8BIT
  49.  
  50. // Ein primitives Schema, um beim Compiliern deutsche oder englische Ausgaben
  51. // zu wählen.
  52.  
  53. #ifdef ENGLISH
  54. #define SPRACHE(x,y) y
  55. #else
  56. #define SPRACHE(x,y) x
  57. #endif
  58.  
  59. #ifndef TASTENZAHL
  60. #define TASTENZAHL 35
  61. #endif // !TASTENZAHL
  62.  
  63. constexpr int nshift = 2; // Anzahl Shifttasten
  64. constexpr int ntaste = TASTENZAHL-nshift; // Anzahl Symboltasten
  65. constexpr int nebene = 2; // Anzahl Ebenen
  66. constexpr int nmaxkorpus = 10;
  67.  
  68. #ifdef OHNE2SHIFT
  69. constexpr int nebene2 = 1;
  70. #else
  71. constexpr int nebene2 = nebene;
  72. #endif
  73.  
  74. // Konstanten, um Zeilennummern zu bezeichnen.
  75. struct zeilen_t {
  76. enum {
  77. Zahlenreihe, Obere_Zeile, Mittelzeile, Untere_Zeile, Leerzeichenzeile,
  78. nzeile
  79. };
  80. };
  81.  
  82. // nzeile ist die Höhe und nspalte ist die Breite eines vollen Tastenfelds.
  83. constexpr int nzeile = zeilen_t::nzeile;
  84. constexpr int nspalte = 16;
  85.  
  86. // Anzahl der Finger (einschliesslich der Daumen)
  87. constexpr int nfinger = 10;
  88.  
  89. class finger_t {
  90. public:
  91. // EinerDerDaumen ist ein Daumen, aber es ist nicht festgelegt, welcher.
  92. enum {
  93. KleinfingerLinks = -5, RingfingerLinks = -4,
  94. MittelfingerLinks = -3, ZeigefingerLinks = -2,
  95. DaumenLinks = -1,
  96. EinerDerDaumen = 0,
  97. DaumenRechts = 1,
  98. ZeigefingerRechts = 2, MittelfingerRechts = 3,
  99. RingfingerRechts = 4, KleinfingerRechts = 5
  100. } _;
  101.  
  102. operator int() const { return _; }
  103. explicit finger_t(int w) : _(static_cast<decltype(_)>(w)){}
  104. finger_t(decltype(_) w) : _(w){}
  105. finger_t() : _(EinerDerDaumen){}
  106. };
  107.  
  108. // Konstanten, um Bigrammkategorien zu bezeichnen.
  109. struct kategorie_t {
  110. enum {
  111. Handwechsel, Kollision, Doppeltanschlag,
  112. Auswaerts, Einwaerts, MitUndefDaumen, nKategorie
  113. } _;
  114.  
  115. operator int() const { return _; }
  116. explicit kategorie_t(int w) : _(static_cast<decltype(_)>(w)){}
  117. kategorie_t(decltype(_) w) : _(w){}
  118. kategorie_t() : _(nKategorie){}
  119. };
  120.  
  121. #endif // !BELEGUNGSOPTIMIERER_KONSTANTEN_H
  122.  
  123. //--------------- src/utfhilfe.hh ---------------
  124. #ifndef BELEGUNGSOPTIMIERER_UTFHILFE_H
  125. #define BELEGUNGSOPTIMIERER_UTFHILFE_H
  126.  
  127. #include <cstdint>
  128. #include <string>
  129.  
  130. std::string utf32_in_utf8(char32_t c);
  131. std::string utf32_in_utf8(const std::u32string& s);
  132. std::string utf32_in_utf8(uint64_t u);
  133.  
  134. char32_t utf8_in_utf32(const char*& s, bool& fehler);
  135.  
  136. std::u32string zahl_in_utf32(int z);
  137.  
  138. std::string utf32_in_ausgabe(char32_t);
  139. std::string utf32_in_ausgabe(const std::u32string&);
  140.  
  141. bool ist_ziffer(char32_t c);
  142. bool ist_zwischenraum(char32_t c);
  143.  
  144. constexpr uint64_t utf_maske = 0x1fffff;
  145.  
  146. #endif //!BELEGUNGSOPTIMIERER_UTFHILFE_H
  147.  
  148. //--------------- src/Unicode.hh ---------------
  149. #ifndef BELEGUNGSOPTIMIERER_UNICODE_H
  150. #define BELEGUNGSOPTIMIERER_UNICODE_H
  151.  
  152. #include <unordered_map>
  153. #include <unordered_set>
  154.  
  155. class Unicode final {
  156. std::unordered_set<char32_t> buchstaben;
  157. std::unordered_map<char32_t, char32_t> gross_in_klein;
  158. Unicode(const Unicode& ) = delete;
  159. Unicode();
  160. public:
  161. static const Unicode& get(){ static const Unicode x; return x; }
  162.  
  163. char32_t kleinbuchstabe(char32_t c) const;
  164. bool ist_buchstabe(char32_t c) const;
  165. };
  166.  
  167. #endif // !BELEGUNGSOPTIMIERER_UNICODE_H
  168.  
  169. //--------------- src/Eingabestream.hh ---------------
  170. #ifndef BELEGUNGSOPTIMIERER_EINGABESTREAM_H
  171. #define BELEGUNGSOPTIMIERER_EINGABESTREAM_H
  172.  
  173. #include <fstream>
  174. #include <string>
  175.  
  176. class Eingabestream final {
  177. std::string zeile, name;
  178. std::u32string buffer;
  179. std::ifstream f;
  180. size_t l, p, maxl, izeile;
  181. int errpos;
  182. bool utf8ein, geaendert;
  183.  
  184. bool fuellen();
  185.  
  186. // Übergehen alle Leerzeichen und Tabulatoren, beginnend von der aktuellen
  187. // Position, höchstens bis zum Ende der Zeile.
  188. void zwischenraum_uebergehen();
  189. public:
  190. // f: Geöffneter Stream; utf8: true wenn der Stream UTF-8 enthalten sollte,
  191. // false, wenn er CP-1252 enthalten sollte.
  192. Eingabestream(const std::string& nam, bool utf8,
  193. bool muss_existieren = true);
  194.  
  195. ~Eingabestream();
  196.  
  197. // Lies nächstes Zeichen (einschliesslich Zeilenenden '\n'); falls Eingabe
  198. // erschöpft ist gibt Null zurück.
  199. char32_t lieszeichen();
  200.  
  201. // Falls aus der aktuellen Zeile schon Zeichen gelesen wurden, fange eine
  202. // neue an. Gib false zurück, wenn die Eingabe erschöpft ist.
  203. bool neuezeile();
  204.  
  205. // Wie neuezeile, übergeht aber Kommentar- und Leerzeilen.
  206. bool echte_neuezeile();
  207.  
  208. // Anzahl der Zeichen, die in der aktuellen Zeile noch verbleiben.
  209. size_t restzeichen() const;
  210.  
  211. // Ist aktuelles Zeichen in aktueller Zeile ein Leerzeichen oder Tabulator?
  212. bool ist_zwischenraum() const;
  213.  
  214. // Ist aktuelles Zeichen in aktueller Zeile eine Ziffer
  215. bool ist_ziffer() const;
  216.  
  217. // Ist aktuelles Zeichen in aktueller Zeile gleich dem übergebenen?
  218. bool ist(char32_t c) const;
  219.  
  220. // übergeht das aktuelle Zeichen, fängt aber nie eine neue Zeile an.
  221. void uebergehen();
  222.  
  223. // Liest nächstes Zeichen in aktueller Zeile; gibt 0 am Zeilenende;
  224. char32_t lies_in_zeile();
  225.  
  226. // Prüft, ob in Rest der Zeile höchstens noch Zwischenraum vorkommt und
  227. // übergeht diesen.
  228. bool zeilenende();
  229.  
  230. // Übergeht führenden Zwischenraum und erwartet dahinter eine Zahl, die bis
  231. // zum Zeilenende oder einem Zwischenraum reicht. Falls das nicht so ist,
  232. // wird false zurückgegeben. Im Erfolgsfall wird true zurückgegeben, der
  233. // gelese Wert steht in wert.
  234. bool hole_zahl(double& wert);
  235.  
  236. // Übergeht führenden Zwischenraum und gibt das dahinter stehende Wort
  237. // zurück, das durch Zwischenraum oder das Zeilenende begrenzt ist. Falls
  238. // die Zeile kein Wort mehr enthält, gib false zurück. Falls man auf ein
  239. // Kommentarzeichen # stösst gilt die Zeile als ohne beendet, kein Wort wird
  240. // gefunden.
  241. bool hole_wort(std::u32string& wert);
  242.  
  243. // Übergeht führenden Zwischenraum und gibt das dahinter stehende Flag (+
  244. // für true, - für false) in wert zurück, das durch Zwischenraum oder das
  245. // Zeilenende begrenzt ist. Falls kein Flag gefunden wird, gib false
  246. // als Returnwert.
  247. bool hole_flag(bool& wert);
  248.  
  249. // übergeht Zwischenraum, und erwartet dann noch mindestens zwei Zeichen in
  250. // der Zeile. Das erste davon ist der Stringbegrenzer; die folgenden
  251. // Zeichen bis zum nächsten Stringbegrenzer gehören zum String. Kommt kein
  252. // weiterer Stringbegrenzer ist das ein Fehler.
  253. bool hole_string(std::u32string& wert);
  254.  
  255. bool encoding_geaendert() const;
  256.  
  257. [[noreturn]] void fehler(size_t off = 0) const;
  258.  
  259. size_t aktuelle_zeile() const;
  260. const std::string& aktuelles_file() const;
  261. };
  262.  
  263. double hole_zahl(Eingabestream& f, double rmin, double rmax);
  264.  
  265. void pruefe_leer_dann_N(Eingabestream& f, size_t N);
  266.  
  267. #endif // !BELEGUNGSOPTIMIERER_EINGABESTREAM_H
  268.  
  269. //--------------- src/typen.hh ---------------
  270. #ifndef BELEGUNGSOPTIMIERER_TYPEN_H
  271. #define BELEGUNGSOPTIMIERER_TYPEN_H
  272.  
  273. //#include "konstanten.hh"
  274. #include <memory>
  275. #include <string>
  276.  
  277. // Koordinate
  278. struct koordinate_t { double x, y; };
  279.  
  280. // Beschreibung einer einzelnen Taste.
  281. struct taste_t final {
  282. std::u32string name;
  283. double x, y, aufwand;
  284. int spalte, zeile;
  285. finger_t finger;
  286. bool istGrundposition, seite;
  287. };
  288.  
  289. // Beschreibung eines n-Gramms.
  290. struct n_gramm_t final {
  291. n_gramm_t(int T1, int T2, int T3, const std::u32string& N)
  292. : t1(T1), t2(T2), t3(T3), name(N){}
  293. int t1, t2, t3;
  294. std::u32string name;
  295. };
  296.  
  297.  
  298. // zaehl_t ist der Datentyp, der zum Zählen von n-Grammen im Korpus verwendet
  299. // wird. Double vermeidet Überläufe bei der Berechnung von Korrelationen und
  300. // ist daher der sinnvollste Typ.
  301. using zaehl_t = double;
  302. using zaehl_ta = std::unique_ptr<zaehl_t[]>;
  303.  
  304. // akkumuations_t wird zur Berechnung der Aufwände verwendet.
  305. using akkumuations_t = float;
  306.  
  307. // aufwand_t wird zur Tabellierung der Aufwände verwendet. Um die Tabellen
  308. // klein zu halten, verwende ich hier nur float; ist allemal genau genug.
  309. using aufwand_t = float;
  310.  
  311. // haeufigkeit_t wird zur Tabellierung der Häufigkeiten verwendet, die in der
  312. // Optimierung verwendet werden. Auch hier ein float, um die Tabellen klein zu
  313. // halten; die sieben Dezimale sollten mehr als ausreichend genau sein.
  314. using haeufigkeit_t = float;
  315.  
  316. // belegung_t ist eine Zeichenpermutation und repräsentiert Belegungen.
  317. using belegung_t = unsigned char[ntaste];
  318.  
  319. // Fingerbelastung durch die verschiedenen Korpora.
  320. using fingerbelastung_t = akkumuations_t[nmaxkorpus][nfinger+1];
  321.  
  322. #endif // !BELEGUNGSOPTIMIERER_TYPEN_H
  323.  
  324. //--------------- src/Naechstes_zeichen.hh ---------------
  325. #ifndef BELEGUNGSOPTIMIERER_NAECHSTES_ZEICHEN_H
  326. #define BELEGUNGSOPTIMIERER_NAECHSTES_ZEICHEN_H
  327.  
  328. //#include "Eingabestream.hh"
  329. #include <string>
  330.  
  331. class Naechstes_zeichen {
  332. Eingabestream text;
  333. public:
  334. Naechstes_zeichen(const std::string& name, bool utf8) : text(name, utf8){}
  335. virtual ~Naechstes_zeichen(){}
  336. virtual char32_t get(){ return text.lieszeichen(); }
  337. bool encoding_geaendert() const { return text.encoding_geaendert(); }
  338. };
  339. #endif // !BELEGUNGSOPTIMIERER_NAECHSTES_ZEICHEN_H
  340.  
  341. //--------------- src/Haeufigkeit.hh ---------------
  342. #ifndef BELEGUNGSOPTIMIERER_HAEUFIGKEIT_H
  343. #define BELEGUNGSOPTIMIERER_HAEUFIGKEIT_H
  344.  
  345. //#include "typen.hh"
  346. #include <cassert>
  347. #include <unordered_map>
  348. #include <vector>
  349.  
  350. class Tastatur;
  351. class Kodierung;
  352.  
  353. class Haeufigkeit final {
  354. private:
  355. haeufigkeit_t h3[ntaste][ntaste][ntaste][nebene];
  356. haeufigkeit_t h2[ntaste][ntaste][nebene][nebene2];
  357. haeufigkeit_t h1[ntaste][nebene], h1e[nmaxkorpus][ntaste][nebene];
  358. haeufigkeit_t gewichte[nmaxkorpus];
  359. haeufigkeit_t hunbekannt;
  360. const int nkorpus;
  361. bool trigramme;
  362. const Tastatur& tastatur;
  363. const Kodierung& kodierung;
  364.  
  365. haeufigkeit_t *h11, *h21, *h22;
  366. haeufigkeit_t *h11e[nmaxkorpus], *h11ee[nmaxkorpus], *h21e[nmaxkorpus];
  367.  
  368. void akkumuliere(int korpus, double gewicht,
  369. const zaehl_t* uh1, const zaehl_t* uh2, const zaehl_t* uh3,
  370. const zaehl_t* uh11, const zaehl_t* uh12,
  371. const zaehl_t* uh22, const zaehl_t* uh1l,
  372. const zaehl_t* uh1s, const zaehl_t* uh2l,
  373. const zaehl_t* uh2s, zaehl_t ll, zaehl_t ls, zaehl_t ss,
  374. const std::unordered_map<char32_t, zaehl_t>& unbekannt,
  375. std::unordered_map<char32_t, zaehl_t>& summe_unbekannt);
  376. haeufigkeit_t& ein(int p, int e)
  377. { assert(p < ntaste && e < nebene); return h1[p][e]; }
  378. haeufigkeit_t& ein_k(int korpus, int p, int e) {
  379. assert(korpus < nkorpus && p < ntaste && e < nebene);
  380. return h1e[korpus][p][e];
  381. }
  382. haeufigkeit_t& bi(int p1, int e1, int p2, int e2){
  383. assert(p1 < ntaste && e1 < nebene && p2 < ntaste && e2 < nebene2);
  384. return h2[p1][p2][e1][e2];
  385. }
  386. haeufigkeit_t& tri(int p1, int p2, int p3, int e3){
  387. assert(p1 < ntaste && p2 < ntaste && p3 < ntaste && e3 < nebene);
  388. return h3[p1][p2][p3][e3];
  389. }
  390.  
  391. haeufigkeit_t& ein_ein(int oi, int oj){
  392. assert(h11 && oi < groesse1 && oj < groesse1);
  393. return h11[sym_index(oi, oj)];
  394. }
  395. haeufigkeit_t& ein_k_ein_k(int korpus, int oi, int oj){
  396. assert(korpus<nkorpus && h11ee[korpus] && oi < groesse1 && oj < groesse1);
  397. return h11ee[korpus][sym_index(oi, oj)];
  398. }
  399. haeufigkeit_t& ein_ein_k(int korpus, int oi, int oj){
  400. assert(korpus<nkorpus && h11e[korpus] && oi < groesse1 && oj < groesse1);
  401. return h11e[korpus][index_bi_flach(oi, oj)];
  402. }
  403. haeufigkeit_t& ein_bi(int ok, int oij){
  404. assert(h21 && ok < groesse1 && oij < groesse2);
  405. return h21[index_tri21_flach(oij, ok)];
  406. }
  407. haeufigkeit_t& ein_k_bi(int korpus, int ok, int oij){
  408. assert(korpus<nkorpus && h21e[korpus] && ok < groesse1 && oij < groesse2);
  409. return h21e[korpus][index_tri21_flach(oij, ok)];
  410. }
  411. haeufigkeit_t& bi_bi(int oij, int okl){
  412. assert(h22 && oij < groesse2 && okl < groesse2);
  413. return h22[sym_index(oij, okl)];
  414. }
  415.  
  416. void varianzen_anlegen();
  417.  
  418. public:
  419. Haeufigkeit(const Tastatur& tastatur, const Kodierung& kodierung,
  420. const std::vector<std::string>& basis,
  421. const std::vector<double>& gewicht,
  422. const std::vector<bool>& t,
  423. bool varianzen,
  424. bool berichte_unbekanne_zeichen);
  425. Haeufigkeit(const Haeufigkeit&) = delete;
  426. // das int-Argument dient lediglich der Unterscheidung vom Copy-Konstruktor
  427. Haeufigkeit(const Haeufigkeit&, int);
  428.  
  429. void setze(const Haeufigkeit& h, const belegung_t p);
  430. void swap(int p1, int p2);
  431.  
  432. ~Haeufigkeit();
  433.  
  434. haeufigkeit_t operator()(int p, int e) const
  435. { assert(p < ntaste && e < nebene); return h1[p][e]; }
  436. haeufigkeit_t operator()(int p1, int e1, int p2, int e2) const {
  437. assert(p1 < ntaste && e1 < nebene && p2 < ntaste && e2 < nebene2);
  438. return h2[p1][p2][e1][e2];
  439. }
  440. haeufigkeit_t operator()(int korpus, int p, int e) const {
  441. assert(korpus < nkorpus && p < ntaste && e < nebene);
  442. return h1e[korpus][p][e];
  443. }
  444. haeufigkeit_t tri(int p1, int p2, int p3, int e3) const {
  445. assert(trigramme && p1 < ntaste && p2 < ntaste && p3 < ntaste &&
  446. e3 < nebene);
  447. return h3[p1][p2][p3][e3];
  448. }
  449. int num_korpus() const { return nkorpus; }
  450. haeufigkeit_t gewicht(int korpus) const
  451. { assert(korpus < nkorpus); return gewichte[korpus]; }
  452. bool mit_trigrammen() const { return trigramme; }
  453. bool mit_varianzen() const { return h11 != nullptr; }
  454.  
  455. haeufigkeit_t ein_ein(int oi, int oj) const {
  456. assert(h11 && oi < groesse1 && oj < groesse1);
  457. return h11[sym_index(oi, oj)];
  458. }
  459. haeufigkeit_t ein_k_ein_k(int korpus, int oi, int oj) const {
  460. assert(korpus<nkorpus && h11ee[korpus] && oi < groesse1 && oj < groesse1);
  461. return h11ee[korpus][sym_index(oi, oj)];
  462. }
  463. haeufigkeit_t ein_ein_k(int korpus, int oi, int oj) const {
  464. assert(korpus<nkorpus && h11e[korpus] && oi < groesse1 && oj < groesse1);
  465. return h11e[korpus][index_bi_flach(oi, oj)];
  466. }
  467. haeufigkeit_t ein_bi(int ok, int oij) const {
  468. assert(h21 && ok < groesse1 && oij < groesse2);
  469. return h21[index_tri21_flach(oij, ok)];
  470. }
  471. haeufigkeit_t ein_k_bi(int korpus, int ok, int oij) const {
  472. assert(korpus<nkorpus && h21e[korpus] && ok < groesse1 && oij < groesse2);
  473. return h21e[korpus][index_tri21_flach(oij, ok)];
  474. }
  475. haeufigkeit_t bi_bi(int oi, int oj) const {
  476. assert(h22 && oi < groesse2 && oj < groesse2);
  477. return h22[sym_index(oi, oj)];
  478. }
  479. haeufigkeit_t unbekannt() const { return hunbekannt; }
  480.  
  481. void statistik() const;
  482.  
  483. // Ein paar Hilfsroutinen, um mehrdimensionale Felder flach umzunummerieren.
  484. static int sym_index(int i1, int i2){
  485. const int k = i1 < i2 ? i1 : i2;
  486. const int g = i1 < i2 ? i2 : i1;
  487. return (g*(g+1))/2+k;
  488. }
  489. static int index_ein_flach(int tastenindex, int ebenenindex)
  490. { return tastenindex*nebene+ebenenindex; }
  491. static int index_bi_flach(int idx_ein1, int idx_ein2)
  492. { return groesse1*idx_ein1+idx_ein2; }
  493. static int index_tri21_flach(int idx_bi, int idx_ein)
  494. { return groesse1*idx_bi+idx_ein; }
  495. static int index_tri_flach(int idx_ein1, int idx_ein2, int idx_ein3)
  496. { return index_tri21_flach(index_bi_flach(idx_ein1, idx_ein2), idx_ein3); }
  497.  
  498. static constexpr int groesse1 = ntaste*nebene;
  499. static constexpr int groesse2 = groesse1*groesse1;
  500. static constexpr int groesse3 = groesse1*groesse2;
  501. static constexpr int groesse11 = (groesse1*(groesse1+1))/2;
  502. static constexpr int groesse21 = groesse1*groesse2;
  503. static constexpr int groesse22 = (groesse2*(groesse2+1))/2;
  504. };
  505.  
  506. #endif // !BELEGUNGSOPTIMIERER_HAEUFIGKEIT_H
  507.  
  508. //--------------- src/Kodierung.hh ---------------
  509. #ifndef BELEGUNGSOPTIMIERER_KODIERUNG_H
  510. #define BELEGUNGSOPTIMIERER_KODIERUNG_H
  511.  
  512. //#include "konstanten.hh"
  513. #include <string>
  514. #include <unordered_map>
  515. #include <utility>
  516. #include <vector>
  517.  
  518. class Kodierung final {
  519. std::unordered_map<char32_t, std::pair<int, int>> invers;
  520. std::unordered_map<char32_t, std::vector<std::pair<int, int>>> inversstr;
  521. std::string strings[ntaste][nebene], glyphname[ntaste], platzhalterstr;
  522. char32_t chars[ntaste][nebene];
  523. unsigned char psenc[ntaste];
  524.  
  525. public:
  526. Kodierung(const std::vector<std::u32string>& klartext,
  527. const std::vector<std::u32string>& ersatzstring,
  528. const std::vector<std::u32string>& glyph,
  529. char32_t platzhalter);
  530. bool ist_platzhalter(int i, int e) const;
  531. const std::string& txt(int i, int e) const;
  532. char32_t uchar(int i, int e) const;
  533. const std::string& bevorzugt(int i) const;
  534. const std::string& txt(int ie) const;
  535. std::pair<int, int> position(char32_t z) const;
  536. const std::vector<std::pair<int,int>>* ersatz(char32_t z) const;
  537. int psencoding(int i) const;
  538. std::string psencstr(int i) const;
  539. const std::string& psglyphname(int i) const;
  540. };
  541.  
  542. #endif // !BELEGUNGSOPTIMIERER_KODIERUNG_H
  543.  
  544. //--------------- src/Tastatur.hh ---------------
  545. #ifndef BELEGUNGSOPTIMIERER_TASTATUR_H
  546. #define BELEGUNGSOPTIMIERER_TASTATUR_H
  547.  
  548. //#include "konstanten.hh"
  549. //#include "typen.hh"
  550. #include <map>
  551. #include <string>
  552. #include <unordered_map>
  553. #include <unordered_set>
  554. #include <vector>
  555.  
  556. class Tastatur final {
  557. public:
  558. // Tests, die feststellen, ob eine Fingernummer ein bestimmter Finger
  559. // (unabhängig von der Hand) ist.
  560. static bool istDaumen(finger_t i);
  561. static bool istKleinfinger(finger_t i);
  562.  
  563. // Kurze Beschreibung der Kategorie.
  564. static const char* kategorie_str(int kategorie);
  565.  
  566. // Längere Beschreibung des Bigramms aus Taste i und j
  567. std::string kategorie_lang(int i, int j) const;
  568.  
  569. // Spaltennummer der Taste i.
  570. int spalte(int i) const;
  571. // Zeilennummer der Taste i.
  572. int zeile(int i) const;
  573.  
  574. // Finger, der Taste i betätigt; der Rückgabewert ist eine der oben
  575. // definierten Konstanten in finger_t.
  576. finger_t finger(int i) const;
  577.  
  578. // Fingerindex zu Taste i; das ist ein Wert zwischen 0 und nfinger
  579. // (einschliesslich).
  580. int finger_index(int i) const;
  581.  
  582. // Nummer der Taste, die die Shifttaste ist, die zusammen mit der
  583. // Symboltaste i benutzt wird, das heisst, die Nummer der Shifttaste, die in
  584. // der anderen Tastaturhälfte wie Taste i liegt.
  585. int shifttaste(int i) const;
  586.  
  587. // Fingerindex für den Finger, der die Shifttaste bedient, die zusammen mit
  588. // der Symboltaste i benutzt wird.
  589. int shift_finger_index(int i) const;
  590.  
  591. // Taste in der der Finger, der Taste i bedient, seine Grundstellung hat.
  592. int grundposition(int i) const;
  593.  
  594. // Die Nummer der Taste in Zeile z und Spalte s. Falls an dieser Position
  595. // keine Taste liegt, wird -1 zurückgegeben.
  596. int taste(int z, int s) const;
  597.  
  598. // Name der Taste i.
  599. const std::u32string& name(int i) const;
  600.  
  601. // Tastenname -> Tastennummer, -1 falls es den Namen nicht gibt.
  602. int taste(const std::u32string& n) const;
  603.  
  604. // Kategorie, zu der das Tastenbigramm aus Taste i gefolgt von Taste j
  605. // gehört; die Kategorie wird als eine der oben definierten Konstanten
  606. // zurückgegeben.
  607. kategorie_t kategorie(int i, int j) const;
  608.  
  609. // Benutzerdefinierte Kategorien, zu dem das Bi- oder Trigramm gemäss der
  610. // Tasten in i gehört.
  611. const std::vector<int>& benutzerkategorie(const std::vector<int>& i) const;
  612.  
  613. // Nummer eine Benutzerkategorie in Namen umwandeln.
  614. const std::string& benutzerkategorie_name(int i) const;
  615.  
  616. // Testet, ob das Tastenbigramm aus Taste i gefolgt von Taste j eine
  617. // Handwiederholung ist (dafür gibt es keine eigene Kategorie).
  618. bool istHandwiederholung(int i, int j) const;
  619.  
  620. // Prüft, ob das Tastentrigramm aus Tasten i, j und k ein Wippbewegung ist.
  621. bool istWippe(int i, int j, int k) const;
  622.  
  623. // Koordinate der Taste i; die Längeneinheit des Koordinatensystems ist die
  624. // Breite einer normalen Taste. Die Koordinate bezeichnet eine geometrische
  625. // Position.
  626. koordinate_t tastenkoord(int i) const;
  627.  
  628. // Distanz der Tasten i und j.
  629. double distanz(int i, int j) const;
  630.  
  631. // Teste, ob Finger mit Index i nur Tasten bedient, deren Belegung fest
  632. // vorgegeben ist.
  633. bool finger_fix(int i) const;
  634.  
  635. // Anzahl der Tasten, die für Zeichen gedacht sind und deren Belegung nicht
  636. // fest ist.
  637. int nvariabel() const;
  638.  
  639. // Lageaufwand der Taste i.
  640. double lageaufwand(int i) const;
  641.  
  642. Tastatur(const std::vector<taste_t>& tasten,
  643. const std::unordered_set<std::u32string>& fixe_tasten);
  644.  
  645. void neue_kategorien(const std::vector<n_gramm_t>& benutzerkategorie);
  646.  
  647. private:
  648. std::u32string namen[ntaste+nshift];
  649. int spalten[ntaste+nshift], zeilen[ntaste+nshift], nvar;
  650. finger_t fingertab[ntaste+nshift];
  651. int fingerind[ntaste+nshift];
  652. int shifttast[ntaste+nshift], sfingerind[ntaste+nshift];
  653. int grundpos[ntaste+nshift], tastennr[nzeile][nspalte];
  654. kategorie_t tastenkategorie[ntaste+nshift][ntaste+nshift];
  655. double x[ntaste+nshift], y[ntaste+nshift], aufwand[ntaste+nshift];
  656. bool fix[nfinger+1];
  657. std::unordered_map<std::u32string, int> namennr;
  658. std::vector<std::string> kategorie_liste;
  659. std::map<std::vector<int>, std::vector<int>> benutzerkat;
  660. };
  661.  
  662. #endif // !BELEGUNGSOPTIMIERER_TASTATUR_H
  663.  
  664. //--------------- src/Grafik.hh ---------------
  665. #ifndef BELEGUNGSOPTIMIERER_GRAFIK_H
  666. #define BELEGUNGSOPTIMIERER_GRAFIK_H
  667.  
  668. //#include "typen.hh"
  669. #include <fstream>
  670. #include <string>
  671.  
  672. class Haeufigkeit;
  673. class Kodierung;
  674. class Konfiguration;
  675. class Tastatur;
  676.  
  677. class Grafik final {
  678. std::ofstream grafik;
  679. int seite;
  680. bool ungerade;
  681. const Tastatur& tastatur;
  682. const Kodierung& kodierung;
  683. public:
  684. Grafik(const std::string& name, const Tastatur& tastatur,
  685. const Kodierung& kodierung, const Haeufigkeit& h,
  686. const Konfiguration& konfiguration);
  687. ~Grafik();
  688. void ausgabe(const belegung_t b);
  689. };
  690.  
  691. #endif // !BELEGUNGSOPTIMIERER_GRAFIK_H
  692.  
  693. //--------------- src/Statistik.hh ---------------
  694. #ifndef BELEGUNGSOPTIMIERER_STATISTIK_H
  695. #define BELEGUNGSOPTIMIERER_STATISTIK_H
  696.  
  697. //#include "konstanten.hh"
  698. //#include "typen.hh"
  699. #include <map>
  700. #include <string>
  701.  
  702. class Aufwandstabelle;
  703. class Haeufigkeit;
  704. class Kodierung;
  705. class Tastatur;
  706.  
  707. struct Statistik {
  708. akkumuations_t aeinzel = 0;
  709. haeufigkeit_t hpos[2][nzeile] = { { 0, 0, 0, 0, 0 },
  710. { 0, 0, 0, 0, 0 } };
  711. haeufigkeit_t hk[kategorie_t::nKategorie] = { 0 };
  712. haeufigkeit_t hs[kategorie_t::nKategorie] = { 0 };
  713. haeufigkeit_t hi0[kategorie_t::nKategorie] = { 0 };
  714. haeufigkeit_t hi2[kategorie_t::nKategorie] = { 0 };
  715. haeufigkeit_t hfinger[nfinger+1] = { 0 };
  716. haeufigkeit_t hkollision1[nfinger] = { 0 }, hkollision2[nfinger] = { 0 };
  717. haeufigkeit_t hskollision1[nshift] = { 0 }, hskollision2[nshift] = { 0 };
  718. haeufigkeit_t hnachbar1[nfinger] = { 0 }, hnachbar2[nfinger] = { 0 };
  719. haeufigkeit_t hsnachbar1[nshift] = { 0 }, hsnachbar2[nshift] = { 0 };
  720. haeufigkeit_t h1tot = 0, h2tot = 0, hs2tot = 0, h3tot = 0;
  721. haeufigkeit_t hlinks = 0, hrechts = 0, hslinks = 0, hsrechts = 0;
  722. haeufigkeit_t hnachbar = 0, hsnachbar = 0;
  723. haeufigkeit_t hwippe = 0, hdoppelhw = 0, hkeinhw = 0;
  724. haeufigkeit_t hrel[3][2] = { {0,0}, {0,0}, {0,0} };
  725. bool mitfinger[nfinger+1] = { false };
  726.  
  727. std::map<int, haeufigkeit_t> hs_benutzer, hk_benutzer, ht_benutzer;
  728. std::multimap<haeufigkeit_t, std::string> ngramm[3][2];
  729.  
  730. Statistik(const belegung_t b, const Tastatur& tastatur,
  731. const Kodierung& kodierung, const Haeufigkeit& h,
  732. const Aufwandstabelle& a, const double ngrammakkumlimit[3]);
  733. };
  734.  
  735. #endif // !BELEGUNGSOPTIMIERER_STATISTIK_H
  736.  
  737. //--------------- src/Konfiguration.hh ---------------
  738. #ifndef BELEGUNGSOPTIMIERER_KONFIGURATION_H
  739. #define BELEGUNGSOPTIMIERER_KONFIGURATION_H
  740.  
  741. //#include "konstanten.hh"
  742. #include <memory>
  743. #include <string>
  744. #include <vector>
  745.  
  746. class Tastatur;
  747. class Kodierung;
  748.  
  749. class Konfiguration final {
  750. // Unnormierte Zielhäufigkeit für Finger von links nach rechts
  751. double fh_unnorm[nfinger];
  752. // Die Häufigkeiten der Tastendrücke werden auf 1 normiert, positive
  753. // Abweichungen von den normierten Zielhäufigkeiten quadriert, mit folgenden
  754. // Gewichten multipliziert und zur Gesamtaufwand addiert:
  755. double mf_input[nfinger];
  756. // Multiplikator für Shift-Bigramme. Mit diesem Faktor werden die normalen
  757. // Bigrammaufwände für die Bigramme aus erster und letzter Taste (Shift und
  758. // zweite Symboltaste) in diesen Tastentrigrammen multipliziert. Erster
  759. // Wert für normale Bigramme mit positivem Gewicht, zweiter mit negativem
  760. // Gewicht.
  761. double mult_shiftindirekt[2];
  762. // Multiplikator Trigramme, die aufgrund von Bigrammen aus erster und
  763. // letzter Taste des Trigramms bewertet werden. Erster Wert für normale
  764. // Bigramme mit positivem Gewicht, zweiter mit negativem Gewicht.
  765. double mult_indirekt[2];
  766. // Der Bequemlichkeit halber haben wir für verschiedene Bigrammkategorien
  767. // Vorfaktoren für den Aufwand eingeführt.
  768. double mult_handwiederholung, mult_auswaerts, mult_handwechsel;
  769. double mult_doppelkomp, mult_zeilenkomp[5];
  770. // Für Bigramme ohne Hand-, aber mit Zeilenwechsel
  771. double mult_schraegZS[2];
  772. double mult_schraegYX[2];
  773. double add_schraegDX[2];
  774. // Fixer Anteil des Aufwand für jede Kollision, Daumen...Kleinfinger
  775. double mult_kollision_konstant[5];
  776. // Variabler Anteil, wird mit Tastenabstand multipliziert,
  777. // Daumen...Kleinfinger
  778. double mult_kollision_distanz[5];
  779. // Nachbarstrafe Daumen/Zeigefinger, Zeige/Mittelfinger, Mittel/Ringfinger,
  780. // Ringfinger/Kleinfinger
  781. double nachbarstrafe[4];
  782. // Mit diesen Parametern kann für Trigramme mit zwei Handwechseln
  783. // bzw. solche ganz ohne Handwechsel einen zusätzlichen Aufwand anrechnen.
  784. double mult_doppelwechsel, mult_doppelwiederholung, mult_wippe;
  785. // Beliebige Bi- und Trigramme
  786. double bigramm_roh[ntaste+nshift][ntaste+nshift];
  787. double trigramm_roh[ntaste+nshift][ntaste+nshift][ntaste+nshift];
  788. // Für Verwechslungspotenzial/Ähnlichkeit
  789. double mult_kollision, mult_nachbar, mult_symmetrisch;
  790. double mult_symmetrisch_gleichzeile, mult_hand_verschieden;
  791. double verwechslungspotenzial_roh[ntaste+nshift][ntaste+nshift];
  792. double aehnlichkeit_roh[ntaste][ntaste];
  793. // Vorlieben
  794. double vorliebe_roh[ntaste][ntaste];
  795. double vorliebe_knick;
  796. // Aufwand aufgrund nicht unterstützter Zeichen.
  797. double aunbekannt;
  798. // Die Schriftarten in Postscriptgrafiken.
  799. std::string _zeichenfont, _beschreibungsfont;
  800. public:
  801. Konfiguration(const std::vector<std::string>& namen,
  802. std::unique_ptr<const Tastatur>& tastatur,
  803. std::unique_ptr<const Kodierung>& kodierung);
  804.  
  805. // Aufwand für Bigramm der Tasten i und j.
  806. double bigrammaufwand(int i, int j, const Tastatur& tastatur) const;
  807.  
  808. // Aufwand für Trigramm der Tasten i, j und k.
  809. double trigrammaufwand(int i, int j, int k, const Tastatur& tastatur) const;
  810.  
  811. // Das Risiko, Tasten i und j zu verwechseln, ausgedrückt als Aufwand.
  812. double verwechslungspotenzial(int i, int j, const Tastatur& tastatur) const;
  813.  
  814. double vorliebe(int i, int j) const;
  815. double vorliebenknick() const;
  816. double aehnlichkeit(int i, int j) const;
  817. double shiftindirekt(double a) const;
  818. double indirekt(double a) const;
  819. double zielhaeufigkeit(int f) const;
  820. double multfinger(int f) const;
  821. double unbekannt() const;
  822.  
  823. const std::string& zeichenfont() const ;
  824. const std::string& beschreibungsfont() const;
  825. };
  826.  
  827. #endif // !BELEGUNGSOPTIMIERER_KONFIGURATION_H
  828.  
  829. //--------------- src/Aufwandstabelle.hh ---------------
  830. #ifndef BELEGUNGSOPTIMIERER_AUFWANDSTABELLE_H
  831. #define BELEGUNGSOPTIMIERER_AUFWANDSTABELLE_H
  832.  
  833. //#include "konstanten.hh"
  834. //#include "typen.hh"
  835. #include <cassert>
  836.  
  837. class Kodierung;
  838. class Konfiguration;
  839. class Tastatur;
  840.  
  841. class Aufwandstabelle final {
  842. aufwand_t a3[ntaste][ntaste][ntaste][nebene];
  843. aufwand_t va2[ntaste][ntaste], vl[ntaste][ntaste], vl_knick;
  844. aufwand_t ae[ntaste][ntaste], a2[ntaste][ntaste][nebene][nebene2];
  845. aufwand_t a1[ntaste][nebene], multfinger[nfinger], aunbekannt;
  846. haeufigkeit_t finger_zielhaeufigkeit[nfinger];
  847. const bool mit_trigrammen;
  848. bool mit_vorlieben, mit_aehnlichkeit;
  849.  
  850. const Tastatur& tastatur;
  851. public:
  852. Aufwandstabelle(bool mit_trigrammen, const Tastatur&,
  853. const Konfiguration&);
  854.  
  855. aufwand_t operator()(int p, int e) const
  856. { assert(p < ntaste && e < nebene); return a1[p][e]; }
  857. aufwand_t operator()(int p1, int e1, int p2, int e2) const {
  858. assert(p1 < ntaste && e1 < nebene && p2 < ntaste && e2 < nebene2);
  859. return a2[p1][p2][e1][e2];
  860. }
  861. aufwand_t tri(int p1, int p2, int p3, int e3) const {
  862. assert(p1 < ntaste && p2 < ntaste && p3 < ntaste && e3 < nebene);
  863. return a3[p1][p2][p3][e3];
  864. }
  865. akkumuations_t fingerabweichung(int i, akkumuations_t rel) const {
  866. assert(i < nfinger); assert(rel <= 1);
  867. return rel-finger_zielhaeufigkeit[i];
  868. }
  869. aufwand_t mult_finger(int fi) const { return multfinger[fi]; }
  870. aufwand_t unbekannt() const { return aunbekannt; }
  871.  
  872. aufwand_t verwechslungspotenzial(int i, int j) const
  873. { assert(i < ntaste && j < ntaste); return va2[i][j]; }
  874. bool hat_aehnlichkeit() const { return mit_aehnlichkeit; }
  875. aufwand_t aehnlichkeit(int i, int j) const
  876. { assert(i < ntaste && j < ntaste); return ae[i][j]; }
  877. bool hat_vorlieben() const { return mit_vorlieben; }
  878. aufwand_t vorliebe(int z, int p) const
  879. { assert(z < ntaste && p < ntaste); return vl[z][p]; }
  880. void anzeigen(const Kodierung&, const Konfiguration&) const;
  881.  
  882. aufwand_t vorliebenknick() const { return vl_knick; }
  883. aufwand_t knick(aufwand_t v) const
  884. { return v < vl_knick ? vl_knick : v; }
  885. };
  886.  
  887. #endif // !BELEGUNGSOPTIMIERER_AUFWANDSTABELLE_H
  888.  
  889. //--------------- src/string_in_belegung.hh ---------------
  890. #ifndef BELEGUNGSOPTIMIERER_STRING_IN_BELEGUNG_H
  891. #define BELEGUNGSOPTIMIERER_STRING_IN_BELEGUNG_H
  892.  
  893. //#include "typen.hh"
  894. #include <string>
  895.  
  896. class Kodierung;
  897.  
  898. void string_in_belegung(const std::u32string& z, belegung_t b, bool* fest,
  899. int nv, const Kodierung& kodierung);
  900.  
  901. #endif //!BELEGUNGSOPTIMIERER_STRING_IN_BELEGUNG_H
  902.  
  903. //--------------- src/html_markup.hh ---------------
  904. #ifndef BELEGUNGSOPTIMIERER_HTML_MARKUP_H
  905. #define BELEGUNGSOPTIMIERER_HTML_MARKUP_H
  906.  
  907. #include <string>
  908.  
  909. class Kodierung;
  910. class Tastatur;
  911.  
  912. void html_markup(const std::string& textfile,
  913. const Kodierung& kodierung,
  914. const Tastatur& tastatur,
  915. const std::string& referenztastatur);
  916.  
  917. #endif // !BELEGUNGSOPTIMIERER_HTML_MARKUP_H
  918.  
  919. //--------------- src/schreibe_belegung.hh ---------------
  920. #ifndef BELEGUNGSOPTIMIERER_SCHREIBE_BELEGUNG_H
  921. #define BELEGUNGSOPTIMIERER_SCHREIBE_BELEGUNG_H
  922.  
  923. //#include "typen.hh"
  924. #include <string>
  925. #include <unordered_map>
  926.  
  927. class Aufwandstabelle;
  928. class Haeufigkeit;
  929. class Kodierung;
  930. class Tastatur;
  931.  
  932. void
  933. schreibe_belegung(const belegung_t b, const Tastatur& tastatur,
  934. const Kodierung& kodierung, const Haeufigkeit& h,
  935. const Aufwandstabelle& a, const akkumuations_t A,
  936. const std::u32string& name,
  937. const double ngrammakkumlimit[3],
  938. const std::unordered_map<std::string, haeufigkeit_t>&
  939. wortliste,
  940. const akkumuations_t handeinsatzlimit,
  941. bool als_fixeszeichen);
  942.  
  943. void
  944. schreibe_belegung(const belegung_t b, double A, int nv,
  945. const Kodierung& kodierung,
  946. const std::u32string* name);
  947.  
  948. void
  949. schreibe_zyklen(const belegung_t b1, const belegung_t b2,
  950. const Kodierung& kodierung);
  951.  
  952. #endif // !BELEGUNGSOPTIMIERER_SCHREIBE_BELEGUNG_H
  953.  
  954. //--------------- src/trennen.hh ---------------
  955. #ifndef BELEGUNGSOPTIMIERER_TRENNEN_H
  956. #define BELEGUNGSOPTIMIERER_TRENNEN_H
  957.  
  958. //#include "Naechstes_zeichen.hh"
  959. #include <string>
  960. #include <unordered_map>
  961. #include <vector>
  962.  
  963. class hole_mit_trennung final : public Naechstes_zeichen {
  964. std::unordered_map<std::u32string, std::vector<char>> trennmuster;
  965. std::u32string wort;
  966. std::vector<bool> trennstellen;
  967. std::unordered_map<std::u32string, std::vector<bool>> cache;
  968. size_t wort_i, maxlen;
  969. bool naechste_ist_trennung;
  970. char32_t rest;
  971.  
  972. char32_t fuelle_buffer();
  973. public:
  974. hole_mit_trennung(const std::string& name, const std::string& tmfile,
  975. bool utf8);
  976. char32_t get() override;
  977. };
  978.  
  979. void markiere_alle_trennstellen(const std::string& ein, const std::string& aus,
  980. const std::string& trennmuster);
  981.  
  982. #endif // !BELEGUNGSOPTIMIERER_TRENNEN_H
  983.  
  984. //--------------- src/wortliste.hh ---------------
  985. #ifndef BELEGUNGSOPTIMIERER_WORTLISTE_H
  986. #define BELEGUNGSOPTIMIERER_WORTLISTE_H
  987.  
  988. //#include "typen.hh"
  989. #include <string>
  990. #include <unordered_map>
  991.  
  992. class Kodierung;
  993.  
  994. void lies_wortliste(const std::string& name,
  995. std::unordered_map<std::u32string, zaehl_t>& wl,
  996. bool muss_existieren);
  997.  
  998. void lies_wortliste(const std::string name,
  999. std::unordered_map<std::string, haeufigkeit_t>& wortliste,
  1000. const Kodierung& kodierung);
  1001.  
  1002. #endif // !BELEGUNGSOPTIMIERER_WORTLISTE_H
  1003.  
  1004. //--------------- src/vollkorpus.hh ---------------
  1005. #ifndef BELEGUNGSOPTIMIERER_VOLLKORPUS_H
  1006. #define BELEGUNGSOPTIMIERER_VOLLKORPUS_H
  1007.  
  1008. //#include "typen.hh"
  1009. #include <cstdint>
  1010. #include <string>
  1011. #include <unordered_map>
  1012.  
  1013. void lies_vollkorpus(const std::string& name, const std::string* trennmuster,
  1014. std::unordered_map<std::u32string, zaehl_t>& wl,
  1015. std::unordered_map<uint64_t, zaehl_t> uh[3]);
  1016.  
  1017.  
  1018. #endif // !BELEGUNGSOPTIMIERER_VOLLKORPUS_H
  1019.  
  1020. //--------------- src/ngramme.hh ---------------
  1021. #ifndef BELEGUNGSOPTIMIERER_NGRAMME_H
  1022. #define BELEGUNGSOPTIMIERER_NGRAMME_H
  1023.  
  1024. #include <string>
  1025. #include <vector>
  1026.  
  1027. void erzeuge_ngrammtabellen(const std::vector<std::string>& namen);
  1028.  
  1029. #endif // !BELEGUNGSOPTIMIERER_NGRAMME_H
  1030.  
  1031. //--------------- src/berechnungen.hh ---------------
  1032. #ifndef BELEGUNGSOPTIMIERER_BERECHNUNGEN_H
  1033. #define BELEGUNGSOPTIMIERER_BERECHNUNGEN_H
  1034.  
  1035. //#include "typen.hh"
  1036. #include <unordered_map>
  1037.  
  1038. class Aufwandstabelle;
  1039. class Grafik;
  1040. class Haeufigkeit;
  1041. class Kodierung;
  1042. class Tastatur;
  1043.  
  1044. void
  1045. suche_optimum(const Tastatur& tastatur, const Kodierung& kodierung,
  1046. const Haeufigkeit* korpus, const Aufwandstabelle& a,
  1047. akkumuations_t minimum, bool schoene_tastatur, bool alle_guten,
  1048. bool als_fixeszeichen, int saatwert, int iterationen,
  1049. int lebenszeichen, const double ngrammakkumlimit[3],
  1050. const std::unordered_map<std::string, haeufigkeit_t>& wortliste,
  1051. akkumuations_t handeinsatzlimit, Grafik* grafik,
  1052. akkumuations_t* globalesMinimum);
  1053.  
  1054. double anzahl_varianten(int N, int n);
  1055.  
  1056. void
  1057. erzeuge_variationen(const belegung_t ausgangsbelegung,
  1058. const Tastatur& tastatur, const Kodierung& kodierung,
  1059. Haeufigkeit& h, const Aufwandstabelle& a,
  1060. akkumuations_t A, int tiefe,
  1061. akkumuations_t limit, const bool* fest);
  1062.  
  1063. akkumuations_t
  1064. aufwandsvarianz(const belegung_t b1, const belegung_t* b2,
  1065. const Tastatur& tastatur,
  1066. const Haeufigkeit& h,
  1067. const Aufwandstabelle& a);
  1068.  
  1069. // Konstanter (belegungsunabhängiger) Aufwand.
  1070. akkumuations_t
  1071. konstanter_aufwand(const Haeufigkeit& h, const Aufwandstabelle& a);
  1072.  
  1073. // Variabler (belegungsabhängiger) Aufwand.
  1074. akkumuations_t
  1075. variabler_aufwand(const belegung_t b, const Haeufigkeit& h,
  1076. const Tastatur& tastatur, const Aufwandstabelle& a);
  1077.  
  1078. #endif // !BELEGUNGSOPTIMIERER_BERECHNUNGEN_H
  1079.  
  1080. //--------------- src/Konfiguration.cc ---------------
  1081. //#include "Konfiguration.hh"
  1082.  
  1083. //#include "Eingabestream.hh"
  1084. //#include "Kodierung.hh"
  1085. //#include "Tastatur.hh"
  1086. //#include "typen.hh"
  1087. //#include "utfhilfe.hh"
  1088. #include <cassert>
  1089. #include <cmath>
  1090. #include <iostream>
  1091. #include <limits>
  1092. #include <map>
  1093. #include <unordered_map>
  1094. #include <utility>
  1095.  
  1096. namespace {
  1097.  
  1098. using herkunft_t = std::pair<size_t, std::string>;
  1099. using str_herkunft_t = std::unordered_map<std::u32string, herkunft_t>;
  1100. using char_herkunft_t = std::unordered_map<char32_t, herkunft_t>;
  1101. using zs_herkunft_t =
  1102. std::map<std::pair<int, int>, std::pair<std::u32string, int>>;
  1103. using gpos_herkunft_t = std::unordered_map<int, std::u32string>;
  1104.  
  1105. std::u32string hole_string(Eingabestream& f, size_t lmin = 0,
  1106. size_t lmax = std::numeric_limits<size_t>::max()){
  1107. std::u32string w;
  1108. if(f.hole_string(w)){
  1109. if(w.length() >= lmin && w.length() <= lmax) return w;
  1110. std::cerr << SPRACHE("Der String '", "The string '")
  1111. << utf32_in_ausgabe(w) << SPRACHE("' ist zu ", "' is too ")
  1112. << (w.length() < lmin
  1113. ? SPRACHE("kurz", "short") : SPRACHE("lang", "long"))
  1114. << (w.length() < lmin ? ". Minimal" : ". Maximal")
  1115. << SPRACHE("e L" strAe "nge: ", " length: ")
  1116. << (w.length() < lmin ? lmin : lmax) << std::endl;
  1117. }else{
  1118. std::cerr << SPRACHE("Ein String wurde erwartet, das abschliessende Anf"
  1119. strUe "hrungszeichen jedoch nicht gefunden.",
  1120. "A string has been expected, however, the closing "
  1121. "quotation mark has not been found.") << std::endl;
  1122. }
  1123. f.fehler();
  1124. }
  1125.  
  1126. std::u32string hole_wort(Eingabestream& f){
  1127. std::u32string w;
  1128. if(f.hole_wort(w)) return w;
  1129. f.fehler();
  1130. }
  1131.  
  1132. void pruefe_tastenname(Eingabestream& f, const std::u32string& name,
  1133. const str_herkunft_t& tn_herkunft)
  1134. {
  1135. if(tn_herkunft.find(name) == tn_herkunft.end()){
  1136. std::cerr << SPRACHE("Die Taste '", "The key '") << utf32_in_ausgabe(name)
  1137. << SPRACHE("' ist unbekannt.", "' is not known.") << std::endl;
  1138. f.fehler();
  1139. }
  1140. }
  1141.  
  1142. std::vector<std::u32string>
  1143. hole_tastenliste(Eingabestream& f, const str_herkunft_t& tn_herkunft){
  1144. std::vector<std::u32string> namen;
  1145. std::u32string name;
  1146. while(f.hole_wort(name)){
  1147. pruefe_tastenname(f, name, tn_herkunft);
  1148. namen.push_back(name);
  1149. }
  1150. if(namen.size() >= 1) return namen;
  1151. std::cerr << SPRACHE("Die Liste von Tasten darf nicht leer sein.",
  1152. "The list of keys must not be empty.") << std::endl;
  1153. f.fehler();
  1154. }
  1155.  
  1156. int hole_int(Eingabestream& f, int rmin = -std::numeric_limits<int>::max(),
  1157. int rmax = std::numeric_limits<int>::max()){
  1158. const double w = hole_zahl(f, rmin, rmax);
  1159. const int i = static_cast<int>(w);
  1160. if(static_cast<double>(i) != w){
  1161. std::cerr << SPRACHE("Ganze Zahl erwartet, ",
  1162. "Expected an integer, found ") << w
  1163. << SPRACHE(" gefunden.", ".") << std::endl;
  1164. f.fehler();
  1165. }
  1166. return i;
  1167. }
  1168.  
  1169. bool hole_flag(Eingabestream& f){
  1170. bool w;
  1171. if(f.hole_flag(w)) return w;
  1172. std::cerr << SPRACHE(
  1173. "Ein Flag ('-' oder '+') wurde erwartet, jedoch nicht gefunden.",
  1174. "A flag ('-' or '+') has been expected, however, none was found.")
  1175. << std::endl;
  1176. f.fehler();
  1177. }
  1178.  
  1179. void das_wars(Eingabestream& f){
  1180. if(!f.zeilenende()){
  1181. if(f.ist(U'#')) f.uebergehen();
  1182. else{
  1183. std::cerr << SPRACHE(strUe "berf" strUe "ssiger Text am Zeilenende.",
  1184. "Excess input at end of the line.") << std::endl;
  1185. f.fehler();
  1186. }
  1187. }
  1188. }
  1189.  
  1190. std::u32string hole_wort_oder_leer(Eingabestream& f){
  1191. std::u32string w = U"";
  1192. if(!f.zeilenende() && !f.ist(U'#')) f.hole_wort(w);
  1193. return w;
  1194. }
  1195.  
  1196. std::u32string hole_string_oder_leer(Eingabestream& f){
  1197. if(!f.zeilenende() && !f.ist(U'#')) return hole_string(f, 1);
  1198. return U"";
  1199. }
  1200.  
  1201. int hole_flag_oder_leer(Eingabestream& f){
  1202. if(!f.zeilenende() && !f.ist(U'#')) return hole_flag(f) ? 1 : -1;
  1203. return 0;
  1204. }
  1205.  
  1206. void schonmal(Eingabestream& f, herkunft_t& h){
  1207. std::cerr << SPRACHE("' wurde bereits in File ",
  1208. "' has already been introduced in file ")
  1209. << h.second << SPRACHE(", Zeile ", ", line ")
  1210. << h.first << SPRACHE(" eingef" strUe "hrt.", ".") << std::endl;
  1211. }
  1212.  
  1213. void tastenname_eindeutigkeit(Eingabestream& f, const std::u32string& name,
  1214. str_herkunft_t& tn_herkunft){
  1215. const auto p = tn_herkunft.find(name);
  1216. if(p != tn_herkunft.end()){
  1217. std::cerr << SPRACHE("Der Tastenname '", "The key name '")
  1218. << utf32_in_ausgabe(name);
  1219. schonmal(f, p->second);
  1220. f.fehler();
  1221. }
  1222. tn_herkunft[name] = std::make_pair(f.aktuelle_zeile(), f.aktuelles_file());
  1223. }
  1224.  
  1225. void fixtasten_eindeutigkeit(Eingabestream& f, const std::u32string& name,
  1226. str_herkunft_t& herkunft){
  1227. const auto p = herkunft.find(name);
  1228. if(p != herkunft.end()){
  1229. std::cerr << SPRACHE("Der Tastenname '", "The key name '")
  1230. << utf32_in_ausgabe(name)
  1231. << SPRACHE("' wurde in File ", "' has already been used for "
  1232. "'FixesZeichen' in file ")
  1233. << p->second.second << SPRACHE(", Zeile ", ", line ")
  1234. << p->second.first
  1235. << SPRACHE(" bereits f" strUe "r 'FixesZeichen' verwendet.",".")
  1236. << std::endl;
  1237. f.fehler();
  1238. }
  1239. herkunft[name] = std::make_pair(f.aktuelle_zeile(), f.aktuelles_file());
  1240. }
  1241.  
  1242. void zs_eindeutigkeit(Eingabestream& f, int spalte, int zeile, int finger,
  1243. const std::u32string& name, zs_herkunft_t& zs_herkunft){
  1244. const auto zs = std::make_pair(spalte, zeile);
  1245. const auto p = zs_herkunft.find(zs);
  1246. if(p != zs_herkunft.end() && p->second.second != finger){
  1247. std::cerr << SPRACHE("Spalte ", "Column ") << spalte
  1248. << SPRACHE(", Zeile ", " row ") << zeile
  1249. << SPRACHE(" wurde bereits der Taste '",
  1250. " has already been assigned to the key '")
  1251. << utf32_in_ausgabe(p->second.first)
  1252. << SPRACHE("' zugewiesen, und diese ist Finger ",
  1253. "' which is associated to finger ")
  1254. << p->second.second
  1255. << SPRACHE(" statt Finger ", " instead of finger ")
  1256. << finger
  1257. << SPRACHE(" zugeordnet.", ".") << std::endl;
  1258. f.fehler();
  1259. }
  1260. zs_herkunft[zs] = std::make_pair(name, finger);
  1261. }
  1262.  
  1263. void gpos_eindeutigkeit(Eingabestream& f, int finger,
  1264. const std::u32string& name,
  1265. gpos_herkunft_t& gpos_herkunft){
  1266. const auto p = gpos_herkunft.find(finger);
  1267. if(p != gpos_herkunft.end()){
  1268. std::cerr << "Finger " << finger
  1269. << SPRACHE(" wurde bereits die Taste '",
  1270. " has been assigned the key '")
  1271. << utf32_in_ausgabe(p->second)
  1272. << SPRACHE("' als Grundposition zugewiesen.",
  1273. "' as rest position already.") << std::endl;
  1274. f.fehler();
  1275. }
  1276. gpos_herkunft[finger] = name;
  1277. }
  1278.  
  1279. taste_t hole_taste(Eingabestream& f, str_herkunft_t& tn_herkunft,
  1280. zs_herkunft_t& zs_herkunft,
  1281. gpos_herkunft_t& gpos_herkunft, int minf,int maxf)
  1282. {
  1283. const std::u32string name = hole_wort(f);
  1284. tastenname_eindeutigkeit(f, name, tn_herkunft);
  1285. const int spalte = hole_int(f, 0,nspalte-1);
  1286. const int zeile = hole_int(f, 0, nzeile-1);
  1287. const double x = hole_zahl(f, -5., 20.), y = hole_zahl(f, -5., 10.);
  1288. const finger_t finger(hole_int(f, minf, maxf));
  1289. zs_eindeutigkeit(f, spalte, zeile, finger, name, zs_herkunft);
  1290. const bool gpos = hole_flag(f);
  1291. if(gpos) gpos_eindeutigkeit(f, finger, name, gpos_herkunft);
  1292. const double aufwand = hole_zahl(f, 0, 1e15);
  1293. const int optss = hole_flag_oder_leer(f);
  1294. const bool seite = optss ? optss > 0 : finger > 0;
  1295. taste_t t{name, x,y, aufwand, spalte, zeile, finger, gpos, seite};
  1296. das_wars(f);
  1297. return t;
  1298. }
  1299.  
  1300. std::u32string hole_tastennamen(Eingabestream& f,
  1301. const str_herkunft_t& tn_herkunft){
  1302. const std::u32string name = hole_wort(f);
  1303. pruefe_tastenname(f, name, tn_herkunft);
  1304. return name;
  1305. }
  1306.  
  1307. void nur_bekannte_zeichen(Eingabestream& f, const std::u32string& s,
  1308. const char_herkunft_t& zeichen_herkunft){
  1309. for(size_t i = 0; i < s.length(); ++i){
  1310. if(zeichen_herkunft.find(s[i]) == zeichen_herkunft.end()){
  1311. std::cerr << SPRACHE("Das Zeichen '", "The symbol '")
  1312. << utf32_in_ausgabe(s[i])
  1313. << SPRACHE("' ist unbekannt.", "' is unknown.") << std::endl;
  1314. f.fehler(i+1);
  1315. }
  1316. }
  1317. }
  1318.  
  1319. void zeichen_eindeutigkeit(Eingabestream& f, const std::u32string& klartext,
  1320. char32_t platzhalter,
  1321. char_herkunft_t& zeichen_herkunft){
  1322. for(size_t j = 0; j < klartext.length(); ++j){
  1323. if(klartext[j] != platzhalter){
  1324. const auto p = zeichen_herkunft.find(klartext[j]);
  1325. if(p != zeichen_herkunft.end()){
  1326. std::cerr << SPRACHE("Das Zeichen '", "The symbol '")
  1327. << utf32_in_ausgabe(klartext[j]);
  1328. schonmal(f, p->second);
  1329. f.fehler(j+1);
  1330. }
  1331. }else if(j || klartext.length() == 1u){
  1332. std::cerr << SPRACHE("Das Platzhalter-Zeichen '",
  1333. "The placeholder symbol '")
  1334. << utf32_in_ausgabe(klartext[j])
  1335. << SPRACHE("' darf nur in Ebene 1 einer Taste mit "
  1336. "mehreren Ebenen erscheinen.",
  1337. "' must only appear on level 1 of a "
  1338. "key with multiple levels.") << std::endl;
  1339. f.fehler();
  1340. }
  1341. }
  1342. for(auto j : klartext)
  1343. zeichen_herkunft[j] = std::make_pair(f.aktuelle_zeile(),
  1344. f.aktuelles_file());
  1345. }
  1346.  
  1347. }
  1348.  
  1349.  
  1350.  
  1351. Konfiguration::
  1352. Konfiguration(const std::vector<std::string>& namen,
  1353. std::unique_ptr<const Tastatur>& tastatur,
  1354. std::unique_ptr<const Kodierung>& kodierung)
  1355. {
  1356. struct stdaufwaende {
  1357. double* tabelle;
  1358. size_t n;
  1359. double wmin, wmax;
  1360. };
  1361. std::unordered_map<std::u32string, stdaufwaende> aufwaende;
  1362. aufwaende[U"Zielh\u00e4ufigkeit"]= { fh_unnorm, nfinger, 0., 1e15 };
  1363. aufwaende[U"Fingerbelastung"] = { mf_input, nfinger, 0., 1e15 };
  1364. aufwaende[U"Shiftbigramm"] = { mult_shiftindirekt, 2, 0., 1. };
  1365. aufwaende[U"Indirekt"] = { mult_indirekt, 2, 0., 1. };
  1366. aufwaende[U"Handwiederholung"] = { &mult_handwiederholung, 1, -1e15, 1e15 };
  1367. aufwaende[U"Ausw\u00e4rts"] = { &mult_auswaerts, 1, -1e15, 1e15 };
  1368. aufwaende[U"Handwechsel"] = { &mult_handwechsel, 1, -1e15, 1e15 };
  1369. aufwaende[U"DoppeltRabatt"] = { &mult_doppelkomp, 1, 0., 1. };
  1370. aufwaende[U"Schr\u00e4gZS"] = { mult_schraegZS, 2, -1e15, 1e15 };
  1371. aufwaende[U"Schr\u00e4gYX"] = { mult_schraegYX, 2, -1e15, 1e15 };
  1372. aufwaende[U"Schr\u00e4gNenner0"]= { add_schraegDX, 2, 0, 1e15 };
  1373. aufwaende[U"Doppelwechsel"] = { &mult_doppelwechsel, 1, -1e15, 1e15 };
  1374. aufwaende[U"Doppelwiederholung"]= { &mult_doppelwiederholung, 1, -1e15,1e15};
  1375. aufwaende[U"Wippe"] = { &mult_wippe, 1, -1e15, 1e15 };
  1376. aufwaende[U"Fehlt"] = { &aunbekannt, 1, 0, 1e15 };
  1377. aufwaende[U"KollisionKonstant"] = { mult_kollision_konstant, 5, -1e15, 1e15};
  1378. aufwaende[U"KollisionDistanz"] = { mult_kollision_distanz, 5, -1e15, 1e15 };
  1379. aufwaende[U"Nachbar"] = { nachbarstrafe, 4, -1e15, 1e15 };
  1380. aufwaende[U"VPKollision"] = { &mult_kollision, 1, -1e15, 1e15 };
  1381. aufwaende[U"VPNachbar"] = { &mult_nachbar, 1, -1e15, 1e15 };
  1382. aufwaende[U"VPHandwechsel"] = { &mult_hand_verschieden, 1, -1e15, 1e15 };
  1383. aufwaende[U"VPSymmetrisch"] = { &mult_symmetrisch, 1, -1e15, 1e15 };
  1384. aufwaende[U"VPSymmetrischGleicheZeile"]= { &mult_symmetrisch_gleichzeile,
  1385. 1, -1e15, 1e15 };
  1386. aufwaende[U"ZeilenwiederholungRabatt"] = { mult_zeilenkomp, 5, 0., 1. };
  1387. #ifdef EXPERIMENTELL
  1388. aufwaende[U"VorliebeKnick"] = { &vorliebe_knick, 1, -1e15, 1e15 };
  1389. #endif // !EXPERIMENTELL
  1390. struct bigramm {
  1391. bigramm(const std::u32string& T1, const std::u32string& T2,
  1392. const std::u32string& N, double w)
  1393. : t1(T1), t2(T2), name(N), a(w){}
  1394. std::u32string t1, t2, name; double a;
  1395. };
  1396. struct verwechslungspotenzial {
  1397. verwechslungspotenzial(const std::u32string& T1, const std::u32string& T2,
  1398. double w) : t1(T1), t2(T2), a(w){}
  1399. std::u32string t1, t2; double a;
  1400. };
  1401. struct trigramm {
  1402. trigramm(const std::u32string& T1, const std::u32string& T2,
  1403. const std::u32string& T3, const std::u32string& N, double w)
  1404. : t1(T1), t2(T2), t3(T3), name(N), a(w){}
  1405. std::u32string t1, t2, t3, name; double a;
  1406. };
  1407. struct vorliebe {
  1408. vorliebe(const std::u32string& Z, double w,
  1409. const std::vector<std::u32string>& T) : z(Z), a(w), t(T){}
  1410. std::u32string z; double a; std::vector<std::u32string> t;
  1411. };
  1412. std::vector<bigramm> bigramme;
  1413. std::vector<trigramm> trigramme;
  1414. std::vector<verwechslungspotenzial> verwechslungspot;
  1415. std::vector<n_gramm_t> benutzerkategorien;
  1416. std::vector<std::u32string> klartext, ersatzstring, glyphnamen;
  1417. std::unordered_map<std::u32string, std::u32string> fixedtext;
  1418. std::unordered_map<std::u32string, std::u32string> fixedglyphs;
  1419. char_herkunft_t zeichen_herkunft;
  1420. gpos_herkunft_t gpos_herkunft;
  1421. zs_herkunft_t zs_herkunft;
  1422. str_herkunft_t tn_herkunft, fixtasten;
  1423. std::vector<taste_t> tasten;
  1424. std::vector<std::pair<std::u32string, double>> aehnlichkeit;
  1425. std::vector<vorliebe> vorlieben;
  1426. std::vector<bool> utf8(namen.size(), true);
  1427. taste_t ShiftL, ShiftR;
  1428. herkunft_t platzhalter_herkunft;
  1429. char32_t platzhalter;
  1430. bool mitSL, mitSR, nochmal;
  1431.  
  1432. do{
  1433. for(auto& i : fh_unnorm) i = 1;
  1434. for(auto& i : mult_shiftindirekt) i = 1;
  1435. for(auto& i : mult_indirekt) i = 1;
  1436. vorliebe_knick = 1e15;
  1437. _zeichenfont = "Courier-Bold";
  1438. _beschreibungsfont = "Courier-Bold";
  1439.  
  1440. bigramme.clear(); trigramme.clear(); verwechslungspot.clear();
  1441. klartext.clear(); glyphnamen.clear(); ersatzstring.clear();
  1442. fixedtext.clear(); fixedglyphs.clear(); fixtasten.clear();
  1443. tasten.clear(); benutzerkategorien.clear();
  1444. zeichen_herkunft.clear(); tn_herkunft.clear();
  1445. zs_herkunft.clear(); gpos_herkunft.clear();
  1446. aehnlichkeit.clear();
  1447. vorlieben.clear();
  1448. mitSL = mitSR = nochmal = false;
  1449. platzhalter = 0;
  1450. for(size_t i = 0; !nochmal && i < namen.size(); ++i){
  1451. Eingabestream f(namen[i], utf8[i]);
  1452. while(f.echte_neuezeile()){
  1453. std::u32string wort;
  1454. if(!f.hole_wort(wort)) f.fehler();
  1455. if(wort == U"Taste"){
  1456. tasten.push_back(hole_taste(f, tn_herkunft, zs_herkunft,
  1457. gpos_herkunft, -5, 5));
  1458. }else if(wort == U"ShiftL"){
  1459. ShiftL = hole_taste(f, tn_herkunft, zs_herkunft,
  1460. gpos_herkunft, -5, -1);
  1461. mitSL = true;
  1462. }else if(wort == U"ShiftR"){
  1463. ShiftR = hole_taste(f, tn_herkunft, zs_herkunft,
  1464. gpos_herkunft, 1, 5);
  1465. mitSR = true;
  1466. }else if(wort == U"Platzhalter"){
  1467. if(platzhalter){
  1468. std::cerr << "'Platzhalter";
  1469. schonmal(f, platzhalter_herkunft);
  1470. f.fehler();
  1471. }
  1472. if(klartext.size() || fixedtext.size()){
  1473. std::cerr << "'Platzhalter' "
  1474. SPRACHE("muss vor der ersten Zeichenfestlegung stehen.",
  1475. "must appear before the first symbol definition.")
  1476. << std::endl;
  1477. f.fehler();
  1478. }
  1479. platzhalter = hole_string(f, 1, 1)[0];
  1480. platzhalter_herkunft =
  1481. std::make_pair(f.aktuelle_zeile(), f.aktuelles_file());
  1482. }else if(wort == U"Zeichen"){
  1483. const auto zeichen = hole_string(f, 1);
  1484. zeichen_eindeutigkeit(f, zeichen, platzhalter, zeichen_herkunft);
  1485. klartext.push_back(zeichen);
  1486. glyphnamen.push_back(hole_wort_oder_leer(f));
  1487. das_wars(f);
  1488. }else if(wort == U"FixesZeichen"){
  1489. const auto taste = hole_tastennamen(f, tn_herkunft);
  1490. if((mitSL && taste == ShiftL.name) ||
  1491. (mitSR && taste == ShiftR.name)){
  1492. std::cerr << SPRACHE(
  1493. "Shifttasten d" strUe "rfen nicht in 'FixesZeichen' "
  1494. "verwendet werden.",
  1495. "Shift keys must not be used in 'FixesZeichen'.")
  1496. << std::endl;
  1497. f.fehler();
  1498. }
  1499. fixtasten_eindeutigkeit(f, taste, fixtasten);
  1500. const auto zeichen = hole_string(f, 1);
  1501. zeichen_eindeutigkeit(f, zeichen, platzhalter, zeichen_herkunft);
  1502. const auto glyph = hole_wort_oder_leer(f);
  1503. das_wars(f);
  1504. fixedglyphs[taste] = glyph;
  1505. fixedtext[taste] = zeichen;
  1506. }else if(wort == U"Vorliebe"){
  1507. const std::u32string s = hole_string(f, 1);
  1508. nur_bekannte_zeichen(f, s, zeichen_herkunft);
  1509. vorlieben.push_back(vorliebe{s, -hole_zahl(f, -1e15, 1e15),
  1510. hole_tastenliste(f, tn_herkunft) });
  1511. }else if(wort == U"Ersatz"){
  1512. ersatzstring.push_back(hole_string(f, 2));
  1513. das_wars(f);
  1514. }else if(wort == U"\u00c4hnlich"){
  1515. const std::u32string s = hole_string(f, 2);
  1516. nur_bekannte_zeichen(f, s, zeichen_herkunft);
  1517. aehnlichkeit
  1518. .push_back(std::make_pair(s, hole_zahl(f, 0, 1e15)));
  1519. das_wars(f);
  1520. }else if(wort == U"Bigramm"){
  1521. const std::u32string t1 = hole_tastennamen(f, tn_herkunft);
  1522. const std::u32string t2 = hole_tastennamen(f, tn_herkunft);
  1523. const double aufwand = hole_zahl(f, -1e15, 1e15);
  1524. const std::u32string name = hole_string_oder_leer(f);
  1525. das_wars(f);
  1526. bigramme.push_back(bigramm{t1, t2, name, aufwand});
  1527. }else if(wort == U"Verwechslungspotenzial"){
  1528. verwechslungspot.push_back
  1529. (verwechslungspotenzial{hole_tastennamen(f, tn_herkunft),
  1530. hole_tastennamen(f,tn_herkunft),
  1531. hole_zahl(f, -1e15, 1e15)});
  1532. if(verwechslungspot.back().t1 == verwechslungspot.back().t2){
  1533. std::cerr << SPRACHE("Ein Verwechslungspotenzial gibt es nur "
  1534. "zwischen verschiedenen Tasten.",
  1535. "Confusability only exists between "
  1536. "different keys.") << std::endl;
  1537. f.fehler();
  1538. }
  1539. das_wars(f);
  1540. }else if(wort == U"Trigramm"){
  1541. const std::u32string t1 = hole_tastennamen(f, tn_herkunft);
  1542. const std::u32string t2 = hole_tastennamen(f, tn_herkunft);
  1543. const std::u32string t3 = hole_tastennamen(f, tn_herkunft);
  1544. const double aufwand = hole_zahl(f, -1e15, 1e15);
  1545. const std::u32string name = hole_string_oder_leer(f);
  1546. das_wars(f);
  1547. trigramme.push_back(trigramm{t1, t2, t3, name, aufwand});
  1548. }else if(wort == U"Zeichenfont"){
  1549. _zeichenfont = utf32_in_ausgabe(hole_wort(f));
  1550. das_wars(f);
  1551. }else if(wort == U"Beschreibungsfont"){
  1552. _beschreibungsfont = utf32_in_ausgabe(hole_wort(f));
  1553. das_wars(f);
  1554. }else{
  1555. const auto k = aufwaende.find(wort);
  1556. if(k == aufwaende.end()){
  1557. std::cerr << SPRACHE("Unbekanntes Schl" strUe "sselwort ",
  1558. "Unknown keyword ")
  1559. << utf32_in_ausgabe(wort) << std::endl;
  1560. f.fehler();
  1561. }else{
  1562. double* a = k->second.tabelle;
  1563. const size_t n = k->second.n;
  1564. const double wmin = k->second.wmin, wmax = k->second.wmax;
  1565. for(size_t j = 0; j < n; ++j) a[j] = hole_zahl(f, wmin, wmax);
  1566. das_wars(f);
  1567. }
  1568. }
  1569. }
  1570. if(f.encoding_geaendert()){
  1571. nochmal = f.encoding_geaendert();
  1572. utf8[i] = false;
  1573. }
  1574. }
  1575. }while(nochmal);
  1576.  
  1577. if(tasten.size() != ntaste){
  1578. std::cerr << "'Taste' " SPRACHE("kommt ", "appears ")
  1579. << tasten.size() << SPRACHE(" mal vor, erwartet ist ",
  1580. " times, expected is ")
  1581. << ntaste
  1582. << SPRACHE(" mal. Sie k" strOe "nnen entweder " strAe "ndern, "
  1583. "wie oft 'Taste' vorkommt oder die erwartete "
  1584. "Tastenzahl mit der Compileroption",
  1585. " times. You can either fix the number of "
  1586. "occurrences of 'Taste', or adjust the number of "
  1587. "expected keys by using the compiler option")
  1588. " '-DTASTENZAHL=" << tasten.size()+nshift
  1589. << SPRACHE("' einstellen.", "'.") << std::endl;
  1590. exit(1);
  1591. }
  1592.  
  1593. // Die Zahl der Shifttasten festgelegen stimmen.
  1594. if(nshift != (mitSL ? 1 : 0)+(mitSR ? 1 : 0)){
  1595. if(!mitSL)
  1596. std::cerr << SPRACHE("ShiftL wurde nicht festgelegt.",
  1597. "ShiftL has not been defined.") << std::endl;
  1598. if(!mitSR)
  1599. std::cerr << SPRACHE("ShiftR wurde nicht festgelegt.",
  1600. "ShiftR has not been defined.") << std::endl;
  1601. if(mitSL && mitSR)
  1602. std::cerr << SPRACHE("ShiftL und ShiftR wurden beide festgelegt.",
  1603. "ShiftL and ShiftR have both been defined.")
  1604. << std::endl;
  1605. exit(1);
  1606. }
  1607.  
  1608. if(mitSL) tasten.push_back(ShiftL);
  1609. if(mitSR) tasten.push_back(ShiftR);
  1610.  
  1611. std::unordered_set<std::u32string> fixset;
  1612. for(const auto& i : fixtasten) fixset.insert(i.first);
  1613. Tastatur* neuetastatur = new Tastatur(tasten, fixset);
  1614. tastatur = std::unique_ptr<const Tastatur>(neuetastatur);
  1615.  
  1616. for(int i = tastatur->nvariabel(); i < ntaste; ++i){
  1617. klartext.push_back(fixedtext[tastatur->name(i)]);
  1618. glyphnamen.push_back(fixedglyphs[tastatur->name(i)]);
  1619. }
  1620. kodierung = std::unique_ptr<const Kodierung>
  1621. (new Kodierung(klartext, ersatzstring, glyphnamen, platzhalter));
  1622.  
  1623. for(const auto& i : bigramme){
  1624. const int i1 = tastatur->taste(i.t1), i2 = tastatur->taste(i.t2);
  1625. bigramm_roh[i1][i2] = i.a;
  1626. if(i.name.length())
  1627. benutzerkategorien.push_back(n_gramm_t{i1, i2, -1, i.name});
  1628. }
  1629. for(const auto& i : verwechslungspot){
  1630. const int i1 = tastatur->taste(i.t1), i2 = tastatur->taste(i.t2);
  1631. verwechslungspotenzial_roh[i1][i2] =
  1632. verwechslungspotenzial_roh[i2][i1] = i.a;
  1633. }
  1634. for(const auto& i : trigramme){
  1635. const int i1 = tastatur->taste(i.t1), i2 = tastatur->taste(i.t2);
  1636. const int i3 = tastatur->taste(i.t3);
  1637. trigramm_roh[i1][i2][i3] = i.a;
  1638. if(i.name.length())
  1639. benutzerkategorien.push_back(n_gramm_t{i1, i2, i3, i.name});
  1640. }
  1641. for(const auto& i : vorlieben){
  1642. for(const auto& j : i.t){
  1643. const int taste = tastatur->taste(j);
  1644. const double aufwand = i.a;
  1645. for(const auto& s : i.z){
  1646. const auto z = kodierung->position(s);
  1647. vorliebe_roh[z.first][taste] += aufwand;
  1648. }
  1649. }
  1650. }
  1651.  
  1652. neuetastatur->neue_kategorien(benutzerkategorien);
  1653.  
  1654. for(const auto& i : aehnlichkeit){
  1655. const std::u32string t = i.first;
  1656. const double w = i.second;
  1657. for(size_t j = 0; j+1 < t.length(); ++j){
  1658. const auto p1 = kodierung->position(t[j]);
  1659. for(size_t k = j+1; k < t.length(); ++k){
  1660. const auto p2 = kodierung->position(t[k]);
  1661. aehnlichkeit_roh[p2.first][p1.first] += w;
  1662. aehnlichkeit_roh[p1.first][p2.first] += w;
  1663. }
  1664. }
  1665. }
  1666. }
  1667.  
  1668. double
  1669. Konfiguration::
  1670. bigrammaufwand(int i, int j, const Tastatur& tastatur) const {
  1671. const int zeile_i = tastatur.zeile(i);
  1672. const int spalte_i = tastatur.spalte(i);
  1673. const finger_t finger_i = tastatur.finger(i);
  1674.  
  1675. const auto zeile_j = tastatur.zeile(j);
  1676. const int spalte_j = tastatur.spalte(j);
  1677. const finger_t finger_j = tastatur.finger(j);
  1678. const int grundpos_j = tastatur.grundposition(j);
  1679.  
  1680. if(tastatur.kategorie(i,j) == kategorie_t::Handwechsel){
  1681. return mult_handwechsel+bigramm_roh[i][j];
  1682. }else if(tastatur.kategorie(i,j) == kategorie_t::MitUndefDaumen){
  1683. return bigramm_roh[i][j];
  1684. }else if(tastatur.kategorie(i,j) == kategorie_t::Doppeltanschlag){
  1685. // Wenn wir eine Taste abseits der Grundposition zweimal anschlagen,
  1686. // müssen wir den Finger nur einmal dorthin bewegen, der Mehraufwand
  1687. // gegenüber dem Anschlag auf der Grundposition entfällt somit beim
  1688. // zweiten Anschlag.
  1689. return mult_doppelkomp*
  1690. (tastatur.lageaufwand(grundpos_j)-tastatur.lageaufwand(j))
  1691. +bigramm_roh[i][j];
  1692. }else if(tastatur.kategorie(i,j) == kategorie_t::Kollision){
  1693. // Kollisionen sind umso schlimmer, je weiter der Finger springen muss.
  1694. const int idx = std::abs(finger_i)-finger_t::DaumenRechts;
  1695. return mult_handwiederholung+mult_kollision_konstant[idx]+
  1696. mult_kollision_distanz[idx]*tastatur.distanz(i,j)+bigramm_roh[i][j];
  1697. }else{
  1698. // Verschiedene Finger auf derselben Hand.
  1699. const bool auswaerts = tastatur.kategorie(i,j) == kategorie_t::Auswaerts;
  1700. const double dspalte = std::abs(spalte_i-spalte_j);
  1701. const double dx =
  1702. std::abs(tastatur.tastenkoord(i).x-tastatur.tastenkoord(j).x);
  1703. const double dy =
  1704. std::abs(tastatur.tastenkoord(i).y-tastatur.tastenkoord(j).y);
  1705. const double dfinger = std::abs(finger_i-finger_j);
  1706. const double dzeile = std::abs(zeile_i-zeile_j);
  1707. const int minfingerindex =
  1708. std::min(std::abs(finger_i), std::abs(finger_j))
  1709. -finger_t::DaumenRechts;
  1710. const bool mitDaumen = (minfingerindex == 0);
  1711. // Wenn wir eine Taste in einer Zeile abseits der Grundzeile anschlagen
  1712. // bewegen wir die Hand dorthin, folgende Anschläge von anderen Tasten
  1713. // in dieser Zeile wird leichter.
  1714. const int dspaltem1 = std::abs(std::abs(spalte_i-spalte_j)-1);
  1715. const double zkomp = mult_zeilenkomp[dspaltem1 < 5 ? dspaltem1 : 4];
  1716. const double komp =
  1717. (!mitDaumen && dzeile == 0 && zeile_i != zeilen_t::Mittelzeile &&
  1718. (zeile_i != zeilen_t::Untere_Zeile ||
  1719. !Tastatur::istKleinfinger(finger_i)))
  1720. ? zkomp*(tastatur.lageaufwand(grundpos_j)-tastatur.lageaufwand(j))
  1721. : 0;
  1722.  
  1723. const double offset = add_schraegDX[finger_i > 0];
  1724. const double nZS = dspalte+offset, nYX = dx+offset;
  1725. const double zZS = mitDaumen
  1726. ? 0. : mult_schraegZS[finger_i > 0]*dzeile;
  1727. const double zYX = mitDaumen
  1728. ? 0. : mult_schraegYX[finger_i > 0]*dy;
  1729. const double zaehler = zZS*nYX+zYX*nZS, nenner = nZS*nYX;
  1730. if((nZS == 0. && zZS != 0.) || (nYX == 0. && zYX != 0.)){
  1731. std::cerr << SPRACHE(
  1732. "Division durch Null f" strUe "r schr" strAe "ge Griffe. "
  1733. "Dieser Fehler kann auftreten, wenn verschiedene Finger "
  1734. "Tasten in derselben Zeile bedienen. 'Schr" strAe
  1735. "gNenner0' schafft Abhilfe.",
  1736. "Division by zero for hand distorting digrams. This "
  1737. "error can occur if different fingers operate keys in "
  1738. "the same column. 'Schr" strAe "gNenner0' can solve this.")
  1739. << std::endl;
  1740. exit(1);
  1741. }
  1742. const double quotient = zaehler == 0. ? 0. : zaehler/nenner;
  1743.  
  1744. return komp+
  1745. // Aufwand für Handwiederholung.
  1746. mult_handwiederholung
  1747. // Zusatzaufwand für Auswärtsbewegung.
  1748. +(auswaerts && !mitDaumen ? mult_auswaerts : 0)
  1749. // Aufwand wenn die Tasten benachbart sind
  1750. +(dfinger == 1 ? nachbarstrafe[minfingerindex] : 0)
  1751. // Aufwand, wenn die Tasten in verschiedenen Zeilen liegen; je
  1752. // schräger der Griff desto schlimmer.
  1753. +quotient
  1754. +bigramm_roh[i][j];
  1755. }
  1756. }
  1757.  
  1758. double
  1759. Konfiguration::
  1760. trigrammaufwand(int i, int j, int k, const Tastatur& tastatur) const {
  1761. // Sinnvoll sind Aufwände nur, wenn erste und letzte Taste auf derselben
  1762. // Hand sind.
  1763. if(!tastatur.istHandwiederholung(i,k)) return trigramm_roh[i][j][k];
  1764.  
  1765. // Ansonsten bauen wir die Trigrammaufwände aus den Bigrammaufwänden. bi
  1766. // ist der Bigrammaufwand für die erste und dritte Taste:
  1767. const double bi = bigrammaufwand(i, k, tastatur);
  1768. const double ik = mult_indirekt[bi < 0]*bi;
  1769. if(tastatur.istHandwiederholung(i,j)){
  1770. // Drei Tasten mit derselben Hand.
  1771. const double extra = trigramm_roh[i][j][k]+mult_doppelwiederholung+
  1772. (tastatur.istWippe(i, j, k) ? mult_wippe : 0);
  1773. if(ik <= 0) return extra;
  1774. const double ij = bigrammaufwand(i, j, tastatur);
  1775. const double jk = bigrammaufwand(j, k, tastatur);
  1776. // Insgesamt sollte der Aufwand mindestens so hoch wie er gewesen
  1777. // wäre, wenn die mittlere Taste auf der anderen Hand gelegen wäre.
  1778. // Man könnte vielleicht in einigen Fällen mehr berechnen, aber sicher
  1779. // nicht weniger.
  1780. return ik > ij+jk ? extra+ik-ij-jk : extra;
  1781. }else
  1782. // Zwei Handwechsel.
  1783. return ik+mult_doppelwechsel+trigramm_roh[i][j][k];
  1784. }
  1785.  
  1786. double
  1787. Konfiguration::
  1788. verwechslungspotenzial(int i, int j, const Tastatur& tastatur) const {
  1789. const finger_t finger_i = tastatur.finger(i);
  1790. const finger_t finger_j = tastatur.finger(j);
  1791. if(!tastatur.istHandwiederholung(i,j)){
  1792. if(!Tastatur::istDaumen(finger_i) &&
  1793. std::abs(finger_i) == std::abs(finger_j)){
  1794. const int zi = tastatur.zeile(i), zj = tastatur.zeile(j);
  1795. return (zi == zj ? mult_symmetrisch_gleichzeile : mult_symmetrisch)
  1796. +mult_hand_verschieden
  1797. +verwechslungspotenzial_roh[i][j];
  1798. }else return mult_hand_verschieden
  1799. +verwechslungspotenzial_roh[i][j];
  1800. }else if(tastatur.kategorie(i,j) == kategorie_t::Kollision){
  1801. return mult_kollision+verwechslungspotenzial_roh[i][j];
  1802. }else{
  1803. return (std::abs(finger_i-finger_j) == 1 ? mult_nachbar : 0)
  1804. +verwechslungspotenzial_roh[i][j];
  1805. }
  1806. }
  1807.  
  1808. double
  1809. Konfiguration::vorliebe(int i, int j) const {
  1810. assert(i < ntaste+nshift && j < ntaste+nshift);
  1811. return vorliebe_roh[i][j];
  1812. }
  1813.  
  1814. double
  1815. Konfiguration::vorliebenknick() const
  1816. { return vorliebe_knick; }
  1817.  
  1818. double
  1819. Konfiguration::aehnlichkeit(int i, int j) const {
  1820. assert(i < ntaste+nshift && j < ntaste+nshift);
  1821. return aehnlichkeit_roh[i][j];
  1822. }
  1823.  
  1824. double
  1825. Konfiguration::shiftindirekt(double a) const
  1826. { return mult_shiftindirekt[a < 0]; }
  1827.  
  1828. double
  1829. Konfiguration::indirekt(double a) const
  1830. { return mult_indirekt[a < 0]; }
  1831.  
  1832. double
  1833. Konfiguration::zielhaeufigkeit(int f) const {
  1834. assert(f < nfinger);
  1835. return fh_unnorm[f];
  1836. }
  1837.  
  1838. double
  1839. Konfiguration::multfinger(int f) const {
  1840. assert(f < nfinger);
  1841. return mf_input[f];
  1842. }
  1843.  
  1844. double
  1845. Konfiguration::unbekannt() const
  1846. { return aunbekannt; }
  1847.  
  1848. const std::string&
  1849. Konfiguration::zeichenfont() const
  1850. { return _zeichenfont; }
  1851.  
  1852. const std::string&
  1853. Konfiguration::beschreibungsfont() const
  1854. { return _beschreibungsfont; }
  1855.  
  1856. //--------------- src/main.cc ---------------
  1857. //#include "Aufwandstabelle.hh"
  1858. //#include "Eingabestream.hh"
  1859. //#include "Grafik.hh"
  1860. //#include "Haeufigkeit.hh"
  1861. //#include "Kodierung.hh"
  1862. //#include "Konfiguration.hh"
  1863. //#include "Tastatur.hh"
  1864. //#include "berechnungen.hh"
  1865. //#include "copyright.hh"
  1866. //#include "html_markup.hh"
  1867. //#include "konstanten.hh"
  1868. //#include "ngramme.hh"
  1869. //#include "schreibe_belegung.hh"
  1870. //#include "string_in_belegung.hh"
  1871. //#include "trennen.hh"
  1872. //#include "typen.hh"
  1873. //#include "utfhilfe.hh"
  1874. //#include "wortliste.hh"
  1875. #include <algorithm>
  1876. #include <cassert>
  1877. #include <chrono>
  1878. #include <cmath>
  1879. #include <cstdint>
  1880. #include <cstdio>
  1881. #include <cstdlib>
  1882. #include <cstring>
  1883. #include <fstream>
  1884. #include <iomanip>
  1885. #include <iostream>
  1886. #include <limits>
  1887. #include <map>
  1888. #include <memory>
  1889. #include <random>
  1890. #include <sstream>
  1891. #include <string>
  1892. #ifdef MIT_THREADS
  1893. #include <thread>
  1894. #endif // MIT_THREADS
  1895. #include <unordered_map>
  1896. #include <unordered_set>
  1897. #include <vector>
  1898.  
  1899. template <typename S, typename Z>
  1900. void einfuegen(std::unordered_map<S, Z>& summe,
  1901. std::unordered_map<S, Z>& summand)
  1902. {
  1903. if(summe.size())
  1904. for(const auto& k : summand) summe[k.first] += k.second;
  1905. else summe.swap(summand);
  1906. }
  1907.  
  1908. void hilfe()
  1909. {
  1910. #ifdef ENGLISH
  1911. std::cout <<
  1912. "Keyboard layout optimiser version " << opt_version << ", compiled for "
  1913. << ntaste+nshift << " keys"
  1914. #ifdef OHNE2SHIFT
  1915. "\n(using option -DOHNE2SHIFT).\n\n"
  1916. #else
  1917. ".\n\n"
  1918. #endif
  1919. "opt [-2|-3 prefix][-A][-b upto][-g file][-G num][-H upto][-i maxiter]\n"
  1920. " [-k][-K][-m max][-r file][-s seed][-t num][-T][-V num][-w file]\n\n"
  1921. "-2 prefix Specifies prefix for UTF-8 encoded files with character frequencies,\n"
  1922. " (suffix .1) and digram frequencies (suffix .2).\n"
  1923. "-3 prefix As -2, additionally with trigram frequencies (suffix .3).\n"
  1924. "-A Dump the efforts used.\n"
  1925. "-b upto Create summary of digrams up to given cumulative frequency per hand.\n"
  1926. "-f Displays layout as 'FixesZeichen'; no not use with option -k.\n"
  1927. "-g file Create a PostScript file with a graphical evaluation of the layouts.\n"
  1928. "-G weight Weight used for subsequent frequency files.\n"
  1929. "-H upto Print one-handed sequences up to given cumulative frequency.\n"
  1930. "-i maxiter Number of local optima to compute.\n"
  1931. "-k Output results in compact form (one line per layout).\n"
  1932. "-K file Use the given configuration file.\n"
  1933. "-m max If this option is present, all layouts with a total effort below the\n"
  1934. " given threshold will be printed.\n"
  1935. "-M file Displays how the file is entered, as HTML (must be used with -r).\n"
  1936. "-r file Output layouts read from the file; do not perform an optimisation.\n"
  1937. "-s seed Seed for random number generator, a positive number.\n"
  1938. #ifdef MIT_THREADS
  1939. "-t num Use num threads (default 1).\n"
  1940. #endif // MIT_THREADS
  1941. "-T Add soft hyphenation in corpus.\n"
  1942. "-V maxdiff Variation depth (must be used with -r).\n"
  1943. "-w file Specifies a word list." << std::endl;
  1944. #else
  1945. std::cout << "Belegungsoptimierer Version " << opt_version
  1946. << ", " strUe "bersetzt f" strUe "r "
  1947. << ntaste+nshift << " Tasten"
  1948. #ifdef OHNE2SHIFT
  1949. "\n(mit Option -DOHNE2SHIFT).\n\n"
  1950. #else
  1951. ".\n\n"
  1952. #endif
  1953. "opt [-2|-3 pr" strAe "fix][-A][-b biszu][-g file][-G num][-H upto][-i maxiter]\n"
  1954. " [-k][-K][-m max][-r file][-s Saat][-t num][-T][-V num][-w file]\n\n"
  1955. "-2 pr" strAe "fix Spezifiziert Pr" strAe "fix f" strUe "r UTF-8-kodierte Files mit\n"
  1956. " Zeichenh" strAe "ufigkeiten (Suffix .1) und Bigrammh" strAe "ufigkeiten (Suffix .2).\n"
  1957. "-3 pr" strAe "fix Wie -2, zus" strAe "tzlich mit Trigrammh" strAe "ufigkeiten (Suffix .3).\n"
  1958. "-A Gib verwendete Aufw" strAe "nde aus.\n"
  1959. "-b biszu Gib Bigrammaufstellung bis zu angegebener summierter H" strAe "ufigkeit\n"
  1960. " pro Hand aus.\n"
  1961. "-f Gibt Belegung als 'FixesZeichen' aus; nicht mit Option -k verwenden.\n"
  1962. "-g file Erzeuge ein PostScript-File mit grafischer Auswertung\n"
  1963. " der Belegungen.\n"
  1964. "-G gewicht Gewicht f" strUe "r folgende H" strAe "ufigkeitsfiles.\n"
  1965. "-H biszu Kumulierte H" strAe "ufigkeit, bis zu der Handeins" strAe "tze ausgegeben werden.\n"
  1966. "-i maxiter Anzahl der zu berechnenden lokalen Optimierungen.\n"
  1967. "-k Gibt Resultate in einer kompakten Form (eine Zeile pro Belegung) aus.\n"
  1968. "-K file Benutze die Konfiguration im angegeben File.\n"
  1969. "-m max Wenn diese Option angegeben wird, werden Belegungen mit\n"
  1970. " Gesamtaufwand unter der angegbenen Schranke angezeigt.\n"
  1971. "-M file Zeigt als HTML, wie das File eingegeben wird (in Verbindung mit -r).\n"
  1972. "-r file Gibt Referenzbelegungen im File aus; es wird keine Optimierung\n"
  1973. " durchgef" strUe "hrt.\n"
  1974. "-s Saat Saat f" strUe "r den Zufallsgenerator, eine positive, ganze Zahl.\n"
  1975. #ifdef MIT_THREADS
  1976. "-t num Benutze num Threads (Voreinstellung 1).\n"
  1977. #endif // MIT_THREADS
  1978. "-T Weiche Trennzeichen in Korpus einf" strUe "gen.\n"
  1979. "-V maxdiff Variantentiefe (in Verbindung mit -r).\n"
  1980. "-w file Spezifiziert eine Wortliste." << std::endl;
  1981. #endif
  1982. exit(0);
  1983. }
  1984.  
  1985. const char* argument(int& argc, char* const*& argv)
  1986. {
  1987. if(argc < 2){
  1988. std::cerr << SPRACHE("Die Option '", "Option '") << *argv
  1989. << SPRACHE("' erwartet ein Argument.",
  1990. "' requires an argument.") << std::endl;
  1991. exit(1);
  1992. }
  1993. argv++; argc--;
  1994. return *argv;
  1995. }
  1996.  
  1997. double fargument(int& argc, char* const*& argv)
  1998. {
  1999. const std::string opt = *argv;
  2000. const char* c = argument(argc, argv);
  2001. char* x;
  2002. const double r = strtod(c, &x);
  2003. if(*x){
  2004. std::cerr << SPRACHE("Das Argument der Option '", "The argument of option '")
  2005. << opt << SPRACHE("' muss eine Zahl sein.", "' must be a number.")
  2006. << std::endl;
  2007. exit(1);
  2008. }
  2009. return r;
  2010. }
  2011. int iargument(int& argc, char* const*& argv)
  2012. {
  2013. const std::string opt = *argv;
  2014. const char* c = argument(argc, argv);
  2015. char* x;
  2016. const long r = strtol(c, &x, 10);
  2017. if(*x){
  2018. std::cerr << SPRACHE("Das Argument der Option '",
  2019. "The argument of option '") << opt
  2020. << SPRACHE("' muss ganzzahlig sein.", "' must be an integer.")
  2021. << std::endl;
  2022. exit(1);
  2023. }
  2024. if(std::abs(r) > std::numeric_limits<int>::max()){
  2025. std::cerr << SPRACHE("Der Betrag des Arguments der Option '",
  2026. "The magnitude of the argument of option '") << opt
  2027. << SPRACHE("' muss muss kleiner oder gleich ",
  2028. "' must be less than or equal to ")
  2029. << std::numeric_limits<int>::max()
  2030. << SPRACHE(" sein.", ".") << std::endl;
  2031. exit(1);
  2032. }
  2033. return r;
  2034. }
  2035.  
  2036. int main(int argc, char* const argv[])
  2037. {
  2038. std::random_device rd;
  2039.  
  2040. bool alle_guten = false, trigramm = false, korpusstatistik = false;
  2041. bool schoene_tastatur = true, zyklen = false, aufwandstabelle = false;
  2042. bool irgendeine_option = false, trennen = false, als_fixeszeichen = false;
  2043. std::string referenztastatur, grafikname;
  2044. int iterationen = std::numeric_limits<int>::max(), num_variierte_tasten = 0;
  2045. int saatwert = rd(), nthreads = 1, iakkumlimit = 0;
  2046. akkumuations_t minimum = 1e38, handeinsatzlimit = 95;
  2047. double ngrammakkumlimit[3] = { -1, -1, -1 }, gewicht = 1, gewichtssumme = 0;
  2048. std::vector<std::string> korpusnamen, freie_argumente;
  2049. std::vector<std::string> konfigurationsfiles, wortlisten, markup;
  2050. std::vector<double> gewichte;
  2051. std::vector<bool> trigramme;
  2052. std::unordered_map<std::string, haeufigkeit_t> wortliste;
  2053.  
  2054. const std::string progname = *argv++; argc--;
  2055. for(; argc; argv++, argc--){
  2056. const std::string option = *argv;
  2057. bool ist_option = true;
  2058.  
  2059. if(option == "-2" || option == "-3"){
  2060. if(korpusnamen.size() >= nmaxkorpus){
  2061. std::cerr << SPRACHE("Man kann maximal ",
  2062. "You can specify at most ") << nmaxkorpus
  2063. << SPRACHE(" verschiedene Korpora angeben. Im "
  2064. "Sourcecode 'nmaxkorpus' erh" strOe "hen.",
  2065. " different corpora. In the source code, "
  2066. "increase 'nmaxkorpus'.")
  2067. << std::endl;
  2068. exit(1);
  2069. }
  2070. korpusnamen.emplace_back(argument(argc, argv));
  2071. gewichte.push_back(gewicht);
  2072. gewichtssumme += gewicht;
  2073. trigramme.push_back(option == "-3");
  2074. trigramm |= trigramme.back();
  2075. }else if(option == "-A"){
  2076. aufwandstabelle = true;
  2077. }else if(option == "-b"){
  2078. if(iakkumlimit < 3){
  2079. ngrammakkumlimit[iakkumlimit] = fargument(argc, argv)/100.;
  2080. if(ngrammakkumlimit[iakkumlimit] < 0){
  2081. std::cerr << SPRACHE(
  2082. "Das Angument von -b darf nicht negativ sein.",
  2083. "The argument of -b must not be negative.") << std::endl;
  2084. exit(1);
  2085. }
  2086. ++iakkumlimit;
  2087. }
  2088. }else if(option == "-f"){
  2089. als_fixeszeichen = true;
  2090. }else if(option == "-g"){
  2091. grafikname = argument(argc, argv);
  2092. }else if(option == "-G"){
  2093. gewicht = fargument(argc, argv);
  2094. if(gewicht <= 0.){
  2095. std::cerr << SPRACHE(
  2096. "Gewichte m" strUe "ssen positive Zahlen sein.",
  2097. "Weights must be positive numbers.") << std::endl;
  2098. exit(1);
  2099. }
  2100. }else if(option == "-h"){
  2101. hilfe();
  2102. }else if(option == "-H"){
  2103. handeinsatzlimit = fargument(argc, argv);
  2104. }else if(option == "-i"){
  2105. iterationen = iargument(argc, argv);
  2106. }else if(option == "-k"){
  2107. schoene_tastatur = false;
  2108. }else if(option == "-K"){
  2109. konfigurationsfiles.emplace_back(argument(argc, argv));
  2110. }else if(option == "-m"){
  2111. minimum = fargument(argc, argv)/100.;
  2112. alle_guten = true;
  2113. }else if(option == "-M"){
  2114. markup.emplace_back(argument(argc, argv));
  2115. }else if(option == "-r"){
  2116. if(referenztastatur.size()){
  2117. std::cerr << SPRACHE(
  2118. "Es darf nur ein Belegungsfile angegeben werden.",
  2119. "You can specify only one layout file.") << std::endl;
  2120. exit(1);
  2121. }
  2122. referenztastatur = argument(argc, argv);
  2123. }else if(option == "-s"){
  2124. saatwert = (iargument(argc, argv));
  2125. }else if(option == "-S"){
  2126. korpusstatistik = true;
  2127. }else if(option == "-t"){
  2128. nthreads = (iargument(argc, argv));
  2129. if(nthreads < 1){
  2130. std::cerr << SPRACHE("Die Anzahl Threads muss mindestens 1 sein.",
  2131. "The number of threads must be at least 1.")
  2132. << std::endl;
  2133. exit(1);
  2134. }
  2135. #ifndef MIT_THREADS
  2136. std::cerr << SPRACHE(
  2137. "Die Option -t ist nicht unterst" strUe "tzt, denn der Optimierer "
  2138. "wurde ohne die Option -DMIT_THREADS " strUe "bersetzt. ",
  2139. "The option -t is not supported, as the optimiser was compiled "
  2140. "without using option -DMIT_THREADS.") << std::endl;
  2141. #endif // !MIT_THREADS
  2142. }else if(option == "-T"){
  2143. trennen = true;
  2144. ist_option = false;
  2145. }else if(option == "-V"){
  2146. num_variierte_tasten = iargument(argc, argv);
  2147. }else if(option == "-w"){
  2148. wortlisten.emplace_back(argument(argc, argv));
  2149. }else if(option == "-Z"){
  2150. zyklen = true;
  2151. }else{
  2152. ist_option = false;
  2153. freie_argumente.push_back(option);
  2154. }
  2155.  
  2156. irgendeine_option |= ist_option;
  2157. }
  2158.  
  2159. if(freie_argumente.size() || trennen){
  2160. if(irgendeine_option){
  2161. std::cerr << SPRACHE("Bei Erstellen von H" strAe "ufigkeitstabellen d"
  2162. strUe "rfen keine Optionen angegeben werden.",
  2163. "When creating frequency files, you must not "
  2164. "specify any options.")
  2165. << std::endl;
  2166. exit(1);
  2167. }
  2168. if(trennen){
  2169. if(freie_argumente.size() != 3){
  2170. std::cerr << SPRACHE(
  2171. "Zum Trennen genau drei Argumente angeben: "
  2172. "Trennmuster, Eingabefile, Ausgabefile",
  2173. "To hyphenate, provide exactly three arguments: "
  2174. "hyphenation patterns, input file, output file") << std::endl;
  2175. exit(1);
  2176. }
  2177. markiere_alle_trennstellen(freie_argumente[1], freie_argumente[2],
  2178. freie_argumente[0]);
  2179. exit(0);
  2180. }else{
  2181. erzeuge_ngrammtabellen(freie_argumente);
  2182. exit(0);
  2183. }
  2184. }
  2185.  
  2186. if(!konfigurationsfiles.size())
  2187. konfigurationsfiles.push_back("standard.cfg");
  2188.  
  2189. std::unique_ptr<const Kodierung> kodierung;
  2190. std::unique_ptr<const Tastatur> tastatur;
  2191. std::unique_ptr<Konfiguration> konfiguration
  2192. (new Konfiguration(konfigurationsfiles, tastatur, kodierung));
  2193. std::unique_ptr<const Aufwandstabelle> a
  2194. (new Aufwandstabelle(trigramm, *tastatur, *konfiguration));
  2195. if(aufwandstabelle){
  2196. a->anzeigen(*kodierung, *konfiguration);
  2197. exit(0);
  2198. }
  2199.  
  2200. if(markup.size()){
  2201. if(!referenztastatur.size()){
  2202. std::cerr << SPRACHE(
  2203. "Mit Option -M muss auch Option -r verwendet werden.",
  2204. "When using option -M, you must use option -r as well.")
  2205. << std::endl;
  2206. exit(1);
  2207. }
  2208. for(auto& i : markup)
  2209. html_markup(i, *kodierung, *tastatur, referenztastatur);
  2210. exit(0);
  2211. }
  2212.  
  2213. if(!korpusnamen.size()){
  2214. std::cerr << SPRACHE("Quellen f" strUe "r Buchstaben- und Bi/Trigrammh"
  2215. strAe "ufigkeiten m" strUe "ssen angegeben werden.",
  2216. "Sources for character and di/trigram frequencies "
  2217. "must be specified.") << std::endl;
  2218. exit(1);
  2219. }
  2220.  
  2221. for(auto& i : gewichte) i /= gewichtssumme;
  2222. std::unique_ptr<const Haeufigkeit> korpus
  2223. (new Haeufigkeit(*tastatur, *kodierung, korpusnamen, gewichte, trigramme,
  2224. referenztastatur.size()&&schoene_tastatur && !trigramm,
  2225. a->unbekannt() > 0));
  2226. if(korpusstatistik) korpus->statistik();
  2227.  
  2228. std::unique_ptr<Grafik> grafik
  2229. (grafikname.size()
  2230. ? new Grafik(grafikname, *tastatur, *kodierung, *korpus, *konfiguration)
  2231. : nullptr);
  2232.  
  2233. for(const auto& i : wortlisten){
  2234. std::unordered_map<std::string, haeufigkeit_t> ht;
  2235. lies_wortliste(i, ht, *kodierung);
  2236. einfuegen(wortliste, ht);
  2237. }
  2238.  
  2239. const char* vgl[2] = { SPRACHE("Gegen erste: ", " Compared to first: "),
  2240. SPRACHE("Gegen vorige: ", " Compared to previous: ")};
  2241.  
  2242. const akkumuations_t K = konstanter_aufwand(*korpus, *a);
  2243. minimum -= K;
  2244. if(referenztastatur.size()){
  2245. constexpr bool utf8 = true;
  2246. belegung_t b2[2]; b2[0][0] = b2[1][0] = ntaste;
  2247. Eingabestream liste(referenztastatur, utf8);
  2248. while(liste.echte_neuezeile()){
  2249. std::u32string bs, uname;
  2250. if(!liste.hole_wort(bs) || !liste.hole_wort(uname)){
  2251. std::cerr << SPRACHE("Fehlerhaft formatiertes Belegungsfile ",
  2252. "Incorrectly formatted layout file ")
  2253. << referenztastatur << std::endl;
  2254. liste.fehler();
  2255. }
  2256.  
  2257. if(bs.size()){
  2258. belegung_t b;
  2259. bool fest[ntaste];
  2260. string_in_belegung(bs, b, fest, tastatur->nvariabel(), *kodierung);
  2261. if(zyklen){
  2262. for(int z = 0; z < 2; ++z){
  2263. if(b2[z][0] >= ntaste) continue;
  2264. int ndiff = 0;
  2265. for(int i = 0; i < tastatur->nvariabel(); ++i)
  2266. if(b[i] != b2[z][i]) ++ndiff;
  2267. std::cout << vgl[z] << ndiff
  2268. << SPRACHE(" Tasten umbelegt, Zyklen:",
  2269. " keys reassigned, cycles:");
  2270. schreibe_zyklen(b2[z], b, *kodierung);
  2271. std::cout << "\n";
  2272. }
  2273. std::cout << "\n";
  2274. }
  2275.  
  2276. std::unique_ptr<Haeufigkeit> arbeitskorpus
  2277. (new Haeufigkeit(*korpus, 0));
  2278. #ifndef PERMUTATIONEN_ALT
  2279. arbeitskorpus->setze(*korpus, b);
  2280. #endif // !PERMUTATIONEN_ALT
  2281. const akkumuations_t A =
  2282. variabler_aufwand(b, *arbeitskorpus, *tastatur, *a);
  2283.  
  2284. if(num_variierte_tasten > 1){
  2285. int numfrei = 0;
  2286. for(int i = 0; i < tastatur->nvariabel(); ++i)
  2287. if(!fest[i]) ++numfrei;
  2288. std::cerr << numfrei << SPRACHE(" freie Tasten, ",
  2289. " variable keys, ")
  2290. << std::setprecision(16)
  2291. << anzahl_varianten(numfrei, num_variierte_tasten)
  2292. << SPRACHE(" Varianten", " variants") << std::endl;
  2293.  
  2294. if(A < minimum) schreibe_belegung(b, A+K, tastatur->nvariabel(),
  2295. *kodierung, &uname);
  2296.  
  2297. erzeuge_variationen(b, *tastatur, *kodierung, *arbeitskorpus, *a,
  2298. A, num_variierte_tasten, minimum, fest);
  2299. }else{
  2300. if(schoene_tastatur){
  2301. schreibe_belegung(b, *tastatur, *kodierung, *korpus, *a, A+K,
  2302. uname, ngrammakkumlimit, wortliste,
  2303. handeinsatzlimit, als_fixeszeichen);
  2304. if(korpus->mit_varianzen() && b2[0][0] < ntaste){
  2305. std::cout << SPRACHE(
  2306. "Standardabweichung der " "Aufwandsdifferenz zur "
  2307. "ersten Belegung: ",
  2308. "Standard deviation of the difference of efforts "
  2309. "compared to the first layout: ")
  2310. << std::setprecision(9)
  2311. << 100*std::sqrt(
  2312. aufwandsvarianz(b, &b2[0], *tastatur,
  2313. *korpus, *a))
  2314. << "\n";
  2315. }
  2316. if(korpus->mit_varianzen()){
  2317. std::cout << SPRACHE(
  2318. "Standardabweichung des Gesamtaufwands: ",
  2319. "Standard deviation of the total effort: ")
  2320. << std::setprecision(9)
  2321. << 100*std::sqrt(
  2322. aufwandsvarianz(b, nullptr, *tastatur,
  2323. *korpus, *a))
  2324. << "\n";
  2325. }
  2326. std::cout << std::endl;
  2327. }else{
  2328. schreibe_belegung(b, A+K, tastatur->nvariabel(), *kodierung,
  2329. &uname);
  2330. }
  2331.  
  2332. if(grafik) grafik->ausgabe(b);
  2333.  
  2334. }
  2335.  
  2336. if(b2[0][0] >= ntaste)
  2337. for(int i = 0; i < ntaste; ++i) b2[0][i] = b[i];
  2338. if(zyklen)
  2339. for(int i = 0; i < ntaste; ++i) b2[1][i] = b[i];
  2340. }
  2341. }
  2342. }else{
  2343. const auto startzeit = std::chrono::high_resolution_clock::now();
  2344.  
  2345. const int lebenszeichen =
  2346. (trigramm ? 1000 : 10000)*(schoene_tastatur ? 1 : 100);
  2347.  
  2348. std::seed_seq saatgen{saatwert};
  2349. std::vector<int> saaten(nthreads);
  2350. saatgen.generate(saaten.begin(), saaten.end());
  2351. akkumuations_t globalesMinimum = minimum;
  2352. #ifdef MIT_THREADS
  2353. std::vector<std::thread> threads;
  2354. for(int i = 1; i < nthreads; ++i){
  2355. threads.push_back(
  2356. std::thread(suche_optimum, *tastatur, *kodierung, korpus.get(), *a,
  2357. minimum, schoene_tastatur, alle_guten, als_fixeszeichen,
  2358. saaten[i], iterationen, std::numeric_limits<int>::max(),
  2359. ngrammakkumlimit, wortliste, handeinsatzlimit,
  2360. grafik.get(), &globalesMinimum));
  2361. }
  2362. #endif // MIT_THREADS
  2363. suche_optimum(*tastatur, *kodierung, korpus.get(), *a, minimum,
  2364. schoene_tastatur, alle_guten, als_fixeszeichen, saaten[0],
  2365. iterationen, lebenszeichen, ngrammakkumlimit, wortliste,
  2366. handeinsatzlimit, grafik.get(), &globalesMinimum);
  2367. #ifdef MIT_THREADS
  2368. for(auto& t : threads) t.join();
  2369. #endif // MIT_THREADS
  2370.  
  2371. const auto endzeit = std::chrono::high_resolution_clock::now();
  2372. const std::chrono::nanoseconds zeitdifferenz = endzeit-startzeit;
  2373. std::cerr << SPRACHE("Laufzeit: ", "Run time: ")
  2374. << std::fixed << std::setw(9)
  2375. << std::setprecision(9) << 1e-9*zeitdifferenz.count()
  2376. << SPRACHE(" Sekunden", " seconds") << std::endl;
  2377. }
  2378.  
  2379. return 0;
  2380. }
  2381.  
  2382. //--------------- src/berechnungen.cc ---------------
  2383. //#include "berechnungen.hh"
  2384.  
  2385. //#include "Aufwandstabelle.hh"
  2386. //#include "Grafik.hh"
  2387. //#include "Haeufigkeit.hh"
  2388. //#include "Kodierung.hh"
  2389. //#include "Tastatur.hh"
  2390. //#include "schreibe_belegung.hh"
  2391. //#include "utfhilfe.hh"
  2392. #include <cstring>
  2393. #include <iostream>
  2394. #ifdef MIT_THREADS
  2395. #include <mutex>
  2396. #endif // MIT_THREADS
  2397. #include <random>
  2398.  
  2399. namespace {
  2400.  
  2401. #ifdef PERMUTATIONEN_ALT
  2402. #define BELEGUNG(z, b, p) const int z = b[p]
  2403. #else
  2404. #define BELEGUNG(z, b, p) const int& z = p
  2405. #endif
  2406.  
  2407. // Der Zufallszahlengenerator kann Einfluss auf die Geschwindigkeit haben.
  2408. using rngengine_t = std::mt19937;
  2409. using uniform_t = std::uniform_int_distribution<char>;
  2410.  
  2411. #ifdef MIT_THREADS
  2412. std::mutex ausgabemutex;
  2413. #endif // MIT_THREADS
  2414.  
  2415. using fingerbelastung_t = akkumuations_t[nmaxkorpus][nfinger+1];
  2416.  
  2417. inline akkumuations_t
  2418. berechne_vorliebensumme(const belegung_t b, const Aufwandstabelle& a){
  2419. if(!a.hat_vorlieben()) return 0;
  2420. akkumuations_t vs = 0;
  2421. for(int p = 0; p < ntaste; ++p) vs += a.vorliebe(b[p], p);
  2422. return vs;
  2423. }
  2424.  
  2425. inline void
  2426. berechne_fingerbelastung(const belegung_t b,
  2427. const Haeufigkeit& h,
  2428. const Tastatur& tastatur,
  2429. fingerbelastung_t fh)
  2430. {
  2431. for(int k = 0; k < h.num_korpus(); ++k){
  2432. for(auto& i : fh[k]) i = 0;
  2433. for(int p1 = 0; p1 < ntaste; ++p1){
  2434. BELEGUNG(z1, b, p1);
  2435. const int fi = tastatur.finger_index(p1);
  2436. for(int e1 = 0; e1 < nebene; ++e1) fh[k][fi] += h(k,z1,e1);
  2437. const int sf = tastatur.shift_finger_index(p1);
  2438. fh[k][sf] += h(k,z1,1);
  2439. }
  2440. }
  2441. }
  2442.  
  2443. inline void zufallsbelegung(belegung_t b, int nv,
  2444. rngengine_t& rng, uniform_t& d){
  2445. for(int j = 0; j < ntaste; ++j) b[j] = j;
  2446. for(int j = nv-1; j ; --j){
  2447. const int pos = d(rng, uniform_t::param_type(0, j));
  2448. std::swap(b[j], b[pos]);
  2449. }
  2450. }
  2451.  
  2452. // Berechne Aufwanderhöhung dadurch, dass man die Belegung der Plätze p1 und p2
  2453. // vertauscht.
  2454. akkumuations_t
  2455. diff_aufwand(int p1, int p2, const belegung_t b,
  2456. const Tastatur& tastatur,
  2457. const Haeufigkeit& h,
  2458. const fingerbelastung_t fh_alt,
  2459. #ifdef EXPERIMENTELL
  2460. const akkumuations_t vs_alt,
  2461. #endif // EXPERIMENTELL
  2462. const Aufwandstabelle& a)
  2463. {
  2464. assert(p1 < tastatur.nvariabel() && p2 < tastatur.nvariabel());
  2465. BELEGUNG(z1, b, p1); BELEGUNG(z2, b, p2);
  2466. akkumuations_t summe = 0;
  2467.  
  2468. for(int e1 = 0; e1 < nebene; ++e1){
  2469. const akkumuations_t dh1 = (h(z2,e1)-h(z1,e1));
  2470. const akkumuations_t da1 = a(p1,e1)-a(p2,e1);
  2471. summe += da1*dh1;
  2472.  
  2473. for(int e2 = 0; e2 < nebene2; ++e2){
  2474. const akkumuations_t dh1 = h(z1,e1,z1,e2)-h(z1,e1,z2,e2);
  2475. const akkumuations_t dh2 = h(z2,e1,z2,e2)-h(z2,e1,z1,e2);
  2476. const akkumuations_t da1 = a(p1,e1,p1,e2)-a(p1,e1,p2,e2);
  2477. const akkumuations_t da2 = a(p2,e1,p2,e2)-a(p2,e1,p1,e2);
  2478. summe += (da1+da2)*(dh1+dh2);
  2479. }
  2480. }
  2481. for(int p = 0; p < ntaste; ++p){
  2482. BELEGUNG(z, b, p);
  2483. for(int e1 = 0; e1 < nebene; ++e1){
  2484. for(int e2 = 0; e2 < nebene2; ++e2){
  2485. const akkumuations_t dh2_1 = h(z2,e1,z,e2)-h(z1,e1,z,e2);
  2486. const akkumuations_t da2_1 = a(p1,e1,p,e2)-a(p2,e1,p,e2);
  2487. const akkumuations_t dh2_2 = h(z,e1,z2,e2)-h(z,e1,z1,e2);
  2488. const akkumuations_t da2_2 = a(p,e1,p1,e2)-a(p,e1,p2,e2);
  2489. summe += da2_1*dh2_1+da2_2*dh2_2;
  2490. }
  2491. }
  2492. }
  2493.  
  2494. if(a.hat_vorlieben()){
  2495. const int z1 = b[p1], z2 = b[p2];
  2496. const akkumuations_t diff_vs =
  2497. (a.vorliebe(z2,p1)+a.vorliebe(z1,p2))
  2498. -(a.vorliebe(z1,p1)+a.vorliebe(z2,p2));
  2499. #ifdef EXPERIMENTELL
  2500. const akkumuations_t vs_neu = vs_alt+diff_vs;
  2501. summe += a.knick(vs_neu)-a.knick(vs_alt);
  2502. #else
  2503. summe += diff_vs;
  2504. #endif // !EXPERIMENTELL
  2505. }
  2506.  
  2507. if(a.hat_aehnlichkeit()){
  2508. const int z1v = b[p1], z2v = b[p2];
  2509. for(int p = 0; p < ntaste; ++p){
  2510. if(p == p1 || p == p2) continue;
  2511. const int z = b[p];
  2512. const akkumuations_t dh2_1 =
  2513. a.aehnlichkeit(z2v,z)-a.aehnlichkeit(z1v,z);
  2514. const akkumuations_t da2_1 =
  2515. a.verwechslungspotenzial(p1,p)-a.verwechslungspotenzial(p2,p);
  2516. summe += 2.*da2_1*dh2_1;
  2517. }
  2518. }
  2519.  
  2520. if(h.mit_trigrammen()){
  2521. for(int pi = 0; pi < ntaste; ++pi){
  2522. if(pi == p1 || pi == p2) continue;
  2523. BELEGUNG(zi, b, pi);
  2524. for(int pj = 0; pj < ntaste; ++pj){
  2525. if(pj == p1 || pj == p2) continue;
  2526. BELEGUNG(zj, b, pj);
  2527. for(int e = 0; e < nebene; ++e){
  2528. const akkumuations_t dh3_1 = h.tri(zi,zj,z2,e)-h.tri(zi,zj,z1,e);
  2529. const akkumuations_t da3_1 = a.tri(pi,pj,p1,e)-a.tri(pi,pj,p2,e);
  2530. summe += da3_1*dh3_1;
  2531. const akkumuations_t dh3_2 = h.tri(zi,z2,zj,e)-h.tri(zi,z1,zj,e);
  2532. const akkumuations_t da3_2 = a.tri(pi,p1,pj,e)-a.tri(pi,p2,pj,e);
  2533. summe += da3_2*dh3_2;
  2534. const akkumuations_t dh3_3 = h.tri(z2,zi,zj,e)-h.tri(z1,zi,zj,e);
  2535. const akkumuations_t da3_3 = a.tri(p1,pi,pj,e)-a.tri(p2,pi,pj,e);
  2536. summe += da3_3*dh3_3;
  2537. }
  2538. }
  2539. }
  2540.  
  2541. for(int pi = 0; pi < ntaste; ++pi){
  2542. if(pi == p1 || pi == p2) continue;
  2543. BELEGUNG(zi, b, pi);
  2544. for(int e = 0; e < nebene; ++e){
  2545. const akkumuations_t dh3_1a = h.tri(zi,z2,z2,e)-h.tri(zi,z1,z1,e);
  2546. const akkumuations_t da3_1a = a.tri(pi,p1,p1,e)-a.tri(pi,p2,p2,e);
  2547. summe += da3_1a*dh3_1a;
  2548. const akkumuations_t dh3_1b = h.tri(zi,z1,z2,e)-h.tri(zi,z2,z1,e);
  2549. const akkumuations_t da3_1b = a.tri(pi,p2,p1,e)-a.tri(pi,p1,p2,e);
  2550. summe += da3_1b*dh3_1b;
  2551. const akkumuations_t dh3_2a = h.tri(z2,zi,z2,e)-h.tri(z1,zi,z1,e);
  2552. const akkumuations_t da3_2a = a.tri(p1,pi,p1,e)-a.tri(p2,pi,p2,e);
  2553. summe += da3_2a*dh3_2a;
  2554. const akkumuations_t dh3_2b = h.tri(z1,zi,z2,e)-h.tri(z2,zi,z1,e);
  2555. const akkumuations_t da3_2b = a.tri(p2,pi,p1,e)-a.tri(p1,pi,p2,e);
  2556. summe += da3_2b*dh3_2b;
  2557. const akkumuations_t dh3_3a = h.tri(z2,z2,zi,e)-h.tri(z1,z1,zi,e);
  2558. const akkumuations_t da3_3a = a.tri(p1,p1,pi,e)-a.tri(p2,p2,pi,e);
  2559. summe += da3_3a*dh3_3a;
  2560. const akkumuations_t dh3_3b = h.tri(z1,z2,zi,e)-h.tri(z2,z1,zi,e);
  2561. const akkumuations_t da3_3b = a.tri(p2,p1,pi,e)-a.tri(p1,p2,pi,e);
  2562. summe += da3_3b*dh3_3b;
  2563. }
  2564. }
  2565. for(int e = 0; e < nebene; ++e){
  2566. const akkumuations_t dh3_a = h.tri(z2,z2,z2,e)-h.tri(z1,z1,z1,e);
  2567. const akkumuations_t da3_a = a.tri(p1,p1,p1,e)-a.tri(p2,p2,p2,e);
  2568. summe += da3_a*dh3_a;
  2569. const akkumuations_t dh3_b = h.tri(z2,z2,z1,e)-h.tri(z1,z1,z2,e);
  2570. const akkumuations_t da3_b = a.tri(p1,p1,p2,e)-a.tri(p2,p2,p1,e);
  2571. summe += da3_b*dh3_b;
  2572. const akkumuations_t dh3_c = h.tri(z2,z1,z2,e)-h.tri(z1,z2,z1,e);
  2573. const akkumuations_t da3_c = a.tri(p1,p2,p1,e)-a.tri(p2,p1,p2,e);
  2574. summe += da3_c*dh3_c;
  2575. const akkumuations_t dh3_d = h.tri(z1,z2,z2,e)-h.tri(z2,z1,z1,e);
  2576. const akkumuations_t da3_d = a.tri(p2,p1,p1,e)-a.tri(p1,p2,p2,e);
  2577. summe += da3_d*dh3_d;
  2578. }
  2579. }
  2580.  
  2581. const int f1 = tastatur.finger_index(p1), f2 = tastatur.finger_index(p2);
  2582. if(f1 == f2) return summe;
  2583.  
  2584. const int sf1 = tastatur.shift_finger_index(p1);
  2585. const int sf2 = tastatur.shift_finger_index(p2);
  2586. akkumuations_t fsgesamt = 0;
  2587. for(int k = 0; k < h.num_korpus(); ++k){
  2588. akkumuations_t fh_neu[nfinger+1];
  2589. for(int i = 0; i < nfinger+1; ++i) fh_neu[i] = fh_alt[k][i];
  2590. for(int e1 = 0; e1 < nebene; ++e1){
  2591. const akkumuations_t dh = h(k,z1,e1)-h(k,z2,e1);
  2592. fh_neu[f1] -= dh;
  2593. fh_neu[f2] += dh;
  2594. }
  2595. if(sf1 != sf2){
  2596. const akkumuations_t dh = h(k,z1,1)-h(k,z2,1);
  2597. fh_neu[sf1] -= dh;
  2598. fh_neu[sf2] += dh;
  2599. }
  2600.  
  2601. akkumuations_t fs = 0;
  2602. for(int i = 0; i < nfinger; ++i){
  2603. const akkumuations_t diff = (fh_neu[i]-fh_alt[k][i]);
  2604. if(diff){
  2605. const akkumuations_t d_neu = a.fingerabweichung(i, fh_neu[i]);
  2606. const akkumuations_t d_alt = a.fingerabweichung(i, fh_alt[k][i]);
  2607. if(d_neu > 0){
  2608. if(d_alt > 0){
  2609. const akkumuations_t plus =
  2610. a.fingerabweichung(i, 0.5*(fh_neu[i]+fh_alt[k][i]));
  2611. fs += a.mult_finger(i)*plus*diff;
  2612. }else fs += 0.5*a.mult_finger(i)*d_neu*d_neu;
  2613. }else if(d_alt > 0)
  2614. fs -= 0.5*a.mult_finger(i)*d_alt*d_alt;
  2615. }
  2616. }
  2617. fsgesamt += h.gewicht(k)*fs;
  2618. }
  2619.  
  2620. return summe+2*fsgesamt;
  2621. }
  2622.  
  2623. // Berechne variablen Gesamtaufwand einer Belegung
  2624. akkumuations_t
  2625. variabler_aufwand(const belegung_t b, const Haeufigkeit& h,
  2626. const fingerbelastung_t fh,
  2627. const Aufwandstabelle& a)
  2628. {
  2629. akkumuations_t summe = 0;
  2630.  
  2631. for(int p1 = 0; p1 < ntaste; ++p1){
  2632. BELEGUNG(z1, b, p1);
  2633. for(int e1 = 0; e1 < nebene; ++e1){
  2634. const akkumuations_t a1 = a(p1,e1), h1 = h(z1,e1);
  2635. summe += a1*h1;
  2636. }
  2637. }
  2638.  
  2639. for(int p1 = 0; p1 < ntaste; ++p1){
  2640. BELEGUNG(z1, b, p1);
  2641. for(int p2 = 0; p2 < ntaste; ++p2){
  2642. BELEGUNG(z2, b, p2);
  2643. for(int e1 = 0; e1 < nebene; ++e1){
  2644. for(int e2 = 0; e2 < nebene2; ++e2){
  2645. const akkumuations_t a2 = a(p1,e1,p2,e2), h2 = h(z1,e1,z2,e2);
  2646. summe += a2*h2;
  2647. }
  2648. }
  2649. }
  2650. }
  2651.  
  2652. if(a.hat_vorlieben()) summe += a.knick(berechne_vorliebensumme(b, a));
  2653.  
  2654. if(a.hat_aehnlichkeit()){
  2655. for(int p1 = 0; p1 < ntaste; ++p1){
  2656. const int z1 = b[p1];
  2657. for(int p2 = 0; p2 < p1; ++p2){
  2658. const int z2 = b[p2];
  2659. const akkumuations_t a2 = a.verwechslungspotenzial(p1,p2);
  2660. const akkumuations_t h2 = a.aehnlichkeit(z1,z2);
  2661. // Faktor 2, weil wir in der Doppelschleife Symmetrie ausnutzen.
  2662. summe += 2.*a2*h2;
  2663. }
  2664. }
  2665. }
  2666.  
  2667. if(h.mit_trigrammen()){
  2668. for(int p1 = 0; p1 < ntaste; ++p1){
  2669. BELEGUNG(z1, b, p1);
  2670. for(int p2 = 0; p2 < ntaste; ++p2){
  2671. BELEGUNG(z2, b, p2);
  2672. for(int p3 = 0; p3 < ntaste; ++p3){
  2673. BELEGUNG(z3, b, p3);
  2674. for(int e3 = 0; e3 < nebene; ++e3){
  2675. const akkumuations_t a3 = a.tri(p1,p2,p3,e3);
  2676. const akkumuations_t h3 = h.tri(z1,z2,z3,e3);
  2677. summe += a3*h3;
  2678. }
  2679. }
  2680. }
  2681. }
  2682. }
  2683.  
  2684. akkumuations_t fsgesamt = 0;
  2685. for(int k = 0; k < h.num_korpus(); ++k){
  2686. akkumuations_t fs = 0;
  2687. for(int i = 0; i < nfinger; ++i){
  2688. if(a.mult_finger(i) == 0) continue;
  2689. const akkumuations_t diff = a.fingerabweichung(i, fh[k][i]);
  2690. if(diff > 0) fs += a.mult_finger(i)*diff*diff;
  2691. }
  2692. fsgesamt += h.gewicht(k)*fs;
  2693. }
  2694. return summe+fsgesamt;
  2695. }
  2696.  
  2697. inline akkumuations_t
  2698. zufaelliger_abstieg(belegung_t b, const Tastatur& tastatur, Haeufigkeit& h,
  2699. const Aufwandstabelle& a, rngengine_t& rng, uniform_t& d)
  2700. {
  2701. bool reduktion;
  2702. belegung_t p;
  2703. int probiert[ntaste][ntaste];
  2704. int variante = 1;
  2705. std::memset(probiert, 0, sizeof(probiert));
  2706. fingerbelastung_t fh;
  2707. berechne_fingerbelastung(b, h, tastatur, fh);
  2708. #ifndef NDEBUG
  2709. akkumuations_t alt = variabler_aufwand(b, h, fh, a);
  2710. #endif // !NDEBUG
  2711. #ifdef EXPERIMENTELL
  2712. akkumuations_t vs = berechne_vorliebensumme(b, a);
  2713. #endif // EXPERIMENTELL
  2714. do{
  2715. reduktion = false;
  2716. zufallsbelegung(p, tastatur.nvariabel(), rng, d);
  2717. for(int i = 0; i < tastatur.nvariabel()-1; ++i){
  2718. const int pi = p[i];
  2719. for(int j = i+1; j < tastatur.nvariabel(); ++j){
  2720. const int pj = p[j];
  2721. if(probiert[pi][pj] == variante) continue;
  2722. const akkumuations_t diff =
  2723. #ifdef EXPERIMENTELL
  2724. diff_aufwand(pi, pj, b, tastatur, h, fh, vs, a);
  2725. #else
  2726. diff_aufwand(pi, pj, b, tastatur, h, fh, a);
  2727. #endif // !EXPERIMENTELL
  2728. if(diff < 0){
  2729. std::swap(b[pi], b[pj]);
  2730. #ifndef PERMUTATIONEN_ALT
  2731. h.swap(pi, pj);
  2732. #endif // !PERMUTATIONEN_ALT
  2733. #ifdef EXPERIMENTELL
  2734. vs = berechne_vorliebensumme(b, a);
  2735. #endif // EXPERIMENTELL
  2736. berechne_fingerbelastung(b, h, tastatur, fh);
  2737. reduktion = true;
  2738. ++variante;
  2739. #ifndef NDEBUG
  2740. const akkumuations_t neu = variabler_aufwand(b, h, fh, a);
  2741. if(std::abs((neu-alt)-diff) >= 1e-5*std::abs(neu+alt)){
  2742. std::cerr << SPRACHE("Relativer Fehler ","Relative error ")
  2743. << std::abs((neu-alt)-diff)/std::abs(neu+alt)
  2744. << std::endl;
  2745. exit(1);
  2746. }
  2747. alt = neu;
  2748. #endif // !NDEBUG
  2749. }
  2750. probiert[pi][pj] = probiert[pj][pi] = variante;
  2751. }
  2752. }
  2753. }while(reduktion);
  2754.  
  2755. return variabler_aufwand(b, h, fh, a);
  2756. }
  2757.  
  2758. struct zyklen_t {
  2759. int pos[ntaste][ntaste];
  2760. int idx[ntaste+1];
  2761. int teilweise;
  2762. };
  2763.  
  2764.  
  2765.  
  2766.  
  2767. void variiere_tasten(belegung_t b, const Tastatur& tastatur,
  2768. const Kodierung& kodierung, Haeufigkeit& h,
  2769. const fingerbelastung_t& fh,
  2770. #ifdef EXPERIMENTELL
  2771. const akkumuations_t vs,
  2772. #endif // EXPERIMENTELL
  2773. const Aufwandstabelle& a, akkumuations_t A, int tiefe,
  2774. zyklen_t& zyklen, int ab, akkumuations_t limit,
  2775. const bool* fest)
  2776. {
  2777. --tiefe;
  2778. for(int p2 = ab; p2 < tastatur.nvariabel(); ++p2){
  2779. if(fest[p2]) continue;
  2780. int z = 0;
  2781. for(; zyklen.idx[z]; ++z){
  2782. const int zlaenge = zyklen.idx[z];
  2783. if(zlaenge == 1) --zyklen.teilweise;
  2784. zyklen.pos[z][zlaenge] = p2;
  2785. if(tiefe) ++zyklen.idx[z];
  2786.  
  2787. for(int j = 0; j < zlaenge; ++j){
  2788. const int p1 = zyklen.pos[z][j];
  2789.  
  2790. const akkumuations_t Aneu =
  2791. #ifdef EXPERIMENTELL
  2792. A+diff_aufwand(p1, p2, b, tastatur, h, fh, vs, a);
  2793. #else
  2794. A+diff_aufwand(p1, p2, b, tastatur, h, fh, a);
  2795. #endif // !EXPERIMENTELL
  2796.  
  2797. std::swap(b[p1], b[p2]);
  2798.  
  2799. if(zyklen.teilweise == 0 && Aneu < limit)
  2800. schreibe_belegung(b, Aneu+konstanter_aufwand(h, a),
  2801. tastatur.nvariabel(), kodierung,0);
  2802.  
  2803. if(tiefe && tiefe >= zyklen.teilweise &&
  2804. p2+1 < tastatur.nvariabel()){
  2805. #ifndef PERMUTATIONEN_ALT
  2806. h.swap(p1, p2);
  2807. #endif // !PERMUTATIONEN_ALT
  2808. fingerbelastung_t fh2;
  2809. berechne_fingerbelastung(b, h, tastatur, fh2);
  2810. #ifdef EXPERIMENTELL
  2811. const akkumuations_t vs2 = berechne_vorliebensumme(b, a);
  2812. variiere_tasten(b, tastatur, kodierung, h, fh2, vs2, a, Aneu,
  2813. tiefe, zyklen, p2+1, limit, fest);
  2814. #else
  2815. variiere_tasten(b, tastatur, kodierung, h, fh2, a, Aneu,
  2816. tiefe, zyklen, p2+1, limit, fest);
  2817. #endif // !EXPERIMENTELL
  2818.  
  2819. #ifndef PERMUTATIONEN_ALT
  2820. h.swap(p1, p2);
  2821. #endif // !PERMUTATIONEN_ALT
  2822. }
  2823. std::swap(b[p1], b[p2]);
  2824. }
  2825. zyklen.idx[z] = zlaenge;
  2826. if(zlaenge == 1) ++zyklen.teilweise;
  2827. }
  2828.  
  2829. if(tiefe > zyklen.teilweise && p2+1 < tastatur.nvariabel()){
  2830. zyklen.idx[z] = 1;
  2831. zyklen.pos[z][0] = p2;
  2832. ++zyklen.teilweise;
  2833. #ifdef EXPERIMENTELL
  2834. variiere_tasten(b, tastatur, kodierung, h, fh, vs, a, A,
  2835. tiefe, zyklen, p2+1, limit, fest);
  2836. #else // !EXPERIMENTELL
  2837. variiere_tasten(b, tastatur, kodierung, h, fh, a, A,
  2838. tiefe, zyklen, p2+1, limit, fest);
  2839. #endif // !EXPERIMENTELL
  2840. zyklen.idx[z] = 0;
  2841. --zyklen.teilweise;
  2842. }
  2843. }
  2844. }
  2845.  
  2846. } // Ende des namenlosen Namensraums.
  2847.  
  2848.  
  2849. void
  2850. suche_optimum(const Tastatur& tastatur, const Kodierung& kodierung,
  2851. const Haeufigkeit* korpus, const Aufwandstabelle& a,
  2852. akkumuations_t minimum, bool schoene_tastatur, bool alle_guten,
  2853. bool als_fixeszeichen, int saatwert, int iterationen,
  2854. int lebenszeichen, const double ngrammakkumlimit[3],
  2855. const std::unordered_map<std::string, haeufigkeit_t>& wortliste,
  2856. akkumuations_t handeinsatzlimit, Grafik* grafik,
  2857. akkumuations_t* globalesMinimum)
  2858. {
  2859. // Es ist nicht klar, dass diese beiden Kopien die Geschwindigkeit
  2860. // verbessern. Auf meiner Maschine tun sie es.
  2861. std::unique_ptr<const Haeufigkeit> h(new Haeufigkeit(*korpus, 0));
  2862. std::unique_ptr<const Aufwandstabelle> aufwand(new Aufwandstabelle(a));
  2863.  
  2864. rngengine_t rng(saatwert);
  2865. uniform_t uniform;
  2866. std::unique_ptr<Haeufigkeit> arbeitskorpus(new Haeufigkeit(*h, 0));
  2867.  
  2868. for(int j = 0; j++ < iterationen;){
  2869. belegung_t b; zufallsbelegung(b, tastatur.nvariabel(), rng, uniform);
  2870.  
  2871. #ifndef PERMUTATIONEN_ALT
  2872. arbeitskorpus->setze(*h, b);
  2873. #endif // !PERMUTATIONEN_ALT
  2874. const akkumuations_t A = zufaelliger_abstieg(b, tastatur, *arbeitskorpus,
  2875. *aufwand, rng, uniform);
  2876. if(A < minimum){
  2877. #ifdef MIT_THREADS
  2878. std::lock_guard<std::mutex> sperre(ausgabemutex);
  2879. #endif // MIT_THREADS
  2880. if(A < *globalesMinimum){
  2881. if(!alle_guten) minimum = *globalesMinimum = A;
  2882. const akkumuations_t K =
  2883. konstanter_aufwand(*arbeitskorpus, *aufwand);
  2884. if(schoene_tastatur)
  2885. schreibe_belegung(b, tastatur, kodierung, *h, *aufwand, A+K,
  2886. zahl_in_utf32(j), ngrammakkumlimit, wortliste,
  2887. handeinsatzlimit, als_fixeszeichen);
  2888. else
  2889. schreibe_belegung(b, A+K, tastatur.nvariabel(), kodierung, 0);
  2890.  
  2891. if(grafik) grafik->ausgabe(b);
  2892. }else if(!alle_guten) minimum = *globalesMinimum;
  2893. }
  2894.  
  2895. if(j % lebenszeichen == 0)
  2896. std::cerr << SPRACHE("Thread 0: Lokale Optimierung ",
  2897. "Thread 0: Local optimisation ")<< j << std::endl;
  2898. }
  2899. }
  2900.  
  2901. double anzahl_varianten(int N, int n)
  2902. {
  2903. double C = N;
  2904. double sf2 = 1, sf1 = 0;
  2905. double summe = 1;
  2906. for(int i = 2; i <= n; ++i){
  2907. C = (C*(N-(i-1)))/i;
  2908. const double sf = (i-1)*(sf1+sf2);
  2909. sf2 = sf1; sf1 = sf;
  2910. summe += C*sf;
  2911. }
  2912. return summe;
  2913. }
  2914.  
  2915. void
  2916. erzeuge_variationen(const belegung_t ausgangsbelegung,
  2917. const Tastatur& tastatur, const Kodierung& kodierung,
  2918. Haeufigkeit& h, const Aufwandstabelle& a,
  2919. akkumuations_t A, int tiefe,
  2920. akkumuations_t limit, const bool* fest)
  2921. {
  2922. belegung_t b;
  2923. for(int i = 0; i < ntaste; ++i) b[i] = ausgangsbelegung[i];
  2924. fingerbelastung_t fh;
  2925. berechne_fingerbelastung(b, h, tastatur, fh);
  2926. zyklen_t zyklen;
  2927. for(int i = 0; i < tastatur.nvariabel()+1; ++i) zyklen.idx[i] = 0;
  2928. zyklen.teilweise = 0;
  2929. #ifdef EXPERIMENTELL
  2930. const akkumuations_t vs = berechne_vorliebensumme(b, a);
  2931. variiere_tasten(b, tastatur, kodierung, h, fh, vs, a, A,
  2932. tiefe, zyklen, 0, limit, fest);
  2933. #else
  2934. variiere_tasten(b, tastatur, kodierung, h, fh, a, A,
  2935. tiefe, zyklen, 0, limit, fest);
  2936. #endif // !EXPERIMENTELL
  2937. }
  2938.  
  2939. akkumuations_t
  2940. aufwandsvarianz(const belegung_t b1, const belegung_t* b2,
  2941. const Tastatur& tastatur,
  2942. const Haeufigkeit& h,
  2943. const Aufwandstabelle& a)
  2944. {
  2945. assert(h.mit_varianzen());
  2946. akkumuations_t summe = 0;
  2947. // Umkehrung der Belegung(en)
  2948. belegung_t ib1, ib2;
  2949. for(int i = 0; i < ntaste; ++i) ib1[b1[i]] = ib2[b1[i]] = i;
  2950. if(b2) for(int i = 0; i < ntaste; ++i) ib2[(*b2)[i]] = i;
  2951.  
  2952. // Ableitung der (Differenz der) Aufwände für das Überschreiten der
  2953. // Zielhäufigkeiten nach den Anschlagsshäufigkeiten, tabelliert nach Zeichen.
  2954. akkumuations_t fhdiff[nmaxkorpus][ntaste][nebene];
  2955. for(int k = 0; k < h.num_korpus(); ++k){
  2956. akkumuations_t fh[2][nfinger+1];
  2957. memset(fh, 0, sizeof(fh));
  2958. for(int j = 0; j < (b2 ? 2 : 1); ++j){
  2959. for(int z = 0; z < ntaste; ++z){
  2960. const int p = j ? ib2[z] : ib1[z];
  2961. const int fi = tastatur.finger_index(p);
  2962. const int sf = tastatur.shift_finger_index(p);
  2963. for(int e = 0; e < nebene; ++e) fh[j][fi] += h(k,z,e);
  2964. fh[j][sf] += h(k,z,1);
  2965. }
  2966. for(int i = 0; i < nfinger; ++i){
  2967. const akkumuations_t diff = a.fingerabweichung(i, fh[j][i]);
  2968. fh[j][i] = diff > 0 ? 2.*h.gewicht(k)*a.mult_finger(i)*diff : 0;
  2969. }
  2970. fh[j][nfinger] = 0;
  2971. }
  2972. for(int z = 0; z < ntaste; ++z){
  2973. const int p1 = ib1[z], p2 = ib2[z];
  2974. const int f1 = tastatur.finger_index(p1);
  2975. const int s1 = tastatur.shift_finger_index(p1);
  2976. const int f2 = tastatur.finger_index(p2);
  2977. const int s2 = tastatur.shift_finger_index(p2);
  2978. for(int e = 0; e < nebene; ++e) fhdiff[k][z][e] = fh[0][f1]-fh[1][f2];
  2979. fhdiff[k][z][1] += fh[0][s1]-fh[1][s2];
  2980. }
  2981. }
  2982.  
  2983. akkumuations_t a1diff[Haeufigkeit::groesse1];
  2984. for(int z1 = 0; z1 < ntaste; ++z1){
  2985. for(int e = 0; e < nebene; ++e)
  2986. a1diff[nebene*z1+e] = b2 ? a(ib1[z1],e)-a(ib2[z1],e) : a(ib1[z1],e);
  2987. }
  2988.  
  2989. for(int z1 = 0; z1 < ntaste; ++z1){
  2990. const int p1_1 = ib1[z1], p1_2 = ib2[z1];
  2991. for(int e1 = 0; e1 < nebene; ++e1){
  2992. const int o1 = nebene*z1+e1;
  2993. for(int z2 = 0; z2 < ntaste; ++z2){
  2994. int p2_1 = ib1[z2], p2_2 = ib2[z2];
  2995. for(int e2 = 0; e2 < nebene; ++e2){
  2996. const int o2 = nebene*z2+e2;
  2997. const haeufigkeit_t h11 = h.ein_ein(o1, o2);
  2998. summe += a1diff[o1]*a1diff[o2]*h11;
  2999.  
  3000. for(int k1 = 0; k1 < h.num_korpus(); ++k1){
  3001. const haeufigkeit_t h11k = h.ein_ein_k(k1, o1, o2);
  3002. summe += a1diff[o1]*fhdiff[k1][z2][e2]*h11k;
  3003. const haeufigkeit_t h11kk = h.ein_k_ein_k(k1, o1, o2);
  3004. summe += fhdiff[k1][z1][e1]*fhdiff[k1][z2][e2]*h11kk;
  3005. }
  3006.  
  3007. if(e2 >= nebene2) continue;
  3008.  
  3009. const int o12 = Haeufigkeit::index_bi_flach(o1, o2);
  3010. const akkumuations_t a12_1 = a(p1_1, e1, p2_1, e2);
  3011. const akkumuations_t a12_2 = b2 ? a(p1_2, e1, p2_2, e2) : 0;
  3012. for(int z3 = 0; z3 < ntaste; ++z3){
  3013. int p3_1 = ib1[z3], p3_2 = ib2[z3];
  3014. for(int e3 = 0; e3 < nebene; ++e3){
  3015. const int o3 = nebene*z3+e3;
  3016. const haeufigkeit_t h21 = h.ein_bi(o3, o12);
  3017. summe += (a12_1-a12_2)*a1diff[o3]*h21;
  3018.  
  3019. for(int k2 = 0; k2 < h.num_korpus(); ++k2){
  3020. const haeufigkeit_t h21k = h.ein_k_bi(k2, o3, o12);
  3021. summe += (a12_1-a12_2)*fhdiff[k2][z3][e3]*h21k;
  3022. }
  3023.  
  3024. for(int z4 = 0; z4 < ntaste; ++z4){
  3025. int p4_1 = ib1[z4], p4_2 = ib2[z4];
  3026. for(int e4 = 0; e4 < nebene2; ++e4){
  3027. const int o4 = nebene*z4+e4;
  3028. const int o34 = Haeufigkeit::index_bi_flach(o3, o4);
  3029. const akkumuations_t a34_1 = a(p3_1, e3, p4_1, e4);
  3030. const akkumuations_t a34_2 =
  3031. b2 ? a(p3_2, e3, p4_2, e4 ) : 0;
  3032. const haeufigkeit_t h22 = h.bi_bi(o12, o34);
  3033. summe += (a12_1-a12_2)*(a34_1-a34_2)*h22;
  3034. }
  3035. }
  3036. }
  3037. }
  3038. }
  3039. }
  3040. }
  3041. }
  3042.  
  3043. return summe;
  3044. }
  3045.  
  3046. akkumuations_t
  3047. konstanter_aufwand(const Haeufigkeit& h, const Aufwandstabelle& a)
  3048. { return a.unbekannt()*h.unbekannt(); }
  3049.  
  3050. akkumuations_t
  3051. variabler_aufwand(const belegung_t b, const Haeufigkeit& h,
  3052. const Tastatur& tastatur, const Aufwandstabelle& a)
  3053. {
  3054. fingerbelastung_t fh;
  3055. berechne_fingerbelastung(b, h, tastatur, fh);
  3056. return variabler_aufwand(b, h, fh, a);
  3057. }
  3058.  
  3059. //--------------- src/Haeufigkeit.cc ---------------
  3060. //#include "Haeufigkeit.hh"
  3061.  
  3062. //#include "Kodierung.hh"
  3063. //#include "Naechstes_zeichen.hh"
  3064. //#include "Tastatur.hh"
  3065. //#include "utfhilfe.hh"
  3066. #include <cstring>
  3067. #include <iomanip>
  3068. #include <iostream>
  3069. #include <string>
  3070.  
  3071. namespace {
  3072.  
  3073. bool lies_codierte_ngramme(const std::string& name, size_t N, size_t Nmax,
  3074. zaehl_t** uh, const Kodierung& kodierung,
  3075. bool muss_existieren, bool& utf8ein,
  3076. std::unordered_map<char32_t, zaehl_t>* unbekannt)
  3077. {
  3078. Eingabestream tabelle(name, utf8ein, muss_existieren);
  3079. if(!tabelle.neuezeile()) return false;
  3080.  
  3081. while(tabelle.echte_neuezeile()){
  3082. const zaehl_t h = hole_zahl(tabelle, 0, 1e15);
  3083. pruefe_leer_dann_N(tabelle, N);
  3084. tabelle.uebergehen();
  3085.  
  3086. size_t ende1 = 0, anfangN = 0; bool ok = true;
  3087. std::vector<std::pair<int, int>> alles;
  3088. for(size_t i = 0; i < N; ++i){
  3089. const char32_t z = tabelle.lies_in_zeile();
  3090. const auto p = kodierung.position(z);
  3091. anfangN = alles.size();
  3092. if(p.first >= 0){
  3093. alles.push_back(p);
  3094. }else if(auto s = kodierung.ersatz(z)){
  3095. for(const auto& j : *s) alles.push_back(j);
  3096. }else{
  3097. ok = false;
  3098. if(unbekannt) (*unbekannt)[z] += h;
  3099. }
  3100. if(!i) ende1 = alles.size();
  3101. }
  3102.  
  3103. if(!ok) continue;
  3104. for(size_t i = 0; i < ende1; ++i){
  3105. int offset = 0;
  3106. for(size_t j = 0; j < Nmax && i+j < alles.size(); ++j){
  3107. const int p = alles[i+j].first, e = alles[i+j].second;
  3108. offset = (offset*ntaste+p)*nebene+e;
  3109. if(j+1 >= N && i+j >= anfangN) uh[j][offset] += h;
  3110. }
  3111. }
  3112. }
  3113.  
  3114. if(tabelle.encoding_geaendert()) utf8ein = false;
  3115. return true;
  3116. }
  3117.  
  3118. int leerzeichenindex(const Kodierung& kodierung){
  3119. const auto p = kodierung.position(U' ');
  3120. if(p.first < 0){
  3121. const auto ersatz = kodierung.ersatz(U' ');
  3122. return ersatz ? (*ersatz)[0].first*nebene+(*ersatz)[0].second : -1;
  3123. }else return p.first*nebene+p.second;
  3124. }
  3125.  
  3126. }
  3127.  
  3128. Haeufigkeit::Haeufigkeit(const Tastatur& tastatur, const Kodierung& kod,
  3129. const std::vector<std::string>& basis,
  3130. const std::vector<double>& gewicht,
  3131. const std::vector<bool>& tri,
  3132. bool varianzen, bool berichte_unbekanne_zeichen)
  3133. : nkorpus(basis.size()), trigramme(false), tastatur(tastatur),
  3134. kodierung(kod), h11(nullptr), h21(nullptr), h22(nullptr)
  3135. {
  3136. memset(h3, 0, sizeof(h3));
  3137. memset(h2, 0, sizeof(h2));
  3138. memset(h1, 0, sizeof(h1));
  3139. memset(h1e, 0, sizeof(h1e));
  3140. memset(h11e, 0, sizeof(h11e));
  3141. memset(h11ee, 0, sizeof(h11ee));
  3142. memset(h21e, 0, sizeof(h21e));
  3143.  
  3144. std::unordered_map<char32_t, zaehl_t> summe_unbekannt;
  3145.  
  3146. for(size_t i = 0; i < basis.size(); ++i){
  3147. std::unordered_map<char32_t, zaehl_t> unbekannt;
  3148. zaehl_ta uh1(new zaehl_t[groesse1]), uh2(new zaehl_t[groesse2]);
  3149. zaehl_ta uh3, uh11, uh21, uh22, uh1l, uh1s, uh2l, uh2s;
  3150. const bool t = tri[i];
  3151. if(t){
  3152. trigramme = true;
  3153. uh3 = zaehl_ta(new zaehl_t[groesse3]);
  3154. }
  3155. zaehl_t llvarianz = 0, lsvarianz = 0, ssvarianz = 0;
  3156.  
  3157. zaehl_t* uh[3] = { uh1.get(), uh2.get(), uh3.get() };
  3158.  
  3159. bool nochmal, utf8[3] = {true, true, true}, utf8a[3] = {true, true, true};
  3160. do{
  3161. unbekannt.clear();
  3162. nochmal = false;
  3163. memset(uh1.get(), 0, sizeof(zaehl_t)*groesse1);
  3164. memset(uh2.get(), 0, sizeof(zaehl_t)*groesse2);
  3165. if(uh3) memset(uh3.get(), 0, sizeof(zaehl_t)*groesse3);
  3166.  
  3167. if(lies_codierte_ngramme(basis[i]+".1", 1, t ? 3 : 2, uh, kodierung,
  3168. false, utf8[0], berichte_unbekanne_zeichen
  3169. ? &unbekannt : nullptr)){
  3170. lies_codierte_ngramme(basis[i]+".2", 2, t ? 3 : 2, uh, kodierung,
  3171. true, utf8[1], nullptr);
  3172. if(t) lies_codierte_ngramme(basis[i]+".3", 3, 3, uh, kodierung,
  3173. true, utf8[2], nullptr);
  3174. for(size_t j = 0; j < 3; ++j){
  3175. nochmal |= (utf8a[j] != utf8[j]);
  3176. utf8a[j] = utf8[j];
  3177. }
  3178. }else{
  3179. if(varianzen && utf8[0]){// nur beim ersten Versuch anlegen/init.
  3180. uh11 = zaehl_ta(new zaehl_t[groesse11]);
  3181. uh21 = zaehl_ta(new zaehl_t[groesse21]);
  3182. uh22 = zaehl_ta(new zaehl_t[groesse22]);
  3183. uh1l = zaehl_ta(new zaehl_t[groesse1]);
  3184. uh1s = zaehl_ta(new zaehl_t[groesse1]);
  3185. uh2l = zaehl_ta(new zaehl_t[groesse2]);
  3186. uh2s = zaehl_ta(new zaehl_t[groesse2]);
  3187. memset(uh11.get(), 0, sizeof(zaehl_t)*groesse11);
  3188. memset(uh21.get(), 0, sizeof(zaehl_t)*groesse21);
  3189. memset(uh22.get(), 0, sizeof(zaehl_t)*groesse22);
  3190. memset(uh1l.get(), 0, sizeof(zaehl_t)*groesse1);
  3191. memset(uh1s.get(), 0, sizeof(zaehl_t)*groesse1);
  3192. memset(uh2l.get(), 0, sizeof(zaehl_t)*groesse2);
  3193. memset(uh2s.get(), 0, sizeof(zaehl_t)*groesse2);
  3194. }
  3195.  
  3196. std::unique_ptr<Naechstes_zeichen> nz
  3197. (new Naechstes_zeichen(basis[i], utf8[0]));
  3198.  
  3199. const int o_korrelationsende = leerzeichenindex(kodierung);
  3200. std::u32string wort;
  3201. zaehl_t nworte = 0;
  3202. std::unordered_map<std::u32string, zaehl_t> worthaeufigkeit;
  3203.  
  3204. // Zähle Wörter, sammle 1/2/3-Gramme
  3205. int o1 = -1, o2 = -1;
  3206. while(const char32_t z = nz->get()){
  3207. const auto p = kodierung.position(z);
  3208. std::vector<std::pair<int,int>> pos(1, p);
  3209. if(p.first < 0){
  3210. const auto ersatz = kodierung.ersatz(z);
  3211. if(ersatz) pos = *ersatz;
  3212. }
  3213.  
  3214. for(const auto j : pos){
  3215. const int o3 = j.first < 0
  3216. ? -1 : index_ein_flach(j.first, j.second);
  3217. if(o3 >= 0){
  3218. wort.push_back(o3);
  3219. ++uh1[o3];
  3220. if(o2 >= 0){
  3221. ++uh2[index_bi_flach(o2, o3)];
  3222. if(t && o1 >= 0)
  3223. ++uh3[index_tri_flach(o1,o2,o3)];
  3224. }
  3225. o1 = o2; o2 = o3;
  3226. }else{
  3227. if(berichte_unbekanne_zeichen && z >= U' ') ++unbekannt[z];
  3228. o1 = o2 = -1;
  3229. }
  3230.  
  3231. if(o3 < 0 || o3 == o_korrelationsende){
  3232. if(varianzen && wort.size()){
  3233. ++worthaeufigkeit[wort];
  3234. ++nworte;
  3235. }
  3236. wort.clear();
  3237. if(o3 >= 0) wort.push_back(o3);
  3238. }
  3239. }
  3240. }
  3241. if(varianzen && wort.size()){
  3242. ++worthaeufigkeit[wort];
  3243. ++nworte;
  3244. }
  3245.  
  3246. nochmal = nz->encoding_geaendert();
  3247.  
  3248. if(nochmal){
  3249. utf8[0] = false;
  3250. }else if(varianzen){
  3251. const double rez_nworte = 1./nworte;
  3252. for(const auto& wort_h : worthaeufigkeit){
  3253. const std::u32string& wort = wort_h.first;
  3254. const size_t rohe_wortlaenge = wort.length();
  3255. double anschlaege = 0., wortlaenge = 0.;
  3256.  
  3257. // Zähle n-Gramme im Wort
  3258. int o2 = -1;
  3259. std::unordered_map<int, double> wh1, wh2;
  3260. for(size_t j = 0; j < rohe_wortlaenge; ++j){
  3261. const int o3 = wort[j];
  3262. // Jedes "o_korrelationsende" wurde in zwei Wörter
  3263. // aufgenommen, daher zählen wir sie hier nur halb.
  3264. const double plus = o3 != o_korrelationsende ? 1 : 0.5;
  3265. if(o3%nebene) anschlaege += plus;
  3266. wh1[o3] += plus;
  3267. anschlaege += plus;
  3268. wortlaenge += plus;
  3269.  
  3270. if(o2 >= 0) ++wh2[index_bi_flach(o2, o3)];
  3271. o2 = o3;
  3272. }
  3273.  
  3274. // Aus Wortzahl und n-Grammzahl pro Wort die
  3275. // n-Grammhäufigkeiten bestimmen, Varianzen (unter Annahme
  3276. // einer Binominalverteilung der Worte) berechnen.
  3277. const zaehl_t h = wort_h.second;
  3278. const double varianz = h*(1.-h*rez_nworte);
  3279. llvarianz += wortlaenge*wortlaenge*varianz;
  3280. lsvarianz += wortlaenge*anschlaege*varianz;
  3281. ssvarianz += anschlaege*anschlaege*varianz;
  3282. for(auto j = wh1.cbegin(); j != wh1.cend(); ++j){
  3283. const int oj = j->first;
  3284. const auto hj = j->second;
  3285. uh1l[oj] += varianz*hj*wortlaenge;
  3286. uh1s[oj] += varianz*hj*anschlaege;
  3287. for(auto k = j; k != wh1.cend(); ++k){
  3288. const int ok = k->first;
  3289. const auto hk = k->second;
  3290. uh11[sym_index(oj, ok)] += varianz*(hj*hk);
  3291. }
  3292. for(auto k = wh2.cbegin(); k != wh2.cend(); ++k){
  3293. const int ok = k->first;
  3294. const auto hk = k->second;
  3295. uh21[index_tri21_flach(ok, oj)] += varianz*(hj*hk);
  3296. }
  3297. }
  3298. for(auto j = wh2.cbegin(); j != wh2.cend(); ++j){
  3299. const int oj = j->first;
  3300. const auto hj = j->second;
  3301. uh2l[oj] += varianz*hj*wortlaenge;
  3302. uh2s[oj] += varianz*hj*anschlaege;
  3303. for(auto k = j; k != wh2.cend(); ++k){
  3304. const int ok = k->first;
  3305. const auto hk = k->second;
  3306. uh22[sym_index(ok, oj)] += varianz*(hj*hk);
  3307. }
  3308. }
  3309. }
  3310. }
  3311. }
  3312. }while(nochmal);
  3313. akkumuliere(i, gewicht[i], uh1.get(), uh2.get(), uh3.get(),
  3314. uh11.get(), uh21.get(), uh22.get(),
  3315. uh1l.get(), uh1s.get(), uh2l.get(), uh2s.get(),
  3316. llvarianz, lsvarianz, ssvarianz,
  3317. unbekannt, summe_unbekannt);
  3318. gewichte[i] = gewicht[i];
  3319. }
  3320.  
  3321. for(int i = 0; i < ntaste; ++i){
  3322. for(int ei = 0; ei < nebene; ++ei){
  3323. if(kodierung.ist_platzhalter(i, ei)) continue;
  3324. const auto& txt = kodierung.txt(i, ei);
  3325. if(h1[i][ei] == 0 && (ei == 0 || txt != kodierung.txt(i, 0)))
  3326. std::cerr << SPRACHE("Zeichen '", "Symbol '") << txt
  3327. << SPRACHE("' tritt im Korpus nie auf.",
  3328. "' does not appear in the corpus.")
  3329. << std::endl;
  3330. }
  3331. }
  3332.  
  3333. hunbekannt = 0;
  3334. zaehl_t hmax = 0; char32_t zmax = 0;
  3335. for(const auto& zh : summe_unbekannt){
  3336. hunbekannt += zh.second;
  3337. if(zh.second > hmax){
  3338. hmax = zh.second; zmax = zh.first;
  3339. }
  3340. }
  3341. if(berichte_unbekanne_zeichen && hunbekannt > 0){
  3342. std::cerr << summe_unbekannt.size()
  3343. << SPRACHE(" verschiedene unbekannte Zeichen, relative "
  3344. "Gesamth" strAe "ufigkeit ",
  3345. " distinct unknown symbols, relative total "
  3346. "frequency ")
  3347. << hunbekannt*100 << "%. "
  3348. << SPRACHE("Das wichtigste dieser Zeichen ist '",
  3349. "The most important of these symbols is '")
  3350. << utf32_in_ausgabe(zmax) << "'.\n" << std::endl;
  3351. }
  3352. }
  3353.  
  3354. // Kein copy-Konstruktor: Korrelationstabellen werden nicht kopiert.
  3355. Haeufigkeit::Haeufigkeit(const Haeufigkeit& h, int)
  3356. : hunbekannt(h.hunbekannt), nkorpus(h.nkorpus),
  3357. trigramme(h.trigramme), tastatur(h.tastatur), kodierung(h.kodierung),
  3358. h11(nullptr) // nur für Destruktor
  3359. {
  3360. for(int i = 0; i < nkorpus; ++i) gewichte[i] = h.gewichte[i];
  3361. belegung_t b;
  3362. for(int j = 0; j < ntaste; ++j) b[j] = j;
  3363. setze(h, b);
  3364. }
  3365.  
  3366. Haeufigkeit::~Haeufigkeit(){
  3367. if(!h11) return;
  3368. delete []h11; delete []h21; delete []h22;
  3369. for(int i = 0; i < nkorpus; ++i){
  3370. delete []h11e[i]; delete []h11ee[i]; delete []h21e[i];
  3371. }
  3372. }
  3373.  
  3374. void
  3375. Haeufigkeit::varianzen_anlegen(){
  3376. if(mit_varianzen()) return;
  3377. h11 = new haeufigkeit_t[groesse11];
  3378. h21 = new haeufigkeit_t[groesse21];
  3379. h22 = new haeufigkeit_t[groesse22];
  3380. memset(h11, 0, sizeof(haeufigkeit_t)*groesse11);
  3381. memset(h21, 0, sizeof(haeufigkeit_t)*groesse21);
  3382. memset(h22, 0, sizeof(haeufigkeit_t)*groesse22);
  3383. for(int i = 0; i < nkorpus; ++i){
  3384. h11e[i] = new haeufigkeit_t[groesse1*groesse1];
  3385. memset(h11e[i], 0, sizeof(haeufigkeit_t)*groesse1*groesse1);
  3386. h11ee[i] = new haeufigkeit_t[groesse11];
  3387. memset(h11ee[i], 0, sizeof(haeufigkeit_t)*groesse11);
  3388. h21e[i] = new haeufigkeit_t[groesse21];
  3389. memset(h21e[i], 0, sizeof(haeufigkeit_t)*groesse21);
  3390. }
  3391. }
  3392.  
  3393. void
  3394. Haeufigkeit::setze(const Haeufigkeit& h, const belegung_t p)
  3395. {
  3396. for(int p1 = 0; p1 < ntaste; ++p1){
  3397. const int z1 = p[p1];
  3398. for(int e1 = 0; e1 < nebene; ++e1)
  3399. h1[p1][e1] = h.h1[z1][e1];
  3400. for(int k = 0; k < nkorpus; ++k)
  3401. for(int e1 = 0; e1 < nebene; ++e1)
  3402. h1e[k][p1][e1] = h.h1e[k][z1][e1];
  3403. }
  3404. for(int p1 = 0; p1 < ntaste; ++p1){
  3405. const int z1 = p[p1];
  3406. for(int p2 = 0; p2 < ntaste; ++p2){
  3407. const int z2 = p[p2];
  3408. for(int e1 = 0; e1 < nebene; ++e1)
  3409. for(int e2 = 0; e2 < nebene2; ++e2)
  3410. h2[p1][p2][e1][e2] = h.h2[z1][z2][e1][e2];
  3411. }
  3412. }
  3413. if(trigramme){
  3414. for(int p1 = 0; p1 < ntaste; ++p1){
  3415. const int z1 = p[p1];
  3416. for(int p2 = 0; p2 < ntaste; ++p2){
  3417. const int z2 = p[p2];
  3418. for(int p3 = 0; p3 < ntaste; ++p3){
  3419. const int z3 = p[p3];
  3420. for(int e1 = 0; e1 < nebene; ++e1)
  3421. h3[p1][p2][p3][e1] = h.h3[z1][z2][z3][e1];
  3422. }
  3423. }
  3424. }
  3425. }
  3426. }
  3427.  
  3428. // Sollte mit C++11 funktionieren, Solaris Studio 12.4 packt es aber nicht:
  3429. // void Haeufigkeit::swap(int p1, int p2){
  3430. // std::swap(h1[p1], h1[p2]);
  3431. // for(int k = 0; k < nkorpus; ++k)
  3432. // std::swap(h1e[k][p1], h1e[k][p2]);
  3433. // std::swap(h2[p1], h2[p2]);
  3434. // for(int p = 0; p < ntaste; ++p)
  3435. // std::swap(h2[p][p1], h2[p][p2]);
  3436. //
  3437. // if(trigramme){
  3438. // std::swap(h3[p1], h3[p2]);
  3439. // for(int pi = 0; pi < ntaste; ++pi)
  3440. // std::swap(h3[pi][p1], h3[pi][p2]);
  3441. // for(int pi = 0; pi < ntaste; ++pi)
  3442. // for(int pj = 0; pj < ntaste; ++pj)
  3443. // std::swap(h3[pi][pj][p1], h3[pi][pj][p2]);
  3444. // }
  3445. // }
  3446.  
  3447. void Haeufigkeit::swap(int p1, int p2){
  3448. for(int e1 = 0; e1 < nebene; ++e1){
  3449. const haeufigkeit_t t = h1[p1][e1];
  3450. h1[p1][e1] = h1[p2][e1];
  3451. h1[p2][e1] = t;
  3452. }
  3453. for(int k = 0; k < nkorpus; ++k)
  3454. for(int e1 = 0; e1 < nebene; ++e1){
  3455. const haeufigkeit_t t = h1e[k][p1][e1];
  3456. h1e[k][p1][e1] = h1e[k][p2][e1];
  3457. h1e[k][p2][e1] = t;
  3458. }
  3459.  
  3460. for(int p = 0; p < ntaste; ++p)
  3461. for(int e1 = 0; e1 < nebene; ++e1)
  3462. for(int e2 = 0; e2 < nebene2; ++e2){
  3463. const haeufigkeit_t t = h2[p1][p][e1][e2];
  3464. h2[p1][p][e1][e2] = h2[p2][p][e1][e2];
  3465. h2[p2][p][e1][e2] = t;
  3466. }
  3467. for(int p = 0; p < ntaste; ++p)
  3468. for(int e1 = 0; e1 < nebene; ++e1)
  3469. for(int e2 = 0; e2 < nebene2; ++e2){
  3470. const haeufigkeit_t t = h2[p][p1][e1][e2];
  3471. h2[p][p1][e1][e2] = h2[p][p2][e1][e2];
  3472. h2[p][p2][e1][e2] = t;
  3473. }
  3474. if(trigramme){
  3475. for(int pi = 0; pi < ntaste; ++pi)
  3476. for(int pj = 0; pj < ntaste; ++pj)
  3477. for(int e1 = 0; e1 < nebene; ++e1){
  3478. const haeufigkeit_t t = h3[p1][pi][pj][e1];
  3479. h3[p1][pi][pj][e1] = h3[p2][pi][pj][e1];
  3480. h3[p2][pi][pj][e1] = t;
  3481. }
  3482. for(int pi = 0; pi < ntaste; ++pi)
  3483. for(int pj = 0; pj < ntaste; ++pj)
  3484. for(int e1 = 0; e1 < nebene; ++e1){
  3485. const haeufigkeit_t t = h3[pi][p1][pj][e1];
  3486. h3[pi][p1][pj][e1] = h3[pi][p2][pj][e1];
  3487. h3[pi][p2][pj][e1] = t;
  3488. }
  3489. for(int pi = 0; pi < ntaste; ++pi)
  3490. for(int pj = 0; pj < ntaste; ++pj)
  3491. for(int e1 = 0; e1 < nebene; ++e1){
  3492. const haeufigkeit_t t = h3[pi][pj][p1][e1];
  3493. h3[pi][pj][p1][e1] = h3[pi][pj][p2][e1];
  3494. h3[pi][pj][p2][e1] = t;
  3495. }
  3496. }
  3497. }
  3498.  
  3499. void Haeufigkeit::
  3500. akkumuliere(int korpus, double gewicht,
  3501. const zaehl_t* uh1, const zaehl_t* uh2, const zaehl_t* uh3,
  3502. const zaehl_t* uh11, const zaehl_t* uh21, const zaehl_t* uh22,
  3503. const zaehl_t* uh1l, const zaehl_t* uh1s,
  3504. const zaehl_t* uh2l, const zaehl_t* uh2s,
  3505. zaehl_t ll, zaehl_t ls, zaehl_t ss,
  3506. const std::unordered_map<char32_t, zaehl_t>& unbekannt,
  3507. std::unordered_map<char32_t, zaehl_t>& summe_unbekannt)
  3508. {
  3509. zaehl_t total = 0, geshiftet = 0, mitfix = 0;
  3510.  
  3511. bool shift_variabel = 0;
  3512. for(int i = ntaste; i < ntaste+nshift; ++i)
  3513. if(!tastatur.finger_fix(tastatur.finger_index(i))) shift_variabel = true;
  3514.  
  3515. for(int i = 0; i < ntaste; ++i){
  3516. for(int ei = 0; ei < nebene; ++ei){
  3517. const int oi = index_ein_flach(i, ei);
  3518. if(!tastatur.finger_fix(tastatur.finger_index(i))) total += uh1[oi];
  3519. mitfix += uh1[oi];
  3520. if(ei && shift_variabel) geshiftet += uh1[oi];
  3521. }
  3522. }
  3523.  
  3524. const zaehl_t htot_k = total+geshiftet;
  3525. const double w = gewicht/total, w2 = w*w;
  3526. const double wf = 1./htot_k, wf2 = wf*wf, wfw = wf*w;
  3527. const double mitfix_w = gewicht/mitfix;
  3528.  
  3529. for(int i = 0; i < ntaste; ++i){
  3530. for(int ei = 0; ei < nebene; ++ei){
  3531. const int oi = index_ein_flach(i, ei);
  3532. ein(i,ei) += uh1[oi]*w;
  3533. ein_k(korpus,i,ei) = uh1[oi]*wf;
  3534.  
  3535. for(int j = 0; j < ntaste; ++j){
  3536. for(int ej = 0; ej < nebene2; ++ej){
  3537. const int oj = index_ein_flach(j, ej);
  3538. const int oij = index_bi_flach(oi, oj);
  3539. bi(i,ei,j,ej) += uh2[oij]*w;
  3540.  
  3541. // Zu dieser speziellen Summation siehe den Kommentar in
  3542. // Aufwandstabelle::Aufwandstabelle
  3543. if(uh3 && ej == 0){
  3544. for(int k = 0; k < ntaste; ++k){
  3545. for(int ek = 0; ek < nebene; ++ek){
  3546. const int ok = index_ein_flach(k, ek);
  3547. const int oijk = index_tri21_flach(oij, ok);
  3548. tri(i,j,k,ek) += uh3[oijk]*w;
  3549. }
  3550. }
  3551. }
  3552. }
  3553. }
  3554. }
  3555. }
  3556. if(uh11){
  3557. const double wk = 1./total;
  3558. varianzen_anlegen();
  3559. for(int oi = 0; oi < groesse1; ++oi){
  3560. const haeufigkeit_t hi = uh1[oi]*wk, hi_f = uh1[oi]*wf;
  3561. for(int oj = 0; oj < groesse1; ++oj){
  3562. const haeufigkeit_t hj = uh1[oj]*wk, hj_f = uh1[oj]*wf;
  3563. const zaehl_t uhij = uh11[sym_index(oi, oj)];
  3564. ein_ein_k(korpus, oi, oj) =
  3565. (uhij-hj_f*uh1s[oi]-hi*uh1l[oj]+ls*hi*hj_f)*wfw;
  3566.  
  3567. if(oj > oi) continue;
  3568. ein_ein(oi, oj) +=
  3569. (uhij-hj*uh1l[oi]-hi*uh1l[oj]+ll*hi*hj)*w2;
  3570. ein_k_ein_k(korpus, oi, oj) =
  3571. (uhij-hj_f*uh1s[oi]-hi_f*uh1s[oj]+ss*hi_f*hj_f)*wf2;
  3572. }
  3573. }
  3574. for(int oij = 0; oij < groesse2; ++oij){
  3575. const haeufigkeit_t hij = uh2[oij]*wk;
  3576. for(int ok = 0; ok < groesse1; ++ok){
  3577. const haeufigkeit_t hk = uh1[ok]*wk, hk_f = uh1[ok]*wf;
  3578. const zaehl_t uhijk = uh21[index_tri21_flach(oij, ok)];
  3579. ein_bi(ok, oij) +=
  3580. (uhijk-hij*uh1l[ok]-hk*uh2l[oij]+ll*hij*hk)*w2;
  3581. ein_k_bi(korpus, ok, oij) =
  3582. (uhijk-hij*uh1l[ok]-hk_f*uh2s[oij]+ls*hij*hk_f)*wfw;
  3583. }
  3584. for(int okl = 0; okl <= oij; ++okl){
  3585. const haeufigkeit_t hkl = uh2[okl]*wk;
  3586. bi_bi(oij, okl) += (uh22[sym_index(oij, okl)]-hij*uh2l[okl]
  3587. -hkl*uh2l[oij]+ll*hij*hkl)*w2;
  3588. }
  3589. }
  3590. }
  3591.  
  3592. for(const auto& zh : unbekannt){
  3593. summe_unbekannt[zh.first] += mitfix_w*zh.second;
  3594. }
  3595. }
  3596.  
  3597. void
  3598. Haeufigkeit::statistik() const {
  3599. const Haeufigkeit& h = *this;
  3600. haeufigkeit_t htot = 0, h2tot = 0, doppelt = 0, gross = 0;
  3601. for(int i = 0; i < ntaste; ++i){
  3602. htot += h(i,0)+h(i,1);
  3603. gross += h(i,1);
  3604. for(int ei = 0; ei < nebene; ++ei){
  3605. for(int ej = 0; ej < nebene2; ++ej){
  3606. doppelt += h(i,ei,i,ej);
  3607. for(int j = 0; j < ntaste; ++j)
  3608. h2tot += h(i,ei,j,ej);
  3609. }
  3610. }
  3611. }
  3612.  
  3613. right(std::cout); fixed(std::cout);
  3614. std::cout << std::setprecision(3)
  3615. << SPRACHE("Zeichenh" strAe "ufigkeit klein/gross:\n\n",
  3616. "Symbol frequencies upper/lower case:\n\n");
  3617. for(int i = 0; i < ntaste; ++i){
  3618. if(i && i%4 == 0) std::cout << "\n";
  3619. std::cout << kodierung.txt(i, 0) << kodierung.txt(i, 1) << " "
  3620. << std::setw(6) << 100.*h(i,0)/htot << "/"
  3621. << std::setw(5) << 100.*h(i,1)/htot << " ";
  3622. }
  3623.  
  3624. std::cout << SPRACHE("\n\nGrossbuchstaben: ", "\n\nCapital letters: ")
  3625. << std::setw(5) << 100*gross/htot
  3626. << SPRACHE(" %\nDoppeltanschl" strAe "ge: ",
  3627. " %\nDouble strokes: ")
  3628. << std::setw(5) << 100*doppelt/h2tot << " %\n" << std::endl;
  3629. }
  3630.  
  3631. //--------------- src/Tastatur.cc ---------------
  3632. //#include "Tastatur.hh"
  3633.  
  3634. //#include "konstanten.hh"
  3635. //#include "utfhilfe.hh"
  3636. #include <cassert>
  3637. #include <cmath>
  3638. #include <iostream> // für Fehlerausgabe, besser wäre Exception
  3639.  
  3640. bool
  3641. Tastatur::istDaumen(finger_t i)
  3642. { return std::abs(i) <= finger_t::DaumenRechts; }
  3643.  
  3644. bool
  3645. Tastatur::istKleinfinger(finger_t i)
  3646. { return std::abs(i) == finger_t::KleinfingerRechts; }
  3647.  
  3648. const char*
  3649. Tastatur::kategorie_str(int kategorie){
  3650. const char* kategorie_s[] = {
  3651. SPRACHE("Handwechsel", "Hand alternation"),
  3652. SPRACHE("Kollision", "Same finger repetition"),
  3653. SPRACHE("Doppeltanschlag", "Double stroke"),
  3654. SPRACHE("Ausw" strAe "rts", "Outwards"),
  3655. SPRACHE("Einw" strAe "rts", "Inwards"),
  3656. SPRACHE("Mit undefiniertem Daumen", "With undefined thumb") };
  3657. return kategorie_s[kategorie];
  3658. }
  3659.  
  3660. std::string
  3661. Tastatur::kategorie_lang(int i, int j) const {
  3662. assert(i < ntaste+nshift && j < ntaste+nshift);
  3663. const int dzeile = std::abs(zeile(i)-zeile(j));
  3664. const int fi = finger(i), fj = finger(j);
  3665. std::string typ = kategorie_str(kategorie(i, j));
  3666. if(istHandwiederholung(i,j)){
  3667. if(std::abs(fi-fj) == 1)
  3668. typ += SPRACHE(", Nachbarfinger", ", adjacent finger");
  3669. if(dzeile == 1)
  3670. typ += SPRACHE(", Zeilensprung", ", row jump");
  3671. if(dzeile == 2)
  3672. typ += SPRACHE(", doppelter Zeilensprung", ", double row jump");
  3673. }
  3674. return typ;
  3675. }
  3676.  
  3677. int
  3678. Tastatur::spalte(int i) const {
  3679. assert(i < ntaste+nshift);
  3680. return spalten[i];
  3681. }
  3682.  
  3683. int
  3684. Tastatur::zeile(int i) const {
  3685. assert(i < ntaste+nshift);
  3686. return zeilen[i];
  3687. }
  3688.  
  3689. finger_t
  3690. Tastatur::finger(int i) const {
  3691. assert(i < ntaste+nshift);
  3692. return fingertab[i];
  3693. }
  3694.  
  3695. int
  3696. Tastatur::finger_index(int i) const {
  3697. assert(i < ntaste+nshift);
  3698. return fingerind[i];
  3699. }
  3700.  
  3701. int
  3702. Tastatur::shifttaste(int i) const {
  3703. assert(i < ntaste+nshift);
  3704. return shifttast[i];
  3705. }
  3706.  
  3707. int
  3708. Tastatur::shift_finger_index(int i) const {
  3709. assert(i < ntaste+nshift);
  3710. return sfingerind[i];
  3711. }
  3712.  
  3713. int
  3714. Tastatur::grundposition(int i) const {
  3715. assert(i < ntaste+nshift);
  3716. return grundpos[i];
  3717. }
  3718.  
  3719. int
  3720. Tastatur::taste(int z, int s) const {
  3721. if(z < 0 || z >= nzeile || s < 0 || s >= nspalte) return -1;
  3722. return tastennr[z][s];
  3723. }
  3724.  
  3725. const std::u32string&
  3726. Tastatur::name(int i) const {
  3727. assert(i < ntaste+nshift);
  3728. return namen[i];
  3729. }
  3730.  
  3731. int
  3732. Tastatur::taste(const std::u32string& n) const {
  3733. const auto i = namennr.find(n);
  3734. return i == namennr.end() ? -1 : i->second;
  3735. }
  3736.  
  3737. kategorie_t
  3738. Tastatur::kategorie(int i, int j) const {
  3739. assert(i < ntaste+nshift && j < ntaste+nshift);
  3740. return tastenkategorie[i][j];
  3741. }
  3742.  
  3743. const std::vector<int>&
  3744. Tastatur::benutzerkategorie(const std::vector<int>& i) const {
  3745. static const std::vector<int> leerervektor;
  3746. const auto p = benutzerkat.find(i);
  3747. return p == benutzerkat.end() ? leerervektor : p->second;
  3748. }
  3749.  
  3750. const std::string&
  3751. Tastatur::benutzerkategorie_name(int i) const
  3752. { return kategorie_liste[i]; }
  3753.  
  3754. bool
  3755. Tastatur::istHandwiederholung(int i, int j) const
  3756. { return kategorie(i,j) != kategorie_t::Handwechsel &&
  3757. kategorie(i,j) != kategorie_t::MitUndefDaumen; }
  3758.  
  3759. bool
  3760. Tastatur::istWippe(int i, int j, int k) const {
  3761. return (kategorie(i, j) == kategorie_t::Einwaerts &&
  3762. kategorie(j, k) == kategorie_t::Auswaerts)
  3763. || (kategorie(i, j) == kategorie_t::Auswaerts &&
  3764. kategorie(j, k) == kategorie_t::Einwaerts);
  3765. }
  3766.  
  3767. koordinate_t
  3768. Tastatur::tastenkoord(int i) const
  3769. { return koordinate_t{x[i], y[i]}; }
  3770.  
  3771. double
  3772. Tastatur::distanz(int i, int j) const {
  3773. const auto ki = tastenkoord(i), kj = tastenkoord(j);
  3774. return std::hypot(ki.x-kj.x, ki.y-kj.y);
  3775. }
  3776.  
  3777. bool
  3778. Tastatur::finger_fix(int i) const
  3779. { return fix[i]; }
  3780.  
  3781. int
  3782. Tastatur::nvariabel() const
  3783. { return nvar; }
  3784.  
  3785. double
  3786. Tastatur::lageaufwand(int i) const
  3787. {
  3788. assert(i < ntaste+nshift);
  3789. return aufwand[i];
  3790. }
  3791.  
  3792. Tastatur::Tastatur(const std::vector<taste_t>& tasten,
  3793. const std::unordered_set<std::u32string>& fixe_tasten){
  3794. nvar = ntaste-fixe_tasten.size();
  3795. if(nvar < 2){
  3796. std::cerr << SPRACHE("Alle Tasten sind fix belegt.",
  3797. "All keys have a fixed mapping.")
  3798. << std::endl;
  3799. exit(1);
  3800. }
  3801.  
  3802. for(auto& i : tastennr) for(auto& j : i) j = -1;
  3803.  
  3804. int gpos[nfinger+1];
  3805. for(auto& i: gpos) i = -1;
  3806. int ifix = nvar, ivar = 0;
  3807. for(int j = 0; j < ntaste+nshift; ++j){
  3808. const taste_t& t = tasten[j];
  3809. const bool istFix = fixe_tasten.find(t.name) != fixe_tasten.end();
  3810. const int i = istFix ? ifix++ : (j < ntaste ? ivar++ : j);
  3811. namen[i] = t.name;
  3812. namennr[t.name] = i;
  3813. spalten[i] = t.spalte;
  3814. zeilen[i] = t.zeile;
  3815. // Wenn meherere Tasten in derselben Spalte und Zeile sind "gewinnt"
  3816. // die erste nicht fixe.
  3817. if(tastennr[t.zeile][t.spalte] == -1){
  3818. tastennr[t.zeile][t.spalte] = i;
  3819. }else{
  3820. if(tastennr[t.zeile][t.spalte] >= nvar && !istFix)
  3821. tastennr[t.zeile][t.spalte] = i;
  3822. }
  3823.  
  3824. fingertab[i] = t.finger;
  3825. fingerind[i] = (t.finger < 0)
  3826. ? t.finger+5
  3827. : (t.finger > 0 ? t.finger+4 : nfinger);
  3828.  
  3829. if(t.istGrundposition) gpos[fingerind[i]] = i;
  3830. x[i] = t.x; y[i] = t.y;
  3831. aufwand[i] = t.aufwand;
  3832.  
  3833. shifttast[i] = t.seite ? ntaste : ntaste+(nshift-1);
  3834. }
  3835.  
  3836. for(int i = 0; i < ntaste+nshift; ++i){
  3837. sfingerind[i] = finger_index(shifttaste(i));
  3838. const int fi = finger_index(i);
  3839. grundpos[i] = gpos[fi] < 0 ? i : gpos[fi];
  3840. }
  3841.  
  3842. for(int i = 0; i < ntaste+nshift; ++i){
  3843. const int finger_i = finger(i);
  3844. for(int j = 0; j < ntaste+nshift; ++j){
  3845. const int finger_j = finger(j);
  3846.  
  3847. if(finger_i == finger_t::EinerDerDaumen ||
  3848. finger_j == finger_t::EinerDerDaumen){
  3849. tastenkategorie[i][j] = kategorie_t::MitUndefDaumen;
  3850. }else if((finger_i^finger_j) < 0){
  3851. tastenkategorie[i][j] = kategorie_t::Handwechsel;
  3852. }else{
  3853. if(spalte(i) == spalte(j) && zeile(i) == zeile(j)){
  3854. tastenkategorie[i][j] = kategorie_t::Doppeltanschlag;
  3855. }else if(finger_i == finger_j){
  3856. tastenkategorie[i][j] = kategorie_t::Kollision;
  3857. }else{
  3858. const bool auswaerts =
  3859. (std::abs(finger_j) > std::abs(finger_i));
  3860. tastenkategorie[i][j] = auswaerts
  3861. ? kategorie_t::Auswaerts
  3862. : kategorie_t::Einwaerts;
  3863. }
  3864. }
  3865. }
  3866. }
  3867.  
  3868. bool mehrere_shift = false;
  3869. for(auto& i : fix) i = true;
  3870. for(int i = 0; i < nvar; ++i){
  3871. fix[finger_index(i)] = false;
  3872. if(shift_finger_index(i) != shift_finger_index(0))
  3873. mehrere_shift = true;
  3874. }
  3875. if(mehrere_shift)
  3876. for(int i = 0; i < nvar; ++i) fix[shift_finger_index(i)] = false;
  3877. }
  3878.  
  3879. void
  3880. Tastatur::neue_kategorien(const std::vector<n_gramm_t>& benutzerkategorie){
  3881. for(const auto& i : benutzerkategorie){
  3882. const std::string n = utf32_in_ausgabe(i.name);
  3883. size_t p = 0;
  3884. for(; p < kategorie_liste.size(); ++p)
  3885. if(kategorie_liste[p] == n) break;
  3886. if(p == kategorie_liste.size())
  3887. kategorie_liste.push_back(n);
  3888. std::vector<int> ngramm = { i.t1, i.t2 };
  3889. if(i.t3 >= 0) ngramm.push_back(i.t3);
  3890. benutzerkat[ngramm].push_back(p);
  3891. }
  3892. }
  3893.  
  3894. //--------------- src/Kodierung.cc ---------------
  3895. //#include "Kodierung.hh"
  3896.  
  3897. //#include "Unicode.hh"
  3898. //#include "utfhilfe.hh"
  3899. #include <cassert>
  3900. #include <iomanip>
  3901. #include <iostream>
  3902. #include <sstream>
  3903.  
  3904. Kodierung::Kodierung(const std::vector<std::u32string>& klartext,
  3905. const std::vector<std::u32string>& ersatzstring,
  3906. const std::vector<std::u32string>& glyph,
  3907. char32_t platzhalter)
  3908. : platzhalterstr(utf32_in_ausgabe(platzhalter))
  3909. {
  3910. // DEL, dann kommen die hohen CTRLs, die können wir alle belegen.
  3911. unsigned char freiercode = 127;
  3912. if(klartext.size() != ntaste){
  3913. std::cerr << SPRACHE("Die Anzahl der der Zeichen ist ",
  3914. "The number of symbols is ")
  3915. << klartext.size()
  3916. << SPRACHE(
  3917. ", sollte jedoch gleich der Anzahl der Zeichentasten ",
  3918. ", but it should be equal to the number of symbol keys ")
  3919. << ntaste << SPRACHE(" sein.", ".") << std::endl;
  3920. exit(1);
  3921. }
  3922. for(int i = 0; i < ntaste; ++i){
  3923. for(int e = 0; e < nebene; ++e) chars[i][e] = 0;
  3924. psenc[i] = 0;
  3925. for(int e = 0; e < nebene; ++e){
  3926. const char32_t c =
  3927. klartext[i].length() < nebene ? klartext[i][0] : klartext[i][e];
  3928. if(c == platzhalter) continue;
  3929. chars[i][e] = c;
  3930. if(c < 256 &&
  3931. (psenc[i] == 0 || psenc[i] == Unicode::get().kleinbuchstabe(c))){
  3932. psenc[i] = c;
  3933. }
  3934. strings[i][e] = utf32_in_ausgabe(c);
  3935. if(invers.find(c) == invers.end()) invers[c] = std::make_pair(i, e);
  3936. }
  3937. for(size_t e = nebene; e < klartext[i].length(); ++e){
  3938. const char32_t extra = klartext[i][e];
  3939. if(psenc[i] == 0 && extra < 256) psenc[i] = extra;
  3940. if(invers.find(extra) == invers.end())
  3941. invers[extra] = std::make_pair(i, nebene-1);
  3942. }
  3943.  
  3944. glyphname[i] = utf32_in_ausgabe(glyph[i]);
  3945. if(psenc[i] == 0){
  3946. psenc[i] = freiercode;
  3947. if(freiercode == 9 || freiercode == 12){
  3948. freiercode += 2; // CR, LF übergehen
  3949. }else if(freiercode == 159){
  3950. // 160 ist nichtumbrechendes Leerzeichen, das überschreiben wir
  3951. // nicht. Fülle dann den CTRL-Bereich.
  3952. freiercode = 1;
  3953. }else ++freiercode;
  3954.  
  3955. if(glyphname[i].length() == 0){
  3956. const int codepoint =
  3957. (chars[i][0] == 0 ||
  3958. Unicode::get().kleinbuchstabe(chars[i][1]) == chars[i][0])
  3959. ? chars[i][1] : chars[i][0];
  3960. const int laenge = codepoint < 0x10000 ? 4 : 5;
  3961. const std::string u = codepoint < 0x10000 ? "uni" : "u";
  3962. std::ostringstream os;
  3963. os << u << std::setw(laenge) << std::setfill('0')
  3964. << std::uppercase << std::hex << codepoint;
  3965. glyphname[i] = os.str();
  3966. }
  3967. }
  3968. }
  3969.  
  3970. for(const auto& i : ersatzstring){
  3971. if(i.length() == 0) continue;
  3972. std::vector<std::pair<int, int>> ersatzliste;
  3973. const char32_t n = i[0];
  3974. std::u32string fehlt;
  3975. for(size_t j = 1; j < i.length(); ++j){
  3976. const auto p = position(i[j]);
  3977. if(p.first < 0){
  3978. const auto* pe = ersatz(i[j]);
  3979. if(pe){
  3980. for(const auto& pk : *pe) ersatzliste.push_back(pk);
  3981. }else fehlt.push_back(i[j]);
  3982. }else ersatzliste.push_back(p);
  3983. }
  3984. if(fehlt.size() == 0){
  3985. inversstr[n] = ersatzliste;
  3986. }else{
  3987. std::cerr << "Ersatz '" << utf32_in_ausgabe(i) << "': "
  3988. << SPRACHE("Warnung: Das Zeichen '",
  3989. "Warning: The character '")
  3990. << utf32_in_ausgabe(n)
  3991. << SPRACHE(
  3992. "' kann nicht ersetzt werden weil das/die Zeichen '",
  3993. "' cannot be substituted because the character(s) '")
  3994. << utf32_in_ausgabe(fehlt)
  3995. << SPRACHE("' nicht in der Belegung sind.",
  3996. "' are not in the layout.")
  3997. << std::endl;
  3998. }
  3999. }
  4000. }
  4001. bool
  4002. Kodierung::ist_platzhalter(int i, int e) const
  4003. { assert(i < ntaste && e < nebene); return strings[i][e].length() == 0; }
  4004.  
  4005. const std::string&
  4006. Kodierung::txt(int i, int e) const
  4007. { return ist_platzhalter(i,e) ? platzhalterstr : strings[i][e]; }
  4008.  
  4009. char32_t
  4010. Kodierung::uchar(int i, int e) const
  4011. { assert(i < ntaste && e < nebene); return chars[i][e];}
  4012.  
  4013. const std::string&
  4014. Kodierung::bevorzugt(int i) const {
  4015. assert(i < ntaste);
  4016. return strings[i][0].length() ? strings[i][0] : strings[i][1];
  4017. }
  4018. const std::string&
  4019. Kodierung::txt(int ie) const
  4020. { assert(ie < ntaste*nebene); return strings[ie/nebene][ie%nebene]; }
  4021.  
  4022. std::pair<int, int>
  4023. Kodierung::position(char32_t z) const {
  4024. const auto i = invers.find(z);
  4025. if(i == invers.end()) return std::make_pair(-1, -1);
  4026. return i->second;
  4027. }
  4028.  
  4029. const std::vector<std::pair<int,int>>*
  4030. Kodierung::ersatz(char32_t z) const {
  4031. const auto i = inversstr.find(z);
  4032. return i == inversstr.end() ? nullptr : &i->second;
  4033. }
  4034.  
  4035. int
  4036. Kodierung::psencoding(int i) const
  4037. { assert(i < ntaste); return psenc[i]; }
  4038.  
  4039. std::string
  4040. Kodierung::psencstr(int i) const {
  4041. std::string str;
  4042. if(psenc[i] == '(' || psenc[i] == ')' || psenc[i] == '\\')
  4043. str.push_back('\\');
  4044. str.push_back(psenc[i]);
  4045. return str;
  4046. }
  4047.  
  4048. const std::string&
  4049. Kodierung::psglyphname(int i) const
  4050. { assert(i < ntaste); return glyphname[i]; }
  4051.  
  4052. //--------------- src/schreibe_belegung.cc ---------------
  4053. //#include "schreibe_belegung.hh"
  4054.  
  4055. //#include "Aufwandstabelle.hh"
  4056. //#include "Haeufigkeit.hh"
  4057. //#include "Kodierung.hh"
  4058. //#include "Statistik.hh"
  4059. //#include "Tastatur.hh"
  4060. //#include "konstanten.hh"
  4061. //#include "utfhilfe.hh"
  4062. #include <cassert>
  4063. #include <cmath>
  4064. #include <iomanip>
  4065. #include <iostream>
  4066. #include <vector>
  4067.  
  4068. #define SP1 std::setprecision(1)
  4069. #define SP2 std::setprecision(2)
  4070. #define SP3 std::setprecision(3)
  4071. #define SP4 std::setprecision(4)
  4072. #define SW2 std::setw(2)
  4073. #define SW4 std::setw(4)
  4074. #define SW5 std::setw(5)
  4075. #define SW6 std::setw(6)
  4076. #define SW7 std::setw(7)
  4077. #define SW8 std::setw(8)
  4078.  
  4079. namespace {
  4080.  
  4081. std::string
  4082. decodiere(const std::string& seq, const Kodierung& kodierung)
  4083. {
  4084. std::string resultat;
  4085. for(const auto j : seq) resultat += kodierung.txt(j);
  4086. return resultat;
  4087. }
  4088.  
  4089. void
  4090. handeinsaetze(const belegung_t b, const Tastatur& tastatur,
  4091. const Kodierung& kodierung,
  4092. const std::unordered_map<std::string, haeufigkeit_t>& wortliste,
  4093. const akkumuations_t limit)
  4094. {
  4095. bool seite[ntaste];
  4096. for(int i = 0; i < ntaste; ++i) seite[b[i]] = (tastatur.finger(i) < 0);
  4097.  
  4098. std::unordered_map<std::string, akkumuations_t> handeinsatz;
  4099. akkumuations_t summe = 0, summe2 = 0, tot = 0, stot[2] = { 0, 0 };
  4100. std::vector<akkumuations_t> prolaenge[2];
  4101. for(auto& i : wortliste){
  4102. const std::string& wort = i.first;
  4103. const haeufigkeit_t h = i.second;
  4104.  
  4105. bool warseite = seite[wort[0]/nebene];
  4106. size_t start = 0;
  4107. for(size_t j = 1; j <= wort.size(); ++j){
  4108. if(j == wort.size() || warseite != seite[wort[j]/nebene]){
  4109. const size_t len = j-start;
  4110.  
  4111. handeinsatz[wort.substr(start, len)] += h;
  4112.  
  4113. stot[warseite] += h;
  4114. while(prolaenge[0].size() <= len){
  4115. prolaenge[0].push_back(0);
  4116. prolaenge[1].push_back(0);
  4117. }
  4118. assert(prolaenge[0].size() == prolaenge[1].size());
  4119. prolaenge[warseite][len] += h;
  4120.  
  4121. summe += len*h;
  4122. summe2 += len*len*h;
  4123. tot += h;
  4124.  
  4125. warseite = !warseite;
  4126. start = j;
  4127. }
  4128. }
  4129. }
  4130.  
  4131. std::multimap<akkumuations_t, std::string> sortiert;
  4132. size_t laengster = 0;
  4133. akkumuations_t hlaengster = 0;
  4134. std::string tlaengster;
  4135. for(const auto& i : handeinsatz){
  4136. sortiert.insert(std::make_pair(i.second, i.first));
  4137. size_t len = i.first.size();
  4138. if(len > laengster || (len == laengster && hlaengster < i.second)){
  4139. laengster = len;
  4140. tlaengster = i.first;
  4141. hlaengster = i.second;
  4142. }
  4143. }
  4144.  
  4145. akkumuations_t mittel = summe/tot;
  4146. std::cout << SPRACHE("\nInsgesamt ", "\nIn total ") << sortiert.size()
  4147. << SPRACHE(
  4148. " verschiedene Handeins" strAe "tze, mittlere L" strAe "nge ",
  4149. " different one-handed sequences, average length ")
  4150. << SP3 << mittel
  4151. << SPRACHE("\n Standardabweichung ",
  4152. "\n standard deviation ")
  4153. << SP3 << std::sqrt(summe2/tot-mittel*mittel)
  4154. << SPRACHE(", maximale L" strAe "nge ",
  4155. ", maximum length ") << laengster
  4156. << SPRACHE(" f" strUe "r ",
  4157. " for ") << decodiere(tlaengster, kodierung)
  4158. << SPRACHE("\n\n# % links % summiert % rechts % summiert "
  4159. "% beide % summiert\n",
  4160. "\n\n# % left % cumulative % right % cumulative "
  4161. "% both % cumulative\n");
  4162.  
  4163. akkumuations_t procum[2] = { 0, 0 };
  4164. for(size_t i = 1; i+1 < prolaenge[0].size(); ++i){
  4165. procum[0] += prolaenge[0][i];
  4166. procum[1] += prolaenge[1][i];
  4167. std::cout << SW2 << i
  4168. << SP4 << SW8 << 100*(prolaenge[1][i]/stot[1]) << " ("
  4169. << SP4 << SW8 << 100*(procum[1]/stot[1]) << ") "
  4170. << SP4 << SW8 << 100*(prolaenge[0][i]/stot[0]) << " ("
  4171. << SP4 << SW8 << 100*(procum[0]/stot[0]) << ") "
  4172. << SP4 << SW8 << 100*((prolaenge[0][i]+prolaenge[1][i])/tot)
  4173. << " ("
  4174. << SP4 << SW8 << 100*((procum[0]+procum[1])/tot) << ")\n";
  4175. }
  4176.  
  4177. if(limit > 0){
  4178. std::cout << SPRACHE("\n# % % summiert\n",
  4179. "\n# % % cumulative\n");
  4180. akkumuations_t sum = 0;
  4181. int n = 0;
  4182. for(auto i = sortiert.crbegin(); i != sortiert.crend(); ++i){
  4183. if(sum > limit) break;
  4184. n++;
  4185. const akkumuations_t h = 100*i->first/tot;
  4186. sum += h;
  4187. std::cout << SW4 << n
  4188. << SP3 << SW7 << h << " ("
  4189. << SP3 << SW7 << sum << ") "
  4190. << decodiere(i->second, kodierung) << "\n";
  4191. }
  4192. }
  4193. }
  4194.  
  4195. }
  4196.  
  4197. void schreibe_belegung(const belegung_t b, const Tastatur& tastatur,
  4198. const Kodierung& kodierung, const Haeufigkeit& h,
  4199. const Aufwandstabelle& a, const akkumuations_t A,
  4200. const std::u32string& name,
  4201. const double ngrammakkumlimit[3],
  4202. const std::unordered_map<std::string, haeufigkeit_t>&
  4203. wortliste,
  4204. const akkumuations_t handeinsatzlimit,
  4205. bool als_fixeszeichen)
  4206. {
  4207. std::string str[nzeile];
  4208. for(int z = 0; z < nzeile; ++z){
  4209. for(int s = 0; s < nspalte; ++s){
  4210. const int t = tastatur.taste(z, s);
  4211. str[z] += (t < 0 || t >= ntaste)
  4212. ? " " : kodierung.bevorzugt(b[t]);
  4213. }
  4214. }
  4215.  
  4216. Statistik S(b, tastatur, kodierung, h, a, ngrammakkumlimit);
  4217.  
  4218. const std::string lspalte(nspalte, ' ');
  4219.  
  4220. std::cout << utf32_in_ausgabe(name);
  4221. for(int i = name.length(); i < nspalte+1; ++i) std::cout << " ";
  4222. right(std::cout); fixed(std::cout);
  4223.  
  4224. std::cout << SP3 << SW7 << 100*A
  4225. << SPRACHE(" Gesamtaufwand "," total effort ")
  4226. << SW7 << 100*S.aeinzel
  4227. << SPRACHE(" Lageaufwand links rechts\n",
  4228. " positional effort left right\n");
  4229. std::cout << str[0] << " "
  4230. << SP3 << SW7 << S.hk[kategorie_t::Kollision]
  4231. << SPRACHE(" Kollisionen ", " same finger rp ")
  4232. << SW7 << S.hs[kategorie_t::Kollision]
  4233. << SPRACHE(" Shift-Kollisionen ob ", " shift same finger top ")
  4234. << SP1 << SW4 << S.hpos[0][zeilen_t::Obere_Zeile] << " "
  4235. << SW4 << S.hpos[1][zeilen_t::Obere_Zeile] << "\n";
  4236. std::cout << str[1] << " "
  4237. << SP3 << SW7 << S.hk[kategorie_t::Handwechsel]
  4238. << SPRACHE(" Handwechsel ", " hand alternat. ")
  4239. << SW7 << S.hs[kategorie_t::Handwechsel]
  4240. << SPRACHE(" Shift-Handwechsel mi ", " shift hand alter. mid ")
  4241. << SP1 << SW4 << S.hpos[0][zeilen_t::Mittelzeile] << " "
  4242. << SW4 << S.hpos[1][zeilen_t::Mittelzeile] << "\n";
  4243. std::cout << str[2] << " "
  4244. << SP3 << SW7
  4245. << S.hk[kategorie_t::Einwaerts]/S.hk[kategorie_t::Auswaerts]
  4246. << SPRACHE(" Ein-/Ausw" strAe "rts ", " inward/outward ")
  4247. << SP3 << SW7 << (S.hk[kategorie_t::Einwaerts]+
  4248. S.hk[kategorie_t::Auswaerts])
  4249. << SPRACHE(" Ein- oder ausw" strAe "rts un ",
  4250. " inward or outward bot ")
  4251. << SP1 << SW4 << S.hpos[0][zeilen_t::Untere_Zeile] << " "
  4252. << SW4 << S.hpos[1][zeilen_t::Untere_Zeile] << "\n";
  4253. std::cout << str[3] << " " << SP3 << SW7 << S.hnachbar
  4254. << SPRACHE(" benachbart ", " adjacent ")
  4255. // Die Normierung von hnachbar ist fragwürdig.
  4256. << SW7 << S.hsnachbar
  4257. << SPRACHE(" Shift-benachbart sum", " shift adjacent sum")
  4258. << SP1 << SW5 << S.hlinks << SW5 << S.hrechts << "\n";
  4259. if(h.mit_trigrammen()){
  4260. std::cout << str[4] << " " << SP3 << SW7 << S.hkeinhw
  4261. << SPRACHE(" kein Handwechs.", " no hand altern.")
  4262. << SP3 << SW7 << S.hdoppelhw
  4263. << SPRACHE(" zwei Handwechsel", " two hand altern.")
  4264. << "\n " << lspalte
  4265. << SP3 << SW7 << S.hwippe
  4266. << SPRACHE(" Wippe ", " seesaw ")
  4267. << SP3 << SW7 << S.hi2[kategorie_t::Kollision]
  4268. << SPRACHE(" IndirKollision", " indir same finger")
  4269. << "\n";
  4270. str[4] = lspalte;
  4271. }
  4272.  
  4273. for(const auto& i : S.hk_benutzer){
  4274. std::cout << str[4] << " " << SP3 << SW7 << i.second << " "
  4275. << tastatur.benutzerkategorie_name(i.first) << "\n";
  4276. str[4] = lspalte;
  4277. }
  4278. for(const auto& i : S.hs_benutzer){
  4279. std::cout << str[4] << " " << SP3 << SW7 << i.second << " Shift-"
  4280. << tastatur.benutzerkategorie_name(i.first) << "\n";
  4281. str[4] = lspalte;
  4282. }
  4283. for(const auto& i : S.ht_benutzer){
  4284. std::cout << str[4] << " " << SP3 << SW7 << i.second << " "
  4285. << tastatur.benutzerkategorie_name(i.first) << "\n";
  4286. str[4] = lspalte;
  4287. }
  4288.  
  4289. std::cout << str[4];
  4290. for(int i = 0; i < nfinger; ++i){
  4291. if(S.mitfinger[i])
  4292. std::cout << " " << SW4 << SP1 << S.hfinger[i];
  4293. else
  4294. std::cout << " --.-";
  4295. }
  4296. std::cout << " Sh" << SW5 << S.hslinks << SW5 << S.hsrechts << "\n";
  4297.  
  4298. if(ngrammakkumlimit[0] >= 0){
  4299. std::cout << SPRACHE(" Kollision/Fi. ", " same fing/fi. ");
  4300. for(int i = 0; i < nfinger; ++i){
  4301. if(S.mitfinger[i])
  4302. std::cout << " " << SP2 << SW4 << S.hkollision1[i];
  4303. else
  4304. std::cout << " ";
  4305. }
  4306. std::cout << " Sh" << SP2;
  4307. for(int s = 0; s < nshift; ++s) std::cout << SW5 << S.hskollision1[s];
  4308.  
  4309. std::cout << SPRACHE("\n \" \" Sprung>=2 ", "\n \" \" jump >= 2 ");
  4310. for(int i = 0; i < nfinger; ++i){
  4311. if(S.mitfinger[i])
  4312. std::cout << SP2 << SW5 << S.hkollision2[i];
  4313. else
  4314. std::cout << " ";
  4315. }
  4316. std::cout << " Sh" << SP2;
  4317. for(int s = 0; s < nshift; ++s) std::cout << SW5 << S.hskollision2[s];
  4318.  
  4319. std::cout << SPRACHE("\n benachbart/F.paar", "\n adjacent/fin.pair");
  4320. for(int i = 0; i < nfinger-1; ++i){
  4321. if(S.mitfinger[i] && S.mitfinger[i+1])
  4322. std::cout << SP2 << SW5 << S.hnachbar1[i];
  4323. else
  4324. std::cout << " ";
  4325. }
  4326. std::cout << " Sh" << SP2;
  4327. for(int s = 0; s < nshift; ++s) std::cout << SW5 << S.hsnachbar1[s];
  4328.  
  4329. std::cout << SPRACHE("\n \" \" Ze.sprung>=2 ",
  4330. "\n \" \" row jump >=2 ");
  4331. for(int i = 0; i < nfinger-1; ++i){
  4332. if(S.mitfinger[i] && S.mitfinger[i+1])
  4333. std::cout << SP2 << SW5 << S.hnachbar2[i];
  4334. else
  4335. std::cout << " ";
  4336. }
  4337. std::cout << " Sh" << SP2;
  4338. for(int s = 0; s < nshift; ++s) std::cout << SW5 << S.hsnachbar2[s];
  4339. std::cout << "\n";
  4340. }
  4341.  
  4342. const haeufigkeit_t htot[3] = { S.h2tot, S.hs2tot, S.h3tot };
  4343. for(int t = 0; t < 3; ++t){
  4344. if(ngrammakkumlimit[t] <= 0) continue;
  4345. for(int s = 0; s < 2; ++s){
  4346. const auto& hwb = S.ngramm[t][s];
  4347. if(hwb.size() == 0) continue;
  4348. double sum = 0;
  4349. std::cout << SPRACHE("\n % alle % ", "\n % all % ")
  4350. << (t < 2
  4351. ? (s ? SPRACHE("rechts","right ")
  4352. : SPRACHE("links "," left "))
  4353. : (s ? SPRACHE("2 H.w.","2 h.a.")
  4354. : SPRACHE("0 H.w.","0 h.a.")))
  4355. << SPRACHE(" summiert\n", " cumulative\n");
  4356. for(auto i = hwb.crbegin();
  4357. i != hwb.crend() && sum < S.hrel[t][s]*ngrammakkumlimit[t]; ++i){
  4358. const double aa = 100*i->first;
  4359. sum += i->first;
  4360. std::cout << SP3 << SW7 << aa/htot[t] << " "
  4361. << SP3 << SW7 << aa/S.hrel[t][s]
  4362. << " ("<< SP3 << SW7 << 100*sum/S.hrel[t][s]
  4363. <<"): " << i->second << "\n";
  4364. }
  4365. }
  4366. }
  4367.  
  4368. if(handeinsatzlimit >= 0 && wortliste.size())
  4369. handeinsaetze(b, tastatur, kodierung, wortliste, handeinsatzlimit);
  4370. std::cout << std::endl;
  4371.  
  4372. if(als_fixeszeichen){
  4373. const std::string einfach = "'", doppelt = "\"";
  4374.  
  4375. for(int i = 0; i < tastatur.nvariabel(); ++i){
  4376. const std::string z0 = kodierung.txt(b[i], 0);
  4377. const std::string z1 = kodierung.txt(b[i], 1);
  4378. const std::string anf = z0 != einfach && z1 != einfach
  4379. ? einfach
  4380. : (z0 != doppelt && z1 != doppelt ? doppelt : "!");
  4381. std::cout << "FixesZeichen " << utf32_in_ausgabe(tastatur.name(i))
  4382. << " " << anf << z0 << z1 << anf << std::endl;
  4383. }
  4384. std::cout << std::endl;
  4385. }
  4386. }
  4387.  
  4388. void schreibe_belegung(const belegung_t b, double A, int nv,
  4389. const Kodierung& kodierung, const std::u32string* name)
  4390. {
  4391. constexpr int zbreite = 9;
  4392. char bewertung[zbreite+ntaste*4+2];
  4393. sprintf(bewertung, "%#8.7g", 100*A);
  4394. char* s = bewertung+(zbreite-1);
  4395. *s++ = ' ';
  4396. for(int i = 0; i < nv; ++i){
  4397. const std::string& z = kodierung.bevorzugt(b[i]);
  4398. for(const char* j = z.c_str(); *j;) *s++ = *j++;
  4399. }
  4400. if(name){
  4401. *s = 0;
  4402. std::cout << bewertung;
  4403. std::cout << " " << utf32_in_ausgabe(*name) << std::endl;
  4404. }else{
  4405. *s++ = '\n'; *s = 0;
  4406. std::cout << bewertung;
  4407. }
  4408. }
  4409.  
  4410. void
  4411. schreibe_zyklen(const belegung_t b1, const belegung_t b2,
  4412. const Kodierung& kodierung)
  4413. {
  4414. belegung_t zyklus;
  4415.  
  4416. for(int i = 0; i < ntaste; ++i){
  4417. const unsigned char z1 = b1[i];
  4418. zyklus[z1] = b2[i];
  4419. };
  4420.  
  4421. for(int i = 0; i < ntaste; ++i){
  4422. const unsigned char z1 = zyklus[i];
  4423. if(z1 == ntaste) continue; // Wurde schon abgehandelt.
  4424. if(z1 == i) continue; // triviale Zyklen ignorieren.
  4425. std::cout << " ";
  4426. unsigned char z = z1;
  4427. do{
  4428. const std::string& txt = kodierung.bevorzugt(z);
  4429. std::cout << (txt == strNBS ? "_" : txt.c_str());
  4430. const unsigned char z2 = zyklus[z];
  4431. zyklus[z] = ntaste;
  4432. z = z2;
  4433. }while(z != z1);
  4434. }
  4435. }
  4436.  
  4437. //--------------- src/vollkorpus.cc ---------------
  4438. //#include "vollkorpus.hh"
  4439.  
  4440. //#include "trennen.hh"
  4441. //#include "utfhilfe.hh"
  4442. #include <fstream>
  4443.  
  4444. void lies_vollkorpus(const std::string& name, const std::string* trennmuster,
  4445. std::unordered_map<std::u32string, zaehl_t>& wl,
  4446. std::unordered_map<uint64_t, zaehl_t> uh[3])
  4447. {
  4448. bool utf8 = true, geaendert = false;
  4449. do{
  4450. for(size_t i = 0; i < 3; ++i) uh[i].clear();
  4451. wl.clear();
  4452.  
  4453. std::unique_ptr<Naechstes_zeichen> nz
  4454. (trennmuster ? new hole_mit_trennung(name, *trennmuster, utf8)
  4455. : new Naechstes_zeichen(name, utf8));
  4456.  
  4457. std::u32string w; w.reserve(20);
  4458. uint64_t z1 = 0, z2 = 0;
  4459. while(const char32_t c = nz->get()){
  4460. if(c < U' ' || c == U'\u00ad'){
  4461. if(w.length()) ++wl[w];
  4462. w.clear();
  4463. z1 = z2 = 0;
  4464. continue;
  4465. }else if(c == U' '){
  4466. if(w.length()) ++wl[w];
  4467. w.clear();
  4468. }else w += c;
  4469.  
  4470. const uint64_t z3 = utf_maske & c;
  4471. ++uh[0][z3];
  4472. if(z2){
  4473. z2 = (z2<<21) | z3;
  4474. ++uh[1][z2];
  4475. if(z1) ++uh[2][(z1<<21) | z3];
  4476. z1 = z2;
  4477. }
  4478. z2 = z3;
  4479. }
  4480. if(w.length()) ++wl[w];
  4481.  
  4482. geaendert = nz->encoding_geaendert();
  4483. utf8 = false;
  4484. }while(geaendert);
  4485. }
  4486.  
  4487. //--------------- src/wortliste.cc ---------------
  4488. //#include "wortliste.hh"
  4489.  
  4490. //#include "Eingabestream.hh"
  4491. //#include "Haeufigkeit.hh"
  4492. //#include "Kodierung.hh"
  4493. //#include "utfhilfe.hh"
  4494. #include <iostream>
  4495.  
  4496. namespace {
  4497.  
  4498. void wort_in_wortliste(
  4499. const std::string wort, unsigned h,
  4500. std::unordered_map<std::string, haeufigkeit_t>& wortliste)
  4501. {
  4502. if(!wort.size()) return;
  4503. const auto i = wortliste.find(wort);
  4504. if(i == wortliste.end())
  4505. wortliste[wort] = h;
  4506. else i->second += h;
  4507. }
  4508.  
  4509. }
  4510.  
  4511. void lies_wortliste(const std::string& name,
  4512. std::unordered_map<std::u32string, zaehl_t>& wl,
  4513. bool muss_existieren){
  4514. bool utf8 = true, geaendert = false;
  4515. do{
  4516. wl.clear();
  4517. Eingabestream f(name, utf8, muss_existieren);
  4518. while(f.echte_neuezeile()){
  4519. const zaehl_t h = hole_zahl(f, 0, 1e15);
  4520. const bool zwischen = f.ist_zwischenraum();
  4521. const size_t rest = f.restzeichen();
  4522. if(!(zwischen && rest > 1)){
  4523. std::cerr << SPRACHE("Nach der Zahl werden ein Leerzeichen und "
  4524. "mindestens ein weiteres Zeichen erwartet.",
  4525. "After the number, one space character and at "
  4526. "least one more character are expected.")
  4527. << std::endl;
  4528. f.fehler();
  4529. }
  4530.  
  4531. f.uebergehen();
  4532. std::u32string idx; idx.reserve(rest-1);
  4533. for(size_t i = 1; i < rest; ++i)
  4534. idx.push_back(f.lies_in_zeile());
  4535. wl[idx] += h;
  4536. }
  4537. geaendert = f.encoding_geaendert();
  4538. utf8 = false;
  4539. }while(geaendert);
  4540. }
  4541.  
  4542. void lies_wortliste(const std::string name,
  4543. std::unordered_map<std::string, haeufigkeit_t>& wortliste,
  4544. const Kodierung& kodierung)
  4545. {
  4546. std::unordered_map<std::u32string, zaehl_t> wl;
  4547. lies_wortliste(name, wl, true);
  4548. for(const auto& i : wl){
  4549. const haeufigkeit_t h = i.second;
  4550. std::string konvertiert;
  4551. for(const char32_t z : i.first){
  4552. const bool zwischenraum = ist_zwischenraum(z);
  4553. const auto c = kodierung.position(z);
  4554. if(c.first < 0 || zwischenraum){
  4555. wort_in_wortliste(konvertiert, h, wortliste);
  4556. konvertiert.erase();
  4557. }else konvertiert
  4558. .push_back(Haeufigkeit::index_ein_flach(c.first, c.second));
  4559. }
  4560. wort_in_wortliste(konvertiert, h, wortliste);
  4561. }
  4562. }
  4563.  
  4564. //--------------- src/Aufwandstabelle.cc ---------------
  4565. //#include "Aufwandstabelle.hh"
  4566.  
  4567. //#include "Kodierung.hh"
  4568. //#include "Konfiguration.hh"
  4569. //#include "Tastatur.hh"
  4570. //#include "utfhilfe.hh"
  4571. #include <iomanip>
  4572. #include <iostream>
  4573. #include <string>
  4574.  
  4575. Aufwandstabelle::
  4576. Aufwandstabelle(bool mittrigrammen, const Tastatur& tast,
  4577. const Konfiguration& A)
  4578. : aunbekannt(A.unbekannt()), mit_trigrammen(mittrigrammen), tastatur(tast)
  4579. {
  4580. // werden Trigramme mit berücksichtigt, steigt der Gesamtaufwand. Daher
  4581. // sollte das Gewicht für die Fingerbelastung auch entsprechend grösser
  4582. // gewählt werden:
  4583. const double mult_mf_tri = 1+A.indirekt(1e100);
  4584. double fh_tot = 0;
  4585. // Wenn einem Finger nur fest belegte Tasten zugeordnet sind legen wir für
  4586. // ihn keine Zielhäufigkeit fest.
  4587. for(int i = 0; i < nfinger; ++i)
  4588. if(!tastatur.finger_fix(i)) fh_tot += A.zielhaeufigkeit(i);
  4589. for(int i = 0; i < nfinger; ++i){
  4590. finger_zielhaeufigkeit[i] = A.zielhaeufigkeit(i)/fh_tot;
  4591. multfinger[i] = mit_trigrammen
  4592. ? mult_mf_tri*A.multfinger(i) : A.multfinger(i);
  4593. if(tastatur.finger_fix(i)) finger_zielhaeufigkeit[i] = multfinger[i] = 0;
  4594. }
  4595.  
  4596. for(int i = 0; i < ntaste; ++i){
  4597. // Basisaufwand für Kleinbuchstaben:
  4598. a1[i][0] = tastatur.lageaufwand(i);
  4599. // Für Grossbuchstaben muss zusätzlich noch Shift gedrückt werden:
  4600. const int shift_i = tastatur.shifttaste(i);
  4601. a1[i][1] = a1[i][0]+tastatur.lageaufwand(tastatur.shifttaste(i))
  4602. +A.bigrammaufwand(shift_i, i, tastatur);
  4603. }
  4604.  
  4605. // Wir bewerten n-Gramme bis zu drei Tasten, dabei wird Shift als Taste
  4606. // mitgezählt. Deshalb fallen Tasten-n-Gramme nicht mit Zeichen-n-Grammen
  4607. // zusammen, und die Zählung wird verwickelt. Shift ist zudem speziell: Zum
  4608. // einen, weil die Shifttaste durch die zu shiftende Taste festgelegt ist,
  4609. // zum anderen, weil Shift vor der zu shiftenden Taste angeschlagen und
  4610. // gehalten wird, bis die zu shiftende Taste angeschlagen wurde.
  4611. //
  4612. // Schauen wir uns die Eingabe von drei Zeichen an. Für jedes Zeichen muss
  4613. // eine Zeichentaste (b) und gegebenenfalls Shift (s) angeschlagen werden.
  4614. // Es gibt also acht Möglichkeiten, die man in die darin enthaltenen
  4615. // Trigramme aufspalten kann:
  4616. //
  4617. // T1: b b b = bbb
  4618. // T2: s-b b b = sbb + bbb
  4619. // T3: b s-b b = bsb + sbb
  4620. // T4: s-b s-b b = sbs + bsb + sbb
  4621. // T5: b b s-b = bbs + bsb
  4622. // T6: s-b b s-b = sbb + bbs + bsb
  4623. // T7: b s-b s-b = bsb + sbs + bsb
  4624. // T8: s-b s-b s-b = sbs + bsb + sbs + bsb
  4625. //
  4626. // Nur für bbb (in T1 und T2) und bbs (in T5 und T6) müssen wir tatsächlich
  4627. // die Häufigkeiten von Zeichentrigrammen betrachten. Für sbb, bsb und sbs
  4628. // genügt die Betrachtung von Zeichenbigrammen. Wir handeln sie daher mit
  4629. // den Bigrammen ab. Für Zeichenbigramme gibt es vier Möglichkeiten, und
  4630. // wir können sie in die enthaltenen Tastenbi- und trigramme aufteilen:
  4631. //
  4632. // B1: b b = bb
  4633. // B2: s-b b = sbb + bb
  4634. // B3: b s-b = bsb + bs
  4635. // B4: s-b s-b = sbs + bsb + bs
  4636. //
  4637. // wobei die Bigramme sb bereits weggelassen sind, denn das sind
  4638. // verkappte 1-Gramme (Grossbuchstaben).
  4639. //
  4640. // Wenn wir die Zeichentrigrammhäufigkeiten für Trigramme der Form bbb
  4641. // und bbs genauer betrachten sehen wir:
  4642. // - Es spielt keine Rolle, ob der erste Buchstabe gross oder klein
  4643. // ist, denn ein allfälliges Shift liegt vor (also ausserhalb) des
  4644. // Trigramms. Wir können die entsprechenden Häufigkeiten summieren.
  4645. // - Der zweite Buchstabe ist immer klein.
  4646. // - Für bbb ist der dritte Buchstabe klein, für bbs gross.
  4647. //
  4648. // Die Zeichenbigrammhäufigkeiten haben wir nach den vier
  4649. // Klein/Gross-Kombinationen aufgespalten.
  4650. //
  4651. // Für die Bewertung ist noch zu bemerken, dass sbb und sbs nicht mit bbb,
  4652. // bbs und bsb gleichzusetzen sind, weil das s am Anfang gehalten werden
  4653. // muss, bis das folgende b getippt ist. Wir nennen nennen Tastentrigramme
  4654. // der Art sbb und sbs «Shift-Bigramme».
  4655.  
  4656. // Fülle die Bigrammtabellen.
  4657. for(int i = 0; i < ntaste; ++i){
  4658. const int shift_i = tastatur.shifttaste(i);
  4659. for(int j = 0; j < ntaste; ++j){
  4660. // Basisbewertung: Bigramme zwischen normalen Tasten
  4661. a2[i][j][0][0] = A.bigrammaufwand(i, j, tastatur);// bb
  4662.  
  4663. // Aufwand, falls das erste Zeichen im Bigramm zusammen mit Shift
  4664. // gedrückt wird.
  4665. const double sa1 = A.bigrammaufwand(shift_i, j, tastatur);
  4666. const double sf1 = A.shiftindirekt(sa1);
  4667. a2[i][j][1][0] = sf1*sa1 // sbb
  4668. +A.bigrammaufwand(i, j, tastatur); // bb
  4669.  
  4670. // Aufwand, falls das zweite Zeichen im Bigramm zusammen mit Shift
  4671. // gedrückt wird.
  4672. #ifndef OHNE2SHIFT
  4673. const int shift_j = tastatur.shifttaste(j);
  4674. a2[i][j][0][1] =
  4675. A.trigrammaufwand(i, shift_j, j, tastatur) // bsb
  4676. +A.bigrammaufwand(i, shift_j, tastatur); // bs
  4677.  
  4678. // Aufwand wenn beide Zeichen mit Shift gedrückt werden.
  4679. const double sa12 = A.bigrammaufwand(shift_i, shift_j, tastatur);
  4680. const double sf12 = A.shiftindirekt(sa12);
  4681. a2[i][j][1][1] = sa12*sf12 // sbs
  4682. +A.trigrammaufwand(i, shift_j, j, tastatur) // bsb
  4683. +A.bigrammaufwand(i, shift_j, tastatur); // bs
  4684. #endif
  4685. }
  4686. }
  4687.  
  4688. bool mit_verwechslungspotenzial = false;
  4689. mit_vorlieben = mit_aehnlichkeit = false;
  4690. for(int i = 0; i < ntaste; ++i){
  4691. for(int j = 0; j < ntaste; ++j){
  4692. va2[i][j] = A.verwechslungspotenzial(i, j, tastatur);
  4693. if(va2[i][j] != 0) mit_verwechslungspotenzial = true;
  4694. ae[i][j] = A.aehnlichkeit(i, j);
  4695. if(ae[i][j] != 0) mit_aehnlichkeit = true;
  4696. vl[i][j] = A.vorliebe(i, j);
  4697. if(vl[i][j] != 0) mit_vorlieben = true;
  4698. }
  4699. }
  4700. mit_aehnlichkeit &= mit_verwechslungspotenzial;
  4701. vl_knick = -A.vorliebenknick();
  4702.  
  4703. if(!mit_trigrammen) return;
  4704. // Fülle die Trigrammtabellen.
  4705. for(int k = 0; k < ntaste; ++k){
  4706. const int shift_k = tastatur.shifttaste(k);
  4707. for(int i = 0; i < ntaste; ++i){
  4708. for(int j = 0; j < ntaste; ++j){
  4709. a3[i][j][k][0] =
  4710. A.trigrammaufwand(i,j,k,tastatur); // bbb
  4711. a3[i][j][k][1] =
  4712. A.trigrammaufwand(i,j,shift_k,tastatur); // bbs
  4713. }
  4714. }
  4715. }
  4716. }
  4717.  
  4718. void
  4719. Aufwandstabelle::
  4720. anzeigen(const Kodierung& kodierung, const Konfiguration& A) const
  4721. {
  4722. // Keine Übersetzung ins Englische, die Wörter hier sind Schlüsselwörter.
  4723. const std::string einfachesanfuehrungszeichen = "'";
  4724. for(int i = 0; i < ntaste+nshift; ++i){
  4725. const std::string ni = utf32_in_ausgabe(tastatur.name(i));
  4726. for(int j = 0; j < ntaste+nshift; ++j){
  4727. const std::string nj = utf32_in_ausgabe(tastatur.name(j));
  4728. const double b = A.bigrammaufwand(i, j, tastatur);
  4729. if(b != 0.)
  4730. std::cout << "Bigramm " << ni << " " << nj << " "
  4731. << std::setprecision(16) << b << "\n";
  4732.  
  4733. if(mit_trigrammen){
  4734. for(int k = 0; k < ntaste+nshift; ++k){
  4735. const double t = A.trigrammaufwand(i, j, k, tastatur);
  4736. if(t != 0.)
  4737. std::cout << "Trigramm " << ni << " " << nj << " "
  4738. << utf32_in_ausgabe(tastatur.name(k)) << " "
  4739. << std::setprecision(16) << t << "\n";
  4740. }
  4741. }
  4742.  
  4743. if(i < ntaste && j < ntaste){
  4744. const double v = verwechslungspotenzial(i, j);
  4745. if(v != 0.)
  4746. std::cout << "Verwechslungspotenzial " << ni << " " << nj << " "
  4747. << std::setprecision(16) << v << "\n";
  4748. if(mit_vorlieben && vorliebe(i, j) != 0.){
  4749. const std::string& z = kodierung.bevorzugt(i);
  4750. const std::string a = z == einfachesanfuehrungszeichen
  4751. ? "\"" : einfachesanfuehrungszeichen;
  4752. std::cout << "Vorliebe " << a << z << a << " "
  4753. << -vorliebe(i, j) << " " << nj << "\n";
  4754. }
  4755. }
  4756. }
  4757. }
  4758. #ifdef EXPERIMENTELL
  4759. if(mit_vorlieben && A.vorliebenknick() > -1e15)
  4760. std::cout << "VorliebeKnick " << A.vorliebenknick() << "\n";
  4761. #endif // EXPERIMENTELL
  4762. }
  4763.  
  4764. //--------------- src/ngramme.cc ---------------
  4765. //#include "ngramme.hh"
  4766.  
  4767. //#include "Eingabestream.hh"
  4768. //#include "typen.hh"
  4769. //#include "utfhilfe.hh"
  4770. //#include "vollkorpus.hh"
  4771. //#include "wortliste.hh"
  4772. #include <cstdint>
  4773. #include <fstream>
  4774. #include <iomanip>
  4775. #include <map>
  4776. #include <unordered_map>
  4777.  
  4778. namespace {
  4779.  
  4780. void lies_ngramme(const std::string& name, size_t N,
  4781. std::unordered_map<uint64_t, zaehl_t>& uh){
  4782. bool utf8 = true, geaendert = false;
  4783. do{
  4784. uh.clear();
  4785. Eingabestream tabelle(name, utf8, true);
  4786. while(tabelle.echte_neuezeile()){
  4787. const zaehl_t h = hole_zahl(tabelle, 0, 1e15);
  4788. pruefe_leer_dann_N(tabelle, N);
  4789. tabelle.uebergehen();
  4790. uint64_t k = 0;
  4791. for(size_t i = 0; i < N; ++i)
  4792. k = (k<<21) | (tabelle.lies_in_zeile() & utf_maske);
  4793. uh[k] += h;
  4794. }
  4795. geaendert = tabelle.encoding_geaendert();
  4796. utf8 = false;
  4797. }while(geaendert);
  4798. }
  4799.  
  4800. template <typename S>
  4801. void ngramme_ausgeben(const std::unordered_map<S, zaehl_t>& uh,
  4802. const std::string& name)
  4803. {
  4804. if(uh.size() == 0) return;
  4805. std::ofstream o(name.c_str(), std::ios_base::out);
  4806. std::multimap<zaehl_t, std::string> g;
  4807. for(const auto& i : uh)
  4808. g.insert(std::make_pair(i.second, utf32_in_utf8(i.first)));
  4809. for(auto i = g.crbegin(); i != g.crend(); ++i)
  4810. o << std::setprecision(16) << i->first << " " << i->second << "\n";
  4811. }
  4812.  
  4813. }
  4814.  
  4815. void erzeuge_ngrammtabellen(const std::vector<std::string>& namen)
  4816. {
  4817. std::unordered_map<std::u32string, zaehl_t> wl;
  4818. std::unordered_map<uint64_t, zaehl_t> uh[3];
  4819. const std::string ext[] = { ".1", ".2", ".3", ".wl" };
  4820.  
  4821. if(namen.size() < 3){
  4822. if(namen.size() == 1)
  4823. lies_vollkorpus(namen[0], nullptr, wl, uh);
  4824. else
  4825. lies_vollkorpus(namen[1], &namen[0], wl, uh);
  4826. }else{
  4827. for(size_t i = 0; i+1 < namen.size(); ++i){
  4828. for(int j = 0; j < 3; ++j){
  4829. std::unordered_map<uint64_t, zaehl_t> uhj;
  4830. lies_ngramme(namen[i]+ext[j], j+1, uhj);
  4831. if(uh[j].size()){
  4832. for(const auto& k : uhj) uh[j][k.first] += uhj[k.second];
  4833. }else{
  4834. uh[j].swap(uhj);
  4835. }
  4836. }
  4837. std::unordered_map<std::u32string, zaehl_t> wli;
  4838. lies_wortliste(namen[i]+ext[3], wli, false);
  4839. if(wl.size()){
  4840. for(const auto& k : wli) wl[k.first] += k.second;
  4841. }else{
  4842. wl.swap(wli);
  4843. }
  4844. }
  4845. }
  4846.  
  4847. const std::string base = namen.back();
  4848. for(int j = 0; j < 3; ++j) ngramme_ausgeben(uh[j], base+ext[j]);
  4849. ngramme_ausgeben(wl, base+ext[3]);
  4850. }
  4851.  
  4852. //--------------- src/html_markup.cc ---------------
  4853. //#include "html_markup.hh"
  4854.  
  4855. //#include "Eingabestream.hh"
  4856. //#include "Kodierung.hh"
  4857. //#include "Naechstes_zeichen.hh"
  4858. //#include "Tastatur.hh"
  4859. //#include "string_in_belegung.hh"
  4860. //#include "utfhilfe.hh"
  4861. #include <cmath>
  4862. #include <fstream>
  4863. #include <iostream>
  4864. #include <map>
  4865. #include <utility>
  4866. #include <vector>
  4867.  
  4868. namespace {
  4869.  
  4870. void add_bigramm_markup(int f, int vf, bool shift,
  4871. std::string& stil)
  4872. {
  4873. char c = 0;
  4874. if(vf == f){
  4875. c = 'K';
  4876. }else if(std::abs(vf-f) == 1){
  4877. c = 'N';
  4878. }else if(vf*f > 0){
  4879. c = (std::abs(f) > std::abs(vf)) ? 'A' : 'E';
  4880. }
  4881. if(c){
  4882. if(stil.length()) stil.push_back(' ');
  4883. stil.push_back(shift ? ('a'-'A')+c : c);
  4884. }
  4885. }
  4886.  
  4887. class Hole_mit_ersetzen {
  4888. Naechstes_zeichen nz;
  4889. const Kodierung& kodierung;
  4890. const std::vector<std::pair<int, int>>* ersatz = nullptr;
  4891. size_t ersatz_i = 0;
  4892. public:
  4893. Hole_mit_ersetzen(const std::string& name, const Kodierung& kodierung,
  4894. bool utf8)
  4895. : nz(name, utf8), kodierung(kodierung){}
  4896.  
  4897. std::pair<char32_t, std::pair<int,int>> get() {
  4898. if(ersatz && ersatz_i < ersatz->size()){
  4899. const auto& ie = (*ersatz)[ersatz_i++];
  4900. return std::make_pair(kodierung.uchar(ie.first, ie.second), ie);
  4901. }
  4902. const char32_t z = nz.get();
  4903. const auto ie = kodierung.position(z);
  4904. if(ie.first < 0){
  4905. ersatz = kodierung.ersatz(z);
  4906. ersatz_i = 0;
  4907. if(ersatz) return get();
  4908. }
  4909. return std::make_pair(z, ie);
  4910. }
  4911.  
  4912. bool encoding_geaendert() const { return nz.encoding_geaendert(); }
  4913. };
  4914.  
  4915. }
  4916.  
  4917. void html_markup(const std::string& textfile, const Kodierung& kodierung,
  4918. const Tastatur& tastatur, const std::string& referenztastatur)
  4919. {
  4920. const std::map<char32_t, std::string> escape =
  4921. {{ U'<', "&lt;" },{ U'>', "&gt;" },{ U'&', "&amp;" },{ U'\u00A0', " " } };
  4922.  
  4923. bool utf8 = true, nochmal;
  4924. do{
  4925. nochmal = false;
  4926. Eingabestream liste(referenztastatur, true);
  4927. std::ofstream html(textfile+".html");
  4928. html << "<!DOCTYPE html><html><head>\n"
  4929. "<meta http-equiv=\"Content-Type\" content=\"text/html; "
  4930. "charset=utf-8\" />\n"
  4931. "<style type=\"text/css\">\n"
  4932. ".K{background-color: #FCC;}\n"
  4933. ".k{text-decoration: underline; text-decoration-color: #F00;}\n"
  4934. ".N{background-color: #FFA;}\n"
  4935. ".n{text-decoration: underline; text-decoration-color: #A80;}\n"
  4936. ".A{background-color: #DDF;}\n"
  4937. ".a{text-decoration: underline; text-decoration-color: #00F;}\n"
  4938. ".E{background-color: #DFD;}\n"
  4939. ".e{text-decoration: underline; text-decoration-color: #0F0;}\n"
  4940. ".L{color: #008;}\n"
  4941. ".R{color: #080;}\n"
  4942. ".G{font-weight: 600;}\n"
  4943. ".B{font-family: monospace; background-color: #FFF; color: #000;}\n"
  4944. "</style>\n"
  4945. "</head><body>\n"
  4946. SPRACHE("<p class=\"B\">"
  4947. "<a class=\"K\">Kollision</a>, "
  4948. "<a class=\"k\">Shift-Kollision</a>, "
  4949. "<a class=\"N\">Nachbaranschlag</a>, "
  4950. "<a class=\"n\">Shift-Nachbaranschlag</a>, "
  4951. "<a class=\"A\">Auswärts</a>, "
  4952. "<a class=\"a\">Shift-Auswärts</a>, "
  4953. "<a class=\"E\">Einwärts</a>, "
  4954. "<a class=\"e\">Shift-Einwärts</a>.\n"
  4955. ,
  4956. "<p class=\"B\">"
  4957. "<a class=\"K\">Same finger repetition</a>, "
  4958. "<a class=\"k\">Shift-same finger repetition</a>, "
  4959. "<a class=\"N\">adjacent finger stroke</a>, "
  4960. "<a class=\"n\">Shift-adjacent finger stroke</a>, "
  4961. "<a class=\"A\">outwards</a>, "
  4962. "<a class=\"a\">Shift-outwards</a>, "
  4963. "<a class=\"E\">inwards</a>, "
  4964. "<a class=\"e\">Shift-inwards</a>.\n"
  4965. ) "</p>";
  4966. while(liste.echte_neuezeile()){
  4967. std::u32string bs, uname;
  4968. if(!liste.hole_wort(bs) || !liste.hole_wort(uname)){
  4969. std::cerr << SPRACHE("Fehlerhaft formatiertes Belegungsfile ",
  4970. "Incorrectly formatted layout file ")
  4971. << referenztastatur << std::endl;
  4972. liste.fehler();
  4973. }
  4974.  
  4975. if(!bs.size()) continue;
  4976. bool fest[ntaste];
  4977. belegung_t b, ib;
  4978. string_in_belegung(bs, b, fest, tastatur.nvariabel(), kodierung);
  4979. for(int i = 0; i < ntaste; ++i) ib[b[i]] = i;
  4980.  
  4981. html << "<h1>" << utf32_in_utf8(uname) << "</h1>\n<p class=\"B\">";
  4982. Hole_mit_ersetzen nz(textfile, kodierung, utf8);
  4983. int vorige_pos = -1, vorige_ebene = -1;
  4984. std::string voriger_stil;
  4985. do{
  4986. const auto zie = nz.get();
  4987. const auto zeichen = zie.first;
  4988. nochmal = nz.encoding_geaendert();
  4989. if(!zeichen || nochmal) break;
  4990. const auto i = zie.second.first, e = zie.second.second;
  4991. std::string stil;
  4992. if(i >= 0 && e >= 0){
  4993. const auto pos = ib[i];
  4994. const auto shift = tastatur.shifttaste(pos);
  4995. const auto f = tastatur.finger(pos), sf = tastatur.finger(shift);
  4996. if(vorige_pos >= 0){
  4997. const auto vshift = tastatur.shifttaste(vorige_pos);
  4998. const auto vf = tastatur.finger(vorige_pos);
  4999. const auto vsf = tastatur.finger(vshift);
  5000. if(vorige_pos != pos) add_bigramm_markup(f, vf, false, stil);
  5001. if(vorige_ebene > 0){
  5002. // Shift-Buchstabentaste oder Shift-Shift?
  5003. const auto nt = e ? shift : pos;
  5004. if(vshift != nt)
  5005. add_bigramm_markup(e ? sf : f, vsf, true, stil);
  5006. }
  5007. }
  5008. vorige_pos = pos; vorige_ebene = e;
  5009. }else{
  5010. vorige_pos = vorige_ebene = -1;
  5011. }
  5012. if(stil != voriger_stil){
  5013. if(voriger_stil.size()) html << "</a>";
  5014. if(stil.size()) html << "<a class=\"" << stil << "\">";
  5015. voriger_stil.swap(stil);
  5016. }
  5017. const auto iesc = escape.find(zeichen);
  5018. if(iesc == escape.end()){
  5019. html << utf32_in_utf8(zeichen);
  5020. }else{
  5021. html << iesc->second;
  5022. }
  5023. }while(true);
  5024. if(voriger_stil.size()) html << "</a>";
  5025. html << "</p>\n";
  5026. }
  5027. html << "</body></html>\n" << std::endl;
  5028. utf8 = false;
  5029. }while(nochmal);
  5030. }
  5031.  
  5032. //--------------- src/trennen.cc ---------------
  5033. //#include "trennen.hh"
  5034.  
  5035. //#include "Eingabestream.hh"
  5036. //#include "Unicode.hh"
  5037. //#include "utfhilfe.hh"
  5038. #include <cassert>
  5039. #include <memory>
  5040.  
  5041. namespace {
  5042.  
  5043. size_t
  5044. lies_trennmuster(const std::string& name,
  5045. std::unordered_map<std::u32string, std::vector<char>>& tabelle)
  5046. {
  5047. size_t maxlen;
  5048. bool utf8ein = true, nochmal = false;
  5049. do{
  5050. tabelle.clear();
  5051. maxlen = 0;
  5052. Eingabestream liste(name, utf8ein);
  5053. while(liste.echte_neuezeile()){
  5054. std::u32string muster;
  5055. std::vector<char> trennstellen;
  5056. bool warziffer = false;
  5057. while(const char32_t zi = liste.lies_in_zeile()){
  5058. if(ist_ziffer(zi)){
  5059. trennstellen.push_back(zi-U'0');
  5060. warziffer = true;
  5061. }else{
  5062. if(!warziffer) trennstellen.push_back(0);
  5063. muster.append(1, zi);
  5064. warziffer = false;
  5065. }
  5066. }
  5067. if(!warziffer) trennstellen.push_back(0);
  5068. assert(trennstellen.size() == muster.size()+1);
  5069. tabelle[muster] = trennstellen;
  5070. if(muster.size() > maxlen) maxlen = muster.size();
  5071. }
  5072. nochmal = liste.encoding_geaendert();
  5073. utf8ein = false;
  5074. }while(nochmal);
  5075. return maxlen;
  5076. }
  5077.  
  5078. void
  5079. trenne(const std::u32string& wort1,
  5080. const std::unordered_map<std::u32string, std::vector<char>>& tabelle,
  5081. size_t maxlen, std::vector<bool>& resultat)
  5082. {
  5083. static const size_t min_silbenlaenge = 2;
  5084.  
  5085. // Die Punkte in der Trennmustertabelle markieren Wortanfang und Wortende.
  5086. std::u32string wort(wort1.size()+2, U'.');
  5087. for(size_t i = 0; i < wort1.size(); ++i)
  5088. wort[i+1] = Unicode::get().kleinbuchstabe(wort1[i]);
  5089. std::vector<char> trennstellen(wort.length()+1, 0);
  5090. for(size_t i = 0; i < wort.size()-min_silbenlaenge; ++i){
  5091. const size_t minlaenge = i ? min_silbenlaenge : min_silbenlaenge+1;
  5092. const size_t len = wort.size()-i;
  5093. const size_t maxlaenge = len > maxlen ? maxlen : len;
  5094. // Effizienz spielt keine Rolle...
  5095. std::u32string muster(wort, i, minlaenge-1);
  5096. muster.reserve(maxlaenge);
  5097. for(size_t j = minlaenge; j <= maxlaenge; ++j){
  5098. muster.append(1, wort[i+j-1]);
  5099. const auto p = tabelle.find(muster);
  5100. if(p != tabelle.end()){
  5101. const std::vector<char>& t = p->second;
  5102. for(size_t k = 0; k < t.size(); ++k){
  5103. if(t[k] > trennstellen[i+k]) trennstellen[i+k] = t[k];
  5104. }
  5105. }
  5106. }
  5107. }
  5108.  
  5109. if(resultat.size() < wort1.size()) resultat.resize(wort1.size());
  5110. for(size_t i = 2; i < trennstellen.size()-2; ++i){
  5111. const bool innen = (i > min_silbenlaenge) &&
  5112. (i < trennstellen.size()-1-min_silbenlaenge);
  5113. resultat[i-2] = innen && (trennstellen[i] & 1);
  5114. }
  5115. resultat[wort1.size()-1] = true;
  5116. }
  5117.  
  5118. }
  5119.  
  5120.  
  5121. char32_t
  5122. hole_mit_trennung::fuelle_buffer(){
  5123. wort_i = 0;
  5124. wort.erase();
  5125. char32_t c = Naechstes_zeichen::get();
  5126. while(Unicode::get().ist_buchstabe(c)){
  5127. wort.append(1, c);
  5128. c = Naechstes_zeichen::get();
  5129. }
  5130. if(wort.size()){
  5131. const auto i = cache.find(wort);
  5132. if(i != cache.end())
  5133. trennstellen = i->second;
  5134. else{
  5135. trenne(wort, trennmuster, maxlen, trennstellen);
  5136. cache[wort] = trennstellen;
  5137. }
  5138. }
  5139. return c;
  5140. }
  5141.  
  5142. hole_mit_trennung::
  5143. hole_mit_trennung(const std::string& name, const std::string& tmfile,
  5144. bool utf8)
  5145. : Naechstes_zeichen(name, utf8)
  5146. {
  5147. maxlen = lies_trennmuster(tmfile, trennmuster);
  5148. naechste_ist_trennung = false;
  5149. rest = fuelle_buffer();
  5150. }
  5151.  
  5152.  
  5153. char32_t
  5154. hole_mit_trennung::
  5155. get(){
  5156. const char32_t trenner = U'\u00ad';
  5157. if(naechste_ist_trennung){
  5158. naechste_ist_trennung = false;
  5159. return trenner;
  5160. }
  5161.  
  5162. if(wort_i < wort.size()){
  5163. naechste_ist_trennung = trennstellen[wort_i];
  5164. const char32_t c = wort[wort_i];
  5165. wort_i++;
  5166. return c;
  5167. }
  5168.  
  5169. if(rest){
  5170. const char32_t alterrest = rest;
  5171. rest = fuelle_buffer();
  5172. naechste_ist_trennung = true;
  5173. return alterrest;
  5174. }
  5175. return 0;
  5176. }
  5177.  
  5178.  
  5179. void markiere_alle_trennstellen(const std::string& ein, const std::string& aus,
  5180. const std::string& trennmuster)
  5181. {
  5182. bool utf8 = true, nochmal = false;
  5183. do{
  5184. std::unique_ptr<Naechstes_zeichen> nz
  5185. (new hole_mit_trennung(ein, trennmuster, utf8));
  5186. std::ofstream ausgabe(aus.c_str(), std::ios_base::out);
  5187. while(char32_t c3 = nz->get()) ausgabe << utf32_in_utf8(c3);
  5188. nochmal = nz->encoding_geaendert();
  5189. utf8 = false;
  5190. }while(nochmal);
  5191. }
  5192.  
  5193. //--------------- src/Grafik.cc ---------------
  5194. //#include "Grafik.hh"
  5195.  
  5196. //#include "Haeufigkeit.hh"
  5197. //#include "Kodierung.hh"
  5198. //#include "Konfiguration.hh"
  5199. //#include "Tastatur.hh"
  5200. #include <cmath>
  5201.  
  5202. Grafik::
  5203. Grafik(const std::string& name, const Tastatur& tast,
  5204. const Kodierung& kod, const Haeufigkeit& h,
  5205. const Konfiguration& konfiguration)
  5206. : grafik(name.c_str(), std::ios_base::out), seite(0),
  5207. ungerade(false), tastatur(tast), kodierung(kod)
  5208. {
  5209. constexpr double sk = 1e6;
  5210. const std::string& Beschreibungsfont = konfiguration.beschreibungsfont();
  5211. const std::string& Zeichenfont = konfiguration.zeichenfont();
  5212.  
  5213. // Vorspann
  5214. grafik <<
  5215. "%!PS-Adobe-3.0\n"
  5216. "%%BoundingBox: 0 0 842 595\n"
  5217. "%%DocumentFonts: " << Beschreibungsfont;
  5218. if(Beschreibungsfont != Zeichenfont) grafik << " " << Zeichenfont;
  5219. grafik <<
  5220. "\n%%DocumentData: Clean8Bit\n"
  5221. "%%EndComments\n"
  5222. "%%BeginProlog\n"
  5223. "/transparenz true def % Verwende Transparenz (nach Konversion in PDF)\n"
  5224. "/alpha 0.5 def % Grad der Transparenz (1: intranspanent)\n"
  5225. "/mitmini true def % Zeige Minitastatur unter Buchstaben\n"
  5226. "/mitZahlen true def % Zeige Haeufigkeiten zusaetzlich als Zahlenwerte an\n"
  5227. "/mitSummen true def % Zeige summierte Haeufigkeiten mit an\n"
  5228. "/minFuerKurve 0.01 def % Mindestbigrammhaeufigkeit, ab der Kurve gemalt wird\n"
  5229. "/maxkurvendicke 0.25 def % Maximale Dicke der Kurven\n"
  5230. "/differenzen false def % Zeige Haeufigkeitsdiffenzen fuer Belegungspaare\n"
  5231. "/fhkaestchen 0.25 def % Fingerhaeufigkeit: Haeufigkeit, die Kaestchen fuellt\n"
  5232. "/ghkaestchen 0.4 def % Gruppenhaeufigkeit ''\n"
  5233. "/bikaestchen 0.02 def % Bigrammhaeufigkeit ''\n"
  5234. "/zhkaestchen 0.2 def % Zeilenspruenge ''\n"
  5235. "/kollschritt 1.25 sqrt def % Sprungdistanz-Einteilung bei Kollisionen\n"
  5236. "/beschrx 0.3 def % X-Position der Beschreibung\n"
  5237. "/beschry -0.7 def % X-Position der Beschreibung\n"
  5238. "/beschrgr 0.3 def % Groesse der Beschreibung\n"
  5239. "%\n"
  5240. "/b{def}bind def/B{bind b}bind b"
  5241. "/h1a[";
  5242.  
  5243. // Variabler Teil: Häufigkeiten, Zeichen, Tasten
  5244. for(int i = 0; i < tastatur.nvariabel(); ++i)
  5245. grafik << std::floor(0.5+(h(i,0)+h(i,1))*sk)
  5246. << (i+1 < tastatur.nvariabel() ? " " : "]");
  5247. grafik << "B/h1s[";
  5248. for(int i = 0; i < tastatur.nvariabel(); ++i)
  5249. grafik << std::floor(0.5+h(i,1)*sk)
  5250. << (i+1 < tastatur.nvariabel() ? " " : "]");
  5251. grafik << "B/h2a[";
  5252. for(int i = 0; i < tastatur.nvariabel(); ++i){
  5253. grafik << "[";
  5254. for(int j = 0; j < tastatur.nvariabel(); ++j){
  5255. double h2 = 0.;
  5256. for(int ej = 0; ej < nebene2; ++ej)
  5257. h2 += h(i,0,j,ej)+h(i,1,j,ej);
  5258. grafik << std::floor(0.5+h2*sk)
  5259. << (j+1 < tastatur.nvariabel() ? " " : "]");
  5260. }
  5261. }
  5262. grafik << "]B/h2s[";
  5263. for(int i = 0; i < tastatur.nvariabel(); ++i){
  5264. grafik << "[";
  5265. for(int j = 0; j < tastatur.nvariabel(); ++j){
  5266. double h2 = 0.;
  5267. for(int ej = 0; ej < nebene2; ++ej)
  5268. h2 += h(i,1,j,ej);
  5269. grafik << std::floor(0.5+h2*sk)
  5270. << (j+1 < tastatur.nvariabel() ? " " : "]");
  5271. }
  5272. }
  5273. grafik << "]B/klartext{(";
  5274. for(int i = 0; i < tastatur.nvariabel(); ++i)
  5275. grafik << kodierung.psencstr(i);
  5276. grafik << ")}B/zeilen[";
  5277. int maxzeile = 0, minzeile = 99;
  5278. double maxx = -100, minx = 100, maxy = -100, miny = 100;
  5279. double maxx1 = -100, minx1 = 100, maxy1 = -100, miny1 = 100;
  5280. for(int i = 0; i < ntaste+nshift; ++i){
  5281. if(i < ntaste && i >= tastatur.nvariabel()) continue;
  5282.  
  5283. const auto k = tastatur.tastenkoord(i);
  5284. const int zeile = zeilen_t::Leerzeichenzeile-tastatur.zeile(i);
  5285.  
  5286. if(zeile > maxzeile) maxzeile = zeile;
  5287. if(zeile < minzeile) minzeile = zeile;
  5288.  
  5289. if(k.x > maxx) maxx = k.x;
  5290. if(k.x < minx) minx = k.x;
  5291. if(k.y > maxy) maxy = k.y;
  5292. if(k.y < miny) miny = k.y;
  5293.  
  5294. if(i < ntaste){
  5295. if(k.x > maxx1) maxx1 = k.x;
  5296. if(k.x < minx1) minx1 = k.x;
  5297. if(k.y > maxy1) maxy1 = k.y;
  5298. if(k.y < miny1) miny1 = k.y;
  5299. }
  5300.  
  5301. grafik << zeile;
  5302. if(i+1 < ntaste+nshift) grafik << " ";
  5303. }
  5304.  
  5305. // Für die globale Skalierung:
  5306. const double weite = maxx-minx+1.5;
  5307. const double hoehe = zeilen_t::Leerzeichenzeile-miny;
  5308. const double skala = std::min(12.5/weite, std::min(4./hoehe, 1.));
  5309. // Für die Skalierung der Minitastaturen:
  5310. const double miniweite = maxx1-minx1+1;
  5311. const double minihoehe = maxy1-miny1+1;
  5312. const double minixoff = minx1-minx;
  5313. const double miniyoff = zeilen_t::Leerzeichenzeile-maxy1;
  5314.  
  5315. grafik << "]B/koordinaten[";
  5316. for(int i = 0; i < ntaste+nshift; ++i){
  5317. if(i < ntaste && i >= tastatur.nvariabel()) continue;
  5318. const auto k = tastatur.tastenkoord(i);
  5319. double x = k.x-minx;
  5320. // Verschiebe Daumentasten der Platzeinteilung zuliebe.
  5321. if(zeilen_t::Leerzeichenzeile == tastatur.zeile(i)){
  5322. if(tastatur.spalte(i) == 5){
  5323. x -= 4;
  5324. }else if(tastatur.spalte(i) == 9){
  5325. x += 4;
  5326. }
  5327. }
  5328. grafik << "[" << x << " " << zeilen_t::Leerzeichenzeile-k.y << "]";
  5329. }
  5330. grafik << "]B/fingertab[";
  5331. for(int i = 0; i < ntaste+nshift; ++i){
  5332. if(i < ntaste && i >= tastatur.nvariabel()) continue;
  5333. grafik << tastatur.finger(i);
  5334. if(i+1 < ntaste+nshift) grafik << " ";
  5335. }
  5336. grafik << "]B/shift[";
  5337. for(int i = 0; i < tastatur.nvariabel(); ++i){
  5338. grafik << tastatur.shifttaste(i)+tastatur.nvariabel()-ntaste;
  5339. if(i+1 < tastatur.nvariabel()) grafik << " ";
  5340. }
  5341. grafik << "]B/minzeile " << minzeile
  5342. << " b/maxzeile " << maxzeile
  5343. << " b/skala " << skala
  5344. << " b/minx " << minx
  5345. << " b/minixoff " << -minixoff
  5346. << " b/miniyoff " << -miniyoff
  5347. << " b/minihoehe " << minihoehe
  5348. << " b/miniweite " << miniweite
  5349. << " b";
  5350.  
  5351. std::string meinencoding = "ISOLatin1Encoding";
  5352. bool umcodieren = false;
  5353. for(int i = 0; i < tastatur.nvariabel(); ++i)
  5354. if(kodierung.psglyphname(i).size()) umcodieren = true;
  5355. if(umcodieren){
  5356. meinencoding = "meinencoding";
  5357. grafik << "/meinencoding[ISOLatin1Encoding aload pop]B\n";
  5358. for(int i = 0; i < tastatur.nvariabel(); ++i){
  5359. if(kodierung.psglyphname(i).size()){
  5360. const int n = kodierung.psencoding(i);
  5361. grafik << meinencoding << " " << n << "/"
  5362. << kodierung.psglyphname(i) << " put\n";
  5363. }
  5364. }
  5365. }
  5366. grafik <<
  5367. "/schrift{findfont 0.3 scalefont setfont}B"
  5368. "/neuerfont{findfont dup length dict begin{b}forall/Encoding "
  5369. << meinencoding << " b currentdict end definefont pop}B"
  5370. "/BSchrift/" << Beschreibungsfont << " neuerfont\n";
  5371. if(Beschreibungsfont != Zeichenfont)
  5372. grafik <<"/ZSchrift/" << Zeichenfont << " neuerfont\n";
  5373.  
  5374. grafik <<
  5375. "/n " << tastatur.nvariabel() << " b/N " << tastatur.nvariabel()+nshift << " b"
  5376. "/zz 5 b" // zeilenzahl
  5377. "/mf 2 b" // innerster Finger
  5378. "/xf 5 b" // äusserster Finger
  5379. "/tmp 2 array B"
  5380. "/rot{3 2 roll}B"
  5381. "/-rot{3 1 roll}B"
  5382. "/over{1 index}B"
  5383. "/2dup{2 copy}B"
  5384. "/nip{exch pop}B"
  5385. "/tuck{exch over}B"
  5386. "/2drop{pop pop}B"
  5387. "/3drop{2drop pop}B"
  5388. "/2swap{4 2 roll}B"
  5389. "/l{1 sub 0 1 rot}B"
  5390. "/L{length l}B"
  5391. "/R{grestore}B"
  5392. "/S{gsave}B"
  5393. "/T{translate}B"
  5394. "/@{exch get}B"
  5395. "/?{ifelse}B"
  5396. "/max{2dup gt{pop}{nip}?}B"
  5397. "/min{2dup gt{nip}{pop}?}B"
  5398. "/hypot{dup mul exch dup mul add sqrt}B"
  5399. "/lf{dup L{over exch 0 put}for pop}B" // lösche Feld
  5400. "/lF{dup L{over @ lf}for pop}B" // lösche Felder
  5401. "/arraymax{tuck L{2 index @ max}for nip}B"
  5402. "/arraysumme{tuck L{2 index @ add}for nip}B"
  5403. "/addinsarray{2 index 2 index get add put}B"
  5404. "/addarrays{dup L{2dup get 3 index -rot addinsarray}for 2drop}B"
  5405. "/submaxvonarray{2 index 2 index get exch sub 0 max put}B"
  5406. "/submaxarrays{dup L{2dup get 3 index -rot submaxvonarray}for 2drop}B"
  5407. "/submaxmatrizen{dup L{2dup get 3 index rot get exch submaxarrays}for 2drop}B"
  5408. "/switch{@ exec}B"
  5409. "/buchstabe{over length over le{2drop(Sh)}{1 getinterval}?}B"
  5410. "/zeile{zeilen @}B/finger{fingertab @}B"
  5411. "/buchstabentab[256{-1}repeat]B "
  5412. // Berechnet buchstabentab[buchstabe] = i
  5413. "n l{klartext over get buchstabentab -rot exch put}for"
  5414. "/koordinate{koordinaten @ aload pop}B"
  5415. "/gruppe{dup finger 0 lt{0}{zz}? exch zeile add}B"
  5416. "/klassifiziere{" // taste2 taste1--
  5417. "2dup eq"
  5418. "{2drop 1}"
  5419. "{"
  5420. "finger exch finger "
  5421. "2dup mul 0 lt"
  5422. "{2drop 0}"
  5423. "{"
  5424. "2dup eq"
  5425. "{2drop 6}"
  5426. "{"
  5427. "abs exch abs 2dup lt"
  5428. "{sub abs 1 eq{3}{5}?}"
  5429. "{sub abs 1 eq{2}{4}?}?"
  5430. "}?"
  5431. "}?"
  5432. "}?"
  5433. "}B"
  5434. "/klassifikationstab["
  5435. "N l{"
  5436. "[exch N l{over klassifiziere exch}for pop]"
  5437. "}for"
  5438. "]B"
  5439. "/bigrammklasse{" // taste1 taste2--
  5440. "exch klassifikationstab @ @"
  5441. "}B"
  5442. "/einmax 0 h1a arraymax b"
  5443. "/bimax 0 h2a L{h2a @ arraymax}for b"
  5444. "/einsumme 0 h1a arraysumme b"
  5445. "/bisumme 0 h2a L{h2a @ arraysumme}for h2s L{h2s @ arraysumme}for b"
  5446. "/ph1a N array B"
  5447. "/ph1A N array B"
  5448. "/ph1s n array B"
  5449. "/ph2a[N{n array}repeat]B"
  5450. "/ph2A[N{n array}repeat]B"
  5451. "/ph2s[n{n array}repeat]B"
  5452. // Weist TOS gemäss der Belegung permutiertes TOS+1 zu
  5453. "/perm1{" // belegung htab1 ptab1--
  5454. "n l{"
  5455. "over exch 4 index over get buchstabentab @ 4 index @ put"
  5456. "}for 3drop"
  5457. "}B"
  5458. // Weist TOS gemäss der Belegung permutiertes TOS+1 zu
  5459. "/perm2{" // belegung htab2 ptab2
  5460. "n l{"
  5461. "3 index over get buchstabentab @ 3 index @ "
  5462. "2 index rot get 4 index -rot perm1"
  5463. "}for 3drop"
  5464. "}B"
  5465. "/setze{" // belegung 1a 2a--
  5466. "rot 2 index 2 index "
  5467. "2 index h2s ph2s perm2 "
  5468. "2 index h2a rot perm2 "
  5469. "over h1s ph1s perm1 "
  5470. "h1a exch perm1 "
  5471. "n 1 over " << nshift-1 << " add{"
  5472. "2 index over 0 put "
  5473. "over @ lf"
  5474. "}for "
  5475. "h1s L{" // 1a 2a i
  5476. "shift over get 2dup exch "
  5477. "ph1s @ 5 index -rot addinsarray "
  5478. "2 index @ exch ph2s @ addarrays"
  5479. "}for 2drop"
  5480. "}B"
  5481. "/zentriert{dup stringwidth pop -0.5 mul 0 rmoveto show}B"
  5482. "/zzahl{mitZahlen{(000000000000)cvs zentriert}{pop}?}B"
  5483. "/zeigebuchstabe{" // belegungsstring tastenindex
  5484. "S "
  5485. "pop 0.5 0.5 moveto "
  5486. << ((Beschreibungsfont != Zeichenfont)
  5487. ? "S/ZSchrift schrift zentriert R"
  5488. : "zentriert")
  5489. <<
  5490. " 0.2 dup scale "
  5491. "tmp 1 get 2.5 2.1 moveto zzahl "
  5492. "R"
  5493. "}B"
  5494. "/skgrau{sqrt 0.95 mul 0.95 exch sub setgray}B"
  5495. "/skrgb{"
  5496. "4 3 roll sqrt 0.95 mul 0.05 add 4 1 roll "
  5497. "3{1 sub 3 index mul 1 add rot}repeat "
  5498. "setrgbcolor pop"
  5499. "}B"
  5500. "/Q{"
  5501. "0.1 0.1 0.8 0.8 rectfill "
  5502. "0 setgray tmp 1 get "
  5503. "0.5 0.12 moveto zzahl"
  5504. "}B"
  5505. "/K{"
  5506. "0.05 setlinewidth newpath "
  5507. "0.1 0.1 moveto 0.9 0.9 lineto "
  5508. "0.1 0.9 moveto 0.9 0.1 lineto stroke"
  5509. "}B"
  5510. "/minitastatur{" // t1 htab
  5511. "S "
  5512. "transparenz{/Normal .setblendmode alpha .setshapealpha}if "
  5513. "0.03 0 0.94 dup minihoehe mul miniweite div rectfill "
  5514. "R "
  5515. "dup L{"
  5516. "S 0.03 0 T "
  5517. "0.94 miniweite div dup scale "
  5518. "minixoff miniyoff T "
  5519. "2dup get dup tmp 1 rot put "
  5520. "bimax div "
  5521. "over koordinate T "
  5522. "3 index rot bigrammklasse"
  5523. "["
  5524. "{0 0.7 0 skrgb Q}"
  5525. "{0 0.7 0 skrgb K}"
  5526. "{0.9 0.7 0 skrgb Q}"
  5527. "{0.9 0.9 0 skrgb Q}"
  5528. "{0.2 0.9 0 skrgb Q}"
  5529. "{0.2 0.9 0 skrgb Q}"
  5530. "{0.9 0 0 skrgb Q}"
  5531. "]switch "
  5532. "R"
  5533. "}for 2drop"
  5534. "}B"
  5535. "/taste{" // tastenindex belegung
  5536. "over buchstabe over ph1a @ "
  5537. "dup tmp 1 rot put "
  5538. "einmax div skgrau "
  5539. "over zeigebuchstabe "
  5540. "mitmini{dup ph2a @ minitastatur}{pop}?"
  5541. "}B"
  5542. "/diffpkt{rot sub -rot exch sub exch}B"
  5543. "/skpunkt{rot over mul -rot mul}B"
  5544. "/kurve{"
  5545. "0.4 -0.2 2dup hypot 0.15 exch div skpunkt newpath moveto "
  5546. "dup 0.4 -0.2 rot skpunkt rot "
  5547. "dup 0.6 -0.2 rot skpunkt rot "
  5548. "0.4 -0.2 2dup hypot 0.15 exch div skpunkt -rot sub "
  5549. "tmp 1 2 index put"
  5550. "/Pattern setcolorspace"
  5551. "<<"
  5552. "/PatternType 2"
  5553. "/Shading<<"
  5554. "/ShadingType 2"
  5555. "/ColorSpace/DeviceRGB"
  5556. "/Coords[0 0 tmp 1 get 0]"
  5557. "/Extend[true true]"
  5558. "/Function<<"
  5559. "/Domain[0 1]"
  5560. "/FunctionType 0"
  5561. "/Range[0 1 0 1 0 1]"
  5562. "/DataSource tmp 0 get"
  5563. "/BitsPerSample 8"
  5564. "/Size[2]"
  5565. ">>"
  5566. ">>"
  5567. ">>matrix makepattern setcolor "
  5568. "exch curveto stroke"
  5569. "}B"
  5570. "/linien{" // htab tastenindex
  5571. "S dup koordinate T 1 setlinecap "
  5572. "transparenz{/Normal .setblendmode alpha .setshapealpha}if "
  5573. "over L{"
  5574. "2dup eq"
  5575. "{pop}"
  5576. "{"
  5577. "2dup bigrammklasse"
  5578. "[<FFFFFF00FFFF>"
  5579. "<FFFFFFFFFFFF>"
  5580. "<FFFFFF8000FF>"
  5581. "<FFFFFF4000FF>"
  5582. "<FFFFFF0080FF>"
  5583. "<FFFFFF00E0FF>"
  5584. "<FFFFFFFF00FF>"
  5585. "]over get tmp 0 rot put "
  5586. "0 eq"
  5587. "{pop}"
  5588. "{"
  5589. "2 index over get bimax div "
  5590. "dup minFuerKurve gt"
  5591. "{"
  5592. "maxkurvendicke mul setlinewidth "
  5593. "over koordinate rot koordinate diffpkt 2dup exch atan "
  5594. "S "
  5595. "rotate hypot over finger 0 lt{1 -1 scale}if kurve "
  5596. "R"
  5597. "}"
  5598. "{2drop}?"
  5599. "}?"
  5600. "}?"
  5601. "}for "
  5602. "2drop R"
  5603. "}B"
  5604. "/gruppenzahl 2 zz mul b"
  5605. "/fsum 11 array B"
  5606. "/fsumA 11 array B"
  5607. "/gsum gruppenzahl array B"
  5608. "/gsumA gruppenzahl array B"
  5609. "/bsum[11{21 array}repeat]B"
  5610. "/bsumA[11{21 array}repeat]B"
  5611. "/zsum[gruppenzahl{zz array}repeat]B"
  5612. "/zsumA[gruppenzahl{zz array}repeat]B"
  5613. "/fingerhaeufigkeit{" // 1a fs
  5614. "dup lf "
  5615. "over L{"
  5616. "2dup finger 5 add "
  5617. "rot 4 index @ addinsarray"
  5618. "}for 2drop"
  5619. "}B"
  5620. "/gruppenhaeufigkeit{" // 1a gs
  5621. "dup lf "
  5622. "over L{2dup gruppe rot 4 index @ addinsarray}for 2drop"
  5623. "}B"
  5624. "/unterklasse{" // t1 t2
  5625. "2dup bigrammklasse dup 3 mul 4 1 roll"
  5626. "["
  5627. "{2drop 0}dup"
  5628. "{zeile exch zeile sub abs}dup"
  5629. "{2drop 0}dup"
  5630. "{koordinate rot koordinate diffpkt hypot "
  5631. "kollschritt div floor 2 min 0 max cvi}"
  5632. "]switch"
  5633. "}B"
  5634. "/bigrammsumme1{" // bs 2a-1 t1
  5635. "over L{"
  5636. "2dup unterklasse "
  5637. "4 index 4 3 roll get "
  5638. "-rot over add 1 exch{"
  5639. "over 5 index -rot addinsarray"
  5640. "}for pop"
  5641. "}for 3drop"
  5642. "}B"
  5643. "/bigrammhaeufigkeit{" // 2a gs
  5644. "dup lF "
  5645. "over L{"
  5646. "2dup finger 5 add get "
  5647. "over 4 index @ "
  5648. "rot bigrammsumme1"
  5649. "}for 2drop"
  5650. "}B"
  5651. "/zssumme1{" // zs-gr 2a-1 t1
  5652. "finger "
  5653. "over L{"
  5654. "2dup finger mul 0 gt"
  5655. "{2 index over get exch zeile 4 index -rot exch addinsarray}"
  5656. "{pop}?"
  5657. "}for "
  5658. "3drop"
  5659. "}B"
  5660. "/zshaeufigkeit{" // 2a zs
  5661. "dup lF "
  5662. "over L{"
  5663. "2dup gruppe get over 4 index @ rot zssumme1"
  5664. "}for 2drop"
  5665. "}B"
  5666. "/umrandung{0.25 setgray 0.003 setlinewidth 0 0 0.8 0.12 rectstroke}B"
  5667. "/zahlimkaestchen{"
  5668. "S "
  5669. "0.25 setgray 0.4 0.017 moveto 0.4 dup scale zzahl "
  5670. "R"
  5671. "}B"
  5672. "/hkaestchen{"
  5673. "0.75 setgray "
  5674. "over exch einsumme mul div 0.8 mul 0.12 0 0 2swap rectfill "
  5675. "umrandung zahlimkaestchen"
  5676. "}B"
  5677. "/bigrammfarben["
  5678. "[0 1 0][0 0 1][1 0 0]"
  5679. "[]dup dup"
  5680. "[1 1 0.5][1 0.85 0.25][1 0.7 0]"
  5681. "[1 1 0.5][1 0.85 0.25][1 0.7 0]"
  5682. "[]dup 2dup 2dup"
  5683. "[1 0.75 0.75][1 0.4 0.4][1 0 0]"
  5684. "]B"
  5685. "/bkaestchen{" // haeufigkeiten a b
  5686. "over 4 1 roll "
  5687. "1 exch{"
  5688. "bigrammfarben over get aload pop setrgbcolor "
  5689. "over @ "
  5690. "bisumme bikaestchen mul div 0.8 mul 0.12 0 0 2swap rectfill"
  5691. "}for "
  5692. "umrandung @ zahlimkaestchen"
  5693. "}B"
  5694. "/zsfarbe["
  5695. "[[0.5 0.5 0.5][0.5 0.5 0.5][0.5 0.5 0.5][0.5 0.5 0.5][0.5 0.5 0.5]]"
  5696. "[[0.5 0.5 0.5][0 1 0][1 0.7 0][1 0 0][1 0 0]]"
  5697. "[[0.5 0.5 0.5][1 0.5 0][0 1 0][1 0.7 0][1 0 0]]"
  5698. "[[0.5 0.5 0.5][1 0 0][1 0.5 0][0 1 0][1 0.7 0]]"
  5699. "[[0.5 0.5 0.5][1 0 0][1 0 0][1 0.7 0][0 1 0]]"
  5700. "]B"
  5701. "/zkaestchen{" // haeufigkeiten farbtab
  5702. "minzeile 1 maxzeile{"
  5703. "2dup get aload pop setrgbcolor "
  5704. "2 index over get bisumme zhkaestchen mul div 0.8 mul "
  5705. "0.12 0 0 2swap rectfill "
  5706. "umrandung 2 index @ zahlimkaestchen "
  5707. "0.8 0.07 T"
  5708. "}for 2drop"
  5709. "}B"
  5710. "/anzeigen{" // beschreibung belegung
  5711. "S "
  5712. "beschrx beschry moveto beschrgr dup scale"
  5713. "{S show R 0 -0.27 rmoveto}forall "
  5714. "R "
  5715. "ph1a L{"
  5716. "S "
  5717. "0.4 -0.55 T ph2a over get exch linien "
  5718. "R"
  5719. "}for "
  5720. "ph1a L{"
  5721. "S "
  5722. "dup koordinate 1 sub T 0.8 dup scale over taste "
  5723. "R"
  5724. "}for pop "
  5725. "mitSummen{"
  5726. "fsum L{"
  5727. "dup 5 sub abs dup mf ge exch xf le and{"
  5728. "S "
  5729. "dup dup 5 lt{2}{1}? minx sub add -0.3 T "
  5730. "dup fsum @ fhkaestchen hkaestchen "
  5731. "0.15 -0.1 T 0.625 dup scale "
  5732. "dup bsum @ dup 18 20 bkaestchen "
  5733. "over dup 5 lt{0.4}{-0.4}? -0.15 T "
  5734. "5 sub abs dup mf ne{over 9 11 bkaestchen}if "
  5735. "rot 5 lt{-0.8}{0.8}? -0.08 T "
  5736. "xf ne{6 8 bkaestchen}{pop}? "
  5737. "R"
  5738. "}{pop}?"
  5739. "}for "
  5740. "gsum L{"
  5741. "dup zz mod dup minzeile ge exch maxzeile le and{"
  5742. "S "
  5743. "dup zz idiv " << weite << " mul 0.25 sub "
  5744. "over zz mod 1 sub T "
  5745. "90 rotate "
  5746. "dup gsum @ ghkaestchen hkaestchen "
  5747. "-0.1 -0.14 T 1.25 maxzeile minzeile sub 1 add div dup scale "
  5748. "zsum over get exch zz mod zsfarbe @ zkaestchen "
  5749. "R"
  5750. "}{pop}?"
  5751. "}for"
  5752. "}if"
  5753. "}B"
  5754. "/adirekt{" // belegung beschreibung--
  5755. "over ph1a ph2a setze "
  5756. "mitSummen{"
  5757. "ph1a fsum fingerhaeufigkeit "
  5758. "ph1a gsum gruppenhaeufigkeit "
  5759. "ph2a bsum bigrammhaeufigkeit "
  5760. "ph2a zsum zshaeufigkeit"
  5761. "}if "
  5762. "anzeigen"
  5763. "}B"
  5764. "/adiff{"
  5765. "ph1A ph2A setze over ph1a ph2a setze "
  5766. "mitSummen{"
  5767. "ph1a fsum fingerhaeufigkeit ph1a gsum gruppenhaeufigkeit "
  5768. "ph2a bsum bigrammhaeufigkeit ph2a zsum zshaeufigkeit "
  5769. "ph1A fsumA fingerhaeufigkeit ph1A gsumA gruppenhaeufigkeit "
  5770. "ph2A bsumA bigrammhaeufigkeit ph2A zsumA zshaeufigkeit "
  5771. "fsum fsumA submaxarrays gsum gsumA submaxarrays "
  5772. "bsum bsumA submaxmatrizen zsum zsumA submaxmatrizen "
  5773. "ph1a ph1A submaxarrays ph2a ph2A submaxmatrizen"
  5774. "}if "
  5775. "anzeigen"
  5776. "}B"
  5777. // Zwei Belegungen. (belegung1 beschr1 belegung2 beschr2 --)
  5778. "/an{S adirekt 0 4 skala div T adirekt showpage R}B"
  5779. // Differenz zweier Belegungen (belegung1 beschr1 belegung2 beschr2 --)
  5780. "/ad{S over exch 4 index adiff 0 4 skala div T adiff showpage R}B"
  5781. // Belegung und Differenz (belegung1 beschr1 belegung2 beschr2 --)
  5782. "/M{S 3 index adiff 0 4 skala div T adirekt showpage R}B"
  5783. // Zwei Belegungen oder ihre Differenz.
  5784. "/A{differenzen{ad}{an}?}B"
  5785. // Einzelne Belegung
  5786. "/E{S 0 2 T adirekt showpage grestore}B\n"
  5787. "%%EndProlog\n"
  5788. "%%BeginSetup\n"
  5789. "<</PageSize[842 595]>> setpagedevice "
  5790. "65 skala mul dup scale 0.5 1.7 T"
  5791. "/BSchrift schrift\n"
  5792. "%%EndSetup" << std::endl;
  5793. };
  5794.  
  5795. void
  5796. Grafik::
  5797. ausgabe(const belegung_t b){
  5798. ungerade = !ungerade;
  5799. if(ungerade){
  5800. seite++;
  5801. grafik << "%%Page: " << seite << " " << seite << "\n";
  5802. }
  5803. grafik << "(";
  5804. for(int i = 0; i < tastatur.nvariabel(); ++i)
  5805. grafik << kodierung.psencstr(b[i]);
  5806. grafik << ")[]";
  5807.  
  5808. if(!ungerade) grafik << "A" << std::endl;
  5809. }
  5810.  
  5811. Grafik::
  5812. ~Grafik(){
  5813. if(ungerade) grafik << "E\n";
  5814. grafik << "%%EOF" << std::endl;
  5815. }
  5816.  
  5817. //--------------- src/string_in_belegung.cc ---------------
  5818. //#include "string_in_belegung.hh"
  5819.  
  5820. //#include "Kodierung.hh"
  5821. //#include "utfhilfe.hh"
  5822. #include <iostream>
  5823.  
  5824. void string_in_belegung(const std::u32string& z, belegung_t b, bool* fest,
  5825. int nv, const Kodierung& kodierung)
  5826. {
  5827. char32_t gabs[ntaste];
  5828. for(auto& i : gabs) i = 0;
  5829. for(int i = 0; i < ntaste; ++i) b[i] = i;
  5830.  
  5831. const int l = z.size();
  5832. if(l < nv-1){
  5833. std::cerr << SPRACHE("Die Belegung '", "The layout '")
  5834. << utf32_in_ausgabe(z)
  5835. << SPRACHE("' hat ", "' has ")
  5836. << l << SPRACHE(" Zeichen, erwartet werden ",
  5837. " symbols, but expected are ")
  5838. << nv << "." << std::endl;
  5839. exit(1);
  5840. }
  5841.  
  5842. int sum = (nv*(nv-1))/2;
  5843. for(int i = 0; i < std::min(l, nv); ++i){
  5844. const auto p = kodierung.position(z[i]);
  5845. if(p.first == -1){
  5846. std::cerr << SPRACHE("Die Belegung '", "The layout '")
  5847. << utf32_in_ausgabe(z)
  5848. << SPRACHE("' enth" strAe "lt das unbekannte Zeichen '",
  5849. "' contains the unknown symbol '")
  5850. << utf32_in_ausgabe(z[i]) << "'." << std::endl;
  5851. exit(1);
  5852. }else if(gabs[p.first]){
  5853. std::cerr << SPRACHE("Die Belegung '", "The layout '")
  5854. << utf32_in_ausgabe(z)
  5855. << SPRACHE("' enth" strAe "lt '", "' contains '")
  5856. << utf32_in_ausgabe(z[i])
  5857. << SPRACHE("' mehrfach. ", "' multiple times.");
  5858. if(z[i] != gabs[p.first]){
  5859. std::cerr << SPRACHE(" Vorher wurde das gleichwertige Zeichen '",
  5860. " Previously, the equivalent symbol '")
  5861. << utf32_in_ausgabe(gabs[p.first])
  5862. << SPRACHE("' verwendet.", "' has been used.");
  5863. }
  5864.  
  5865. std::cerr << std::endl;
  5866. exit(1);
  5867. }else{
  5868. b[i] = p.first;
  5869. sum -= b[i];
  5870. gabs[p.first] = z[i];
  5871. fest[i] = (p.second != 0) && kodierung.txt(p.first, 0).length();
  5872. }
  5873. }
  5874.  
  5875. if(l < nv){
  5876. b[nv-1] = sum;
  5877. fest[nv-1] = false;
  5878. }
  5879. }
  5880.  
  5881. //--------------- src/Eingabestream.cc ---------------
  5882. //#include "Eingabestream.hh"
  5883.  
  5884. //#include "konstanten.hh"
  5885. //#include "utfhilfe.hh"
  5886. #include <iostream>
  5887.  
  5888. namespace {
  5889.  
  5890. constexpr char32_t cp1252extra[] =
  5891. U"\u20ac \u201a\u0192\u201e\u2026\u2020\u2021\u02c6\u2030\u0160"
  5892. U"\u2039\u0152 \u017d \u2018\u2019\u201c\u201d\u2022\u2013\u2014"
  5893. U"\u02dc\u2122\u0161\u203a\u0153 \u017e\u0178";
  5894.  
  5895. char32_t cp1252_in_utf32(const char*& s){
  5896. if(*s == 0) return 0;
  5897. const char32_t c = *s++ & 0xff;
  5898. if(c < 0x80 || c >= 0xA0) return c;
  5899. return cp1252extra[c-0x80];
  5900. }
  5901.  
  5902. double zehnhoch(unsigned n){
  5903. double fak = 1., mult = 10.;
  5904. while(n){
  5905. if(n & 1) fak *= mult;
  5906. n >>= 1;
  5907. mult *= mult;
  5908. }
  5909. return fak;
  5910. }
  5911.  
  5912. constexpr char32_t BOM = U'\uFEFF', CR = U'\u000D';
  5913. }
  5914.  
  5915.  
  5916. Eingabestream::
  5917. Eingabestream(const std::string& nam, bool utf8,
  5918. bool muss_existieren)
  5919. : name(nam), l(0), p(0), maxl(0), izeile(0), errpos(-1),
  5920. utf8ein(utf8), geaendert(false){
  5921. f.open(name.c_str());
  5922. if(muss_existieren && !f){
  5923. std::cerr << "'" << name
  5924. << SPRACHE("' ist nicht lesbar.", "' is not readable")
  5925. << std::endl;
  5926. exit(1);
  5927. }
  5928. }
  5929.  
  5930. Eingabestream::
  5931. ~Eingabestream()
  5932. { f.close(); }
  5933.  
  5934. // Lies nächstes Zeichen (einschliesslich Zeilenenden '\n'); falls Eingabe
  5935. // erschöpft ist gibt Null zurück.
  5936. char32_t
  5937. Eingabestream::lieszeichen(){
  5938. if(p < l) return buffer[p++];
  5939. if(!fuellen()) return 0;
  5940. return U'\n';
  5941. }
  5942.  
  5943. // Falls aus der aktuellen Zeile schon Zeichen gelesen wurden, fange eine
  5944. // neue an. Gib false zurück, wenn die Eingabe erschöpft ist.
  5945. bool
  5946. Eingabestream::neuezeile(){
  5947. errpos = -1;
  5948. if(!p && l) return true;
  5949. p = l;
  5950. return fuellen();
  5951. }
  5952. // Wie neuezeile, übergeht aber Kommentar- und Leerzeilen.
  5953. bool
  5954. Eingabestream::echte_neuezeile(){
  5955. while(neuezeile()){
  5956. zwischenraum_uebergehen();
  5957. if(p == l) continue;
  5958. if(ist(U'#')){ p = l; continue; }
  5959. return true;
  5960. }
  5961. return false;
  5962. }
  5963.  
  5964. size_t
  5965. Eingabestream::restzeichen() const
  5966. { return l-p; }
  5967.  
  5968. bool
  5969. Eingabestream::ist_zwischenraum() const
  5970. { return p < l && ::ist_zwischenraum(buffer[p]); }
  5971.  
  5972. bool
  5973. Eingabestream::ist_ziffer() const
  5974. { return p < l && ::ist_ziffer(buffer[p]); }
  5975.  
  5976. // Ist aktuelles Zeichen in aktueller Zeile gleich dem übergebenen?
  5977. bool Eingabestream::ist(char32_t c) const { return p < l && c == buffer[p]; }
  5978.  
  5979. void
  5980. Eingabestream::zwischenraum_uebergehen()
  5981. { while(ist_zwischenraum()) ++p; }
  5982.  
  5983. void
  5984. Eingabestream::uebergehen()
  5985. { if(p < l) ++p; }
  5986.  
  5987. char32_t
  5988. Eingabestream::lies_in_zeile()
  5989. { return p < l ? buffer[p++] : 0; }
  5990.  
  5991. bool
  5992. Eingabestream::zeilenende(){
  5993. zwischenraum_uebergehen();
  5994. errpos = p;
  5995. return p == l;
  5996. }
  5997.  
  5998. bool
  5999. Eingabestream::hole_wort(std::u32string& wert){
  6000. wert.resize(0);
  6001. zwischenraum_uebergehen();
  6002. errpos = p;
  6003. if(p >= l) return false;
  6004. if(ist(U'#')){ p = l; return false; }
  6005. while(p < l && !ist_zwischenraum()) wert.push_back(buffer[p++]);
  6006. return true;
  6007. }
  6008.  
  6009. bool
  6010. Eingabestream::hole_flag(bool& wert){
  6011. zwischenraum_uebergehen();
  6012. errpos = p;
  6013. if(p >= l) return false;
  6014. wert = ist(U'+');
  6015. if(wert || ist(U'-')){ ++p; return p == l || ist_zwischenraum(); }
  6016. return false;
  6017. }
  6018.  
  6019. bool
  6020. Eingabestream::hole_string(std::u32string& wert){
  6021. wert.resize(0);
  6022. zwischenraum_uebergehen();
  6023. errpos = p;
  6024. if(p+1 >= l) return false;
  6025. const char32_t ende = buffer[p++];
  6026. while(p < l && buffer[p] != ende) wert.push_back(buffer[p++]);
  6027. if(p >= l) return false;
  6028. ++p;
  6029. return true;
  6030. }
  6031.  
  6032. bool Eingabestream::encoding_geaendert() const { return geaendert; }
  6033.  
  6034. [[noreturn]] void
  6035. Eingabestream::fehler(size_t off) const {
  6036. const std::string o = name+SPRACHE(", Zeile ", ", row ")+
  6037. std::to_string(izeile)+": ";
  6038. std::cerr << o << zeile << std::endl;
  6039. if(errpos >=0){
  6040. size_t n = o.length()+errpos+off;
  6041. for(size_t i = 0; i < n; ++i)
  6042. std::cerr << ".";
  6043. std::cerr << "^" << std::endl;
  6044. }
  6045. exit(1);
  6046. }
  6047.  
  6048. size_t
  6049. Eingabestream::aktuelle_zeile() const
  6050. { return izeile; }
  6051.  
  6052. const std::string&
  6053. Eingabestream::aktuelles_file() const
  6054. { return name; }
  6055.  
  6056. bool
  6057. Eingabestream::hole_zahl(double& wert){
  6058. zwischenraum_uebergehen();
  6059. errpos = p;
  6060. wert = 0;
  6061. if(p >= l) return false;
  6062.  
  6063. double sign = 1.;
  6064. if(buffer[p] == U'-'){
  6065. sign = -1.; ++p;
  6066. }else if(buffer[p] == U'+') ++p;
  6067.  
  6068. int nk = 0, ev = 0, es = 1;
  6069. bool nachkomma = false, exponent = false, zf = false;
  6070. for(; p < l && !ist_zwischenraum(); ++p){
  6071. if(ist_ziffer()){
  6072. const double val = buffer[p]-U'0';
  6073. if(exponent){
  6074. ev = ev*10+val;
  6075. }else{
  6076. wert = wert*10.+val;
  6077. if(nachkomma) ++nk;
  6078. zf = true;
  6079. }
  6080. }else if(buffer[p] == U'.' || buffer[p] == U','){
  6081. if(exponent || nachkomma) return false;
  6082. nachkomma = true;
  6083. }else if(buffer[p] == U'e' || buffer[p] == U'E'){
  6084. if(exponent) return false;
  6085. if(p+1 == l) return false;
  6086. if(buffer[p+1] == '-'){
  6087. es = -1.; ++p;
  6088. }else if(buffer[p+1] == '+') ++p;
  6089. if(p+1 == l) return false;
  6090. ++p;
  6091. if(!ist_ziffer()) return false;
  6092. ev = buffer[p]-U'0';
  6093. exponent = true;
  6094. }else{
  6095. return false;
  6096. }
  6097. }
  6098. ev = es*ev-nk;
  6099. const double e10 = sign*zehnhoch(std::abs(ev));
  6100. wert = ev < 0 ? wert/e10 : wert*e10;
  6101. return zf;
  6102. }
  6103.  
  6104. bool
  6105. Eingabestream::fuellen(){
  6106. if(p < l) return true; // Buffer nicht leer.
  6107. p = l = 0;
  6108. buffer.resize(0); buffer.reserve(maxl);
  6109. if(!f || f.rdstate() & std::ios::eofbit) return false;
  6110. // Das \n am Zeilenende ist nicht enthalten.
  6111. std::getline(f, zeile);
  6112. ++izeile;
  6113.  
  6114. const char* cp = zeile.c_str();
  6115. if(utf8ein){
  6116. bool reinterpret = false;
  6117. while(*cp){
  6118. const char32_t c = utf8_in_utf32(cp, reinterpret);
  6119. if(reinterpret){
  6120. l = 0; buffer.resize(0); buffer.reserve(maxl);
  6121. geaendert = true;
  6122. return false;
  6123. }
  6124. if(c != BOM && c != CR){ // wegen CP/M und dergleichen
  6125. buffer.push_back(c);
  6126. ++l;
  6127. }
  6128. }
  6129. }else{
  6130. while(*cp){
  6131. buffer.push_back(cp1252_in_utf32(cp));
  6132. ++l;
  6133. }
  6134. }
  6135.  
  6136. if(l > maxl) maxl = l;
  6137. return true;
  6138. }
  6139.  
  6140. double
  6141. hole_zahl(Eingabestream& f, double rmin, double rmax){
  6142. double w;
  6143. if(f.hole_zahl(w)){
  6144. if(w < rmin || w > rmax){
  6145. std::cerr << w
  6146. << SPRACHE(" ist ausserhalb des erlaubten Wertebereichs [",
  6147. " is not within the allowed range of values [")
  6148. << rmin << ", " << rmax << "]." << std::endl;
  6149. }else return w;
  6150. }else{
  6151. std::cerr << SPRACHE("Eine Zahl wurde erwartet, jedoch nicht gefunden.",
  6152. "A number has been expected, but none was found.")
  6153. << std::endl;
  6154. }
  6155. f.fehler();
  6156. }
  6157.  
  6158. void
  6159. pruefe_leer_dann_N(Eingabestream& f, size_t N){
  6160. const bool rest = f.restzeichen() == N+1;
  6161. const bool zwischen = f.ist_zwischenraum();
  6162. if(zwischen && rest) return;
  6163.  
  6164. std::cerr << SPRACHE("Nach der Zahl werden ein Leerzeichen und genau ",
  6165. "After the number, one space character and exactly ")
  6166. << N << SPRACHE(" weitere Zeichen erwartet.",
  6167. " additional characters are expected.")
  6168. << std::endl;
  6169. f.fehler();
  6170. }
  6171.  
  6172. //--------------- src/Statistik.cc ---------------
  6173. //#include "Statistik.hh"
  6174.  
  6175. //#include "Aufwandstabelle.hh"
  6176. //#include "Haeufigkeit.hh"
  6177. //#include "Kodierung.hh"
  6178. //#include "Tastatur.hh"
  6179.  
  6180. Statistik::
  6181. Statistik(const belegung_t b, const Tastatur& tastatur,
  6182. const Kodierung& kodierung, const Haeufigkeit& h,
  6183. const Aufwandstabelle& a, const double ngrammakkumlimit[3])
  6184. {
  6185. for(int i = 0; i < ntaste; ++i){
  6186. const int fi = tastatur.finger(i);
  6187. const int zi = b[i], sti = tastatur.shifttaste(i);
  6188. const int fx = tastatur.finger_index(i);
  6189. const int s = fi > 0;
  6190. const int sfi = tastatur.finger(sti);
  6191. const int ss = sfi > 0;
  6192. const int sfx = tastatur.finger_index(sti);
  6193. const int z = tastatur.zeile(i);
  6194. const int sz = tastatur.zeile(sti);
  6195.  
  6196. mitfinger[fx] = mitfinger[sfx] = true;
  6197.  
  6198. haeufigkeit_t h01 = 0;
  6199. for(int ei = 0; ei < nebene; ++ei){
  6200. aeinzel += a(i,ei)*h(zi,ei);
  6201. if(fx < nfinger) h01 += h(zi,ei);
  6202. }
  6203. const haeufigkeit_t h1 = sfx < nfinger ? h(zi,1) : 0;
  6204. h1tot += h01+h1;
  6205. hpos[s][z] += h01;
  6206. hpos[ss][sz] += h1;
  6207. hfinger[fx] += h01;
  6208. hfinger[sfx] += h1;
  6209. hlinks += (1-s)*h01+(1-ss)*h1;
  6210. hslinks += (1-ss)*h1;
  6211. hrechts += ss*h1+s*h01;
  6212. hsrechts += ss*h1;
  6213.  
  6214. for(int j = 0; j < ntaste; ++j){
  6215. if(tastatur.kategorie(i,j) == kategorie_t::MitUndefDaumen) continue;
  6216. const int zj = b[j];
  6217. const int stj= tastatur.shifttaste(j), sfy= tastatur.finger_index(stj);
  6218. const int fy = tastatur.finger_index(j);
  6219. const int fj = tastatur.finger(j);
  6220. const int f2[2] = { fj, tastatur.finger(stj) };
  6221. const int t2[2] = { j, stj }, fi2[2] = { fy, sfy };
  6222.  
  6223. // sbb und sbs (siehe den ganz langen Kommentar oben) sind ein
  6224. // Mittelding zwischen Bigrammen und Trigammen. Für die Ausgabe
  6225. // weisen wir sie getrennt und mit der Vorsatz "Shift-" aus.
  6226. for(int ej = 0; ej < nebene2; ++ej){
  6227. // Shift-Bigramme (sbb und sbs)
  6228. const haeufigkeit_t h2 = h(zi,1,zj,ej);
  6229. hs[tastatur.kategorie(sti,t2[ej])] += h2;
  6230. hs2tot += h2;
  6231.  
  6232. const std::vector<int> sbi = { sti, t2[ej] };
  6233. for(const int ub : tastatur.benutzerkategorie(sbi))
  6234. hs_benutzer[ub] += h2;
  6235.  
  6236. if(std::abs(sfi-f2[ej]) == 1){
  6237. hsnachbar += h2;
  6238. hsnachbar1[sti-ntaste] += h2;
  6239. if(std::abs(sz-tastatur.zeile(t2[ej])) > 1)
  6240. hsnachbar2[sti-ntaste] += h2;
  6241. }else if(tastatur.kategorie(sti,t2[ej]) == kategorie_t::Kollision){
  6242. hskollision1[sti-ntaste] += h2;
  6243. if(tastatur.distanz(sti,t2[ej]) >= 2)
  6244. hskollision2[sti-ntaste] += h2;
  6245. }
  6246.  
  6247. if(h2 > 0 && ngrammakkumlimit[1] > 0 &&
  6248. tastatur.istHandwiederholung(sti,t2[ej])){
  6249. std::string bg_typ = kodierung.txt(zi,1)+kodierung.txt(zj,ej)
  6250. +" : Shift-"+tastatur.kategorie_lang(sti, t2[ej]);
  6251. hrel[1][ss] += h2;
  6252. const std::pair<haeufigkeit_t, std::string> hw(h2, bg_typ);
  6253. ngramm[1][ss].insert(hw);
  6254. }
  6255.  
  6256. for(int ei = 0; ei < nebene; ++ei){
  6257. // Bigramme: bb in B1 und B2 (ej == 0), bs in B3 und B4 (ej == 1)
  6258. const haeufigkeit_t h2 = h(zi,ei,zj,ej);
  6259. hk[tastatur.kategorie(i,t2[ej])] += h2;
  6260. h2tot+= h2;
  6261. if(std::abs(f2[ej]-fi) == 1){
  6262. hnachbar += h2;
  6263. hnachbar1[(fx+fi2[ej]-1)/2] += h2;
  6264. if(std::abs(z-tastatur.zeile(t2[ej])) > 1)
  6265. hnachbar2[(fx+fi2[ej]-1)/2] += h2;
  6266. }else if(tastatur.kategorie(i,t2[ej]) == kategorie_t::Kollision){
  6267. assert(fx < nfinger);
  6268. hkollision1[fx] += h2;
  6269. if(tastatur.distanz(i,t2[ej]) >= 2) hkollision2[fx] += h2;
  6270. }
  6271.  
  6272. const std::vector<int> bi = {i, t2[ej] };
  6273. for(const int ub : tastatur.benutzerkategorie(bi))
  6274. hk_benutzer[ub] += h2;
  6275.  
  6276. if(ej){
  6277. // bsb, vom Tippen her Trigramme.
  6278. const haeufigkeit_t h3 = h(zi,ei,zj,ej);
  6279. // Wir interessieren uns nicht für einfache Handwechsel, und
  6280. // kein Handwechsel kann hier nicht vorkommen.
  6281. if(tastatur.kategorie(i,stj) == kategorie_t::Handwechsel){
  6282. hi2[tastatur.kategorie(i,j)] += h3; // bsb in B3 und B4
  6283. hdoppelhw += h3;
  6284. }
  6285. h3tot += h3;
  6286.  
  6287. const std::vector<int> tri = {i, stj, j };
  6288. for(const int ub : tastatur.benutzerkategorie(tri))
  6289. ht_benutzer[ub] += h2;
  6290. }
  6291. }
  6292.  
  6293. // bb und bs. Die hatten wir oben schonmal, wir müssen hier aber
  6294. // darauf achten, dass wir nicht unterscheiden, ob das erste b ein
  6295. // Grossbuchstabe ist oder nicht, denn in beiden Fällen handelt es
  6296. // sich um dasselbe Tastenbigramm (das unterscheidende Shift liegt
  6297. // vor diesem).
  6298. const haeufigkeit_t hij = h(zi,0,zj,ej)+h(zi,1,zj,ej);
  6299. if(hij > 0 && ngrammakkumlimit[0] > 0 &&
  6300. tastatur.istHandwiederholung(i, t2[ej])){
  6301. // Für ej == 1 steht der Grossbuchstabe in diesem Bigramm für
  6302. // die Shifttaste die man zu seine Eingabe braucht.
  6303. std::string bg_typ = kodierung.txt(zi,0)+kodierung.txt(zj,ej)
  6304. +" : "+tastatur.kategorie_lang(i, t2[ej]);
  6305. hrel[0][s] += hij;
  6306. const std::pair<haeufigkeit_t, std::string> hw(hij, bg_typ);
  6307. ngramm[0][s].insert(hw);
  6308. }
  6309. }
  6310.  
  6311. if(h.mit_trigrammen()){
  6312. for(int k = 0; k < ntaste; ++k){
  6313. if(tastatur.finger(k) == finger_t::EinerDerDaumen) continue;
  6314. const int zk = b[k];
  6315.  
  6316. // Die normalen Trigramme.
  6317. const int stk = tastatur.shifttaste(k), t3[2] = { k, stk };
  6318. const haeufigkeit_t h3[2] = { h.tri(zi,zj,zk,0),
  6319. h.tri(zi,zj,zk,1) };
  6320. h3tot += h3[0]+h3[1];
  6321.  
  6322. for(int ek = 0; ek < 2; ++ek){
  6323. if(tastatur.kategorie(i,j) == kategorie_t::Handwechsel){
  6324. // ek == 0: bbb in T1 und T2; ek == 1: bbs in T5 und T6
  6325. hi2[tastatur.kategorie(i,t3[ek])] += h3[ek];
  6326. }else{
  6327. if(tastatur.kategorie(i,t3[ek]) !=
  6328. kategorie_t::Handwechsel){
  6329. if(tastatur.istWippe(i,j,t3[ek])) hwippe += h3[ek];
  6330. hi0[tastatur.kategorie(i,t3[ek])] += h3[ek];
  6331. }
  6332. }
  6333.  
  6334. const std::vector<int> tri = {i, j, t3[ek] };
  6335. for(const int ub : tastatur.benutzerkategorie(tri))
  6336. ht_benutzer[ub] += h3[ek];
  6337.  
  6338. const int wdh =
  6339. (tastatur.kategorie(i,j) == kategorie_t::Handwechsel)+
  6340. (tastatur.kategorie(j,t3[ek]) == kategorie_t::Handwechsel);
  6341. if(h3[ek] <= 0 || wdh == 1) continue;
  6342.  
  6343. if(wdh == 2) hdoppelhw += h3[ek];
  6344. else hkeinhw += h3[ek];
  6345.  
  6346. if(ngrammakkumlimit[2] > 0){
  6347. std::string tri_typ = kodierung.txt(zi,0)
  6348. +kodierung.txt(zj,0)+kodierung.txt(zk,ek)+" : ";
  6349. if(wdh == 2){
  6350. // doppelter Handwechsel: Charakterisiert durch erste
  6351. // und erste und letzte Taste
  6352. tri_typ += SPRACHE("Indirekt-", "indirect ")
  6353. +tastatur.kategorie_lang(i, t3[ek]);
  6354. }else{
  6355. // Sonst durch die beiden Bigramme charakterisiert.
  6356. tri_typ += tastatur.kategorie_lang(i, j)
  6357. +" + "+tastatur.kategorie_lang(j, t3[ek]);
  6358. if(tastatur.istWippe(i,j,t3[ek]))
  6359. tri_typ += SPRACHE(" (Wippe)", " (seesaw)");
  6360. }
  6361. const int s = wdh/2;
  6362. const std::pair<haeufigkeit_t, std::string> tri(h3[ek],
  6363. tri_typ);
  6364. hrel[2][s] += h3[ek];
  6365. ngramm[2][s].insert(tri);
  6366. }
  6367. }
  6368. }
  6369. }
  6370. }
  6371. }
  6372.  
  6373. const akkumuations_t sk1 = 100./h1tot;
  6374. hlinks *= sk1;
  6375. hrechts *= sk1;
  6376. hslinks *= sk1;
  6377. hsrechts *= sk1;
  6378. for(int s = 0; s < 2; ++s) for(auto& x : hpos[s]) x *= sk1;
  6379. for(int i = 0; i < nfinger; ++i) hfinger[i] *= sk1;
  6380.  
  6381. const akkumuations_t sk2 = 100./h2tot;
  6382. hnachbar *= sk2;
  6383. for(auto& x : hk) x *= sk2;
  6384. for(auto& i : hk_benutzer) i.second *= sk2;
  6385. for(int i = 0; i < nfinger; ++i){
  6386. hkollision1[i] *= sk2;
  6387. hkollision2[i] *= sk2;
  6388. hnachbar1[i] *= sk2;
  6389. hnachbar2[i] *= sk2;
  6390. }
  6391.  
  6392. // ssk2 == 0 kommt durchaus vor; vemeide NaNs.
  6393. const akkumuations_t ssk2 = hs2tot > 0 ? 100./hs2tot : 0;
  6394. hsnachbar *= ssk2;
  6395. for(auto& x : hs) x *= ssk2;
  6396. for(auto& i : hs_benutzer) i.second *= ssk2;
  6397. for(int i = 0; i < nshift; ++i){
  6398. hskollision1[i] *= ssk2;
  6399. hskollision2[i] *= ssk2;
  6400. hsnachbar1[i] *= ssk2;
  6401. hsnachbar2[i] *= ssk2;
  6402. }
  6403.  
  6404. const akkumuations_t sk3 = h3tot > 0 ? 100./h3tot : 0;
  6405. hkeinhw *= sk3;
  6406. hdoppelhw *= sk3;
  6407. hwippe *= sk3;
  6408. for(auto& x : hi0) x *= sk3;
  6409. for(auto& x : hi2) x *= sk3;
  6410. for(auto& i : ht_benutzer) i.second *= sk3;
  6411. }
  6412.  
  6413. //--------------- src/Unicode.cc ---------------
  6414. //#include "Unicode.hh"
  6415.  
  6416. namespace {
  6417. // Um vom eingestellten Locale unabhängig zu werden, definieren wir unsere
  6418. // Zeichenklassifikation selber.
  6419. constexpr char32_t kleinbuchstaben[] =
  6420. U"\u0061\u0062\u0063\u0064\u0065\u0066\u0067\u0068\u0069\u006A\u006B"
  6421. U"\u006C\u006D\u006E\u006F\u0070\u0071\u0072\u0073\u0074\u0075\u0076"
  6422. U"\u0077\u0078\u0079\u007A\u00E0\u00E1\u00E2\u00E3\u00E4\u00E5\u00E6"
  6423. U"\u00E7\u00E8\u00E9\u00EA\u00EB\u00EC\u00ED\u00EE\u00EF\u00F0\u00F1"
  6424. U"\u00F2\u00F3\u00F4\u00F5\u00F6\u00F8\u00F9\u00FA\u00FB\u00FC\u00FD"
  6425. U"\u00FE\u0101\u0103\u0105\u0107\u0109\u010B\u010D\u010F\u0111\u0113"
  6426. U"\u0115\u0117\u0119\u011B\u011D\u011F\u0121\u0123\u0125\u0127\u0129"
  6427. U"\u012B\u012D\u012F\u0069\u0133\u0135\u0137\u013A\u013C\u013E\u0140"
  6428. U"\u0142\u0144\u0146\u0148\u014B\u014D\u014F\u0151\u0153\u0155\u0157"
  6429. U"\u0159\u015B\u015D\u015F\u0161\u0163\u0165\u0167\u0169\u016B\u016D"
  6430. U"\u016F\u0171\u0173\u0175\u0177\u00FF\u017A\u017C\u017E\u0253\u0183"
  6431. U"\u0185\u0254\u0188\u0256\u0257\u018C\u01DD\u0259\u025B\u0192\u0260"
  6432. U"\u0263\u0269\u0268\u0199\u026F\u0272\u0275\u01A1\u01A3\u01A5\u0280"
  6433. U"\u01A8\u0283\u01AD\u0288\u01B0\u028A\u028B\u01B4\u01B6\u0292\u01B9"
  6434. U"\u01BD\u01C6\u01C9\u01CC\u01CE\u01D0\u01D2\u01D4\u01D6\u01D8\u01DA"
  6435. U"\u01DC\u01DF\u01E1\u01E3\u01E5\u01E7\u01E9\u01EB\u01ED\u01EF\u01F3"
  6436. U"\u01F5\u0195\u01BF\u01F9\u01FB\u01FD\u01FF\u0201\u0203\u0205\u0207"
  6437. U"\u0209\u020B\u020D\u020F\u0211\u0213\u0215\u0217\u0219\u021B\u021D"
  6438. U"\u021F\u019E\u0223\u0225\u0227\u0229\u022B\u022D\u022F\u0231\u0233"
  6439. U"\u2C65\u023C\u019A\u2C66\u0242\u0180\u0289\u028C\u0247\u0249\u024B"
  6440. U"\u024D\u024F\u0371\u0373\u0377\u03F3\u03AC\u03AD\u03AE\u03AF\u03CC"
  6441. U"\u03CD\u03CE\u03B1\u03B2\u03B3\u03B4\u03B5\u03B6\u03B7\u03B8\u03B9"
  6442. U"\u03BA\u03BB\u03BC\u03BD\u03BE\u03BF\u03C0\u03C1\u03C3\u03C4\u03C5"
  6443. U"\u03C6\u03C7\u03C8\u03C9\u03CA\u03CB\u03D7\u03D9\u03DB\u03DD\u03DF"
  6444. U"\u03E1\u03E3\u03E5\u03E7\u03E9\u03EB\u03ED\u03EF\u03B8\u03F8\u03F2"
  6445. U"\u03FB\u037B\u037C\u037D\u0450\u0451\u0452\u0453\u0454\u0455\u0456"
  6446. U"\u0457\u0458\u0459\u045A\u045B\u045C\u045D\u045E\u045F\u0430\u0431"
  6447. U"\u0432\u0433\u0434\u0435\u0436\u0437\u0438\u0439\u043A\u043B\u043C"
  6448. U"\u043D\u043E\u043F\u0440\u0441\u0442\u0443\u0444\u0445\u0446\u0447"
  6449. U"\u0448\u0449\u044A\u044B\u044C\u044D\u044E\u044F\u0461\u0463\u0465"
  6450. U"\u0467\u0469\u046B\u046D\u046F\u0471\u0473\u0475\u0477\u0479\u047B"
  6451. U"\u047D\u047F\u0481\u048B\u048D\u048F\u0491\u0493\u0495\u0497\u0499"
  6452. U"\u049B\u049D\u049F\u04A1\u04A3\u04A5\u04A7\u04A9\u04AB\u04AD\u04AF"
  6453. U"\u04B1\u04B3\u04B5\u04B7\u04B9\u04BB\u04BD\u04BF\u04CF\u04C2\u04C4"
  6454. U"\u04C6\u04C8\u04CA\u04CC\u04CE\u04D1\u04D3\u04D5\u04D7\u04D9\u04DB"
  6455. U"\u04DD\u04DF\u04E1\u04E3\u04E5\u04E7\u04E9\u04EB\u04ED\u04EF\u04F1"
  6456. U"\u04F3\u04F5\u04F7\u04F9\u04FB\u04FD\u04FF\u0501\u0503\u0505\u0507"
  6457. U"\u0509\u050B\u050D\u050F\u0511\u0513\u0515\u0517\u0519\u051B\u051D"
  6458. U"\u051F\u0521\u0523\u0525\u0527\u0529\u052B\u052D\u052F\u0561\u0562"
  6459. U"\u0563\u0564\u0565\u0566\u0567\u0568\u0569\u056A\u056B\u056C\u056D"
  6460. U"\u056E\u056F\u0570\u0571\u0572\u0573\u0574\u0575\u0576\u0577\u0578"
  6461. U"\u0579\u057A\u057B\u057C\u057D\u057E\u057F\u0580\u0581\u0582\u0583"
  6462. U"\u0584\u0585\u0586\u2D00\u2D01\u2D02\u2D03\u2D04\u2D05\u2D06\u2D07"
  6463. U"\u2D08\u2D09\u2D0A\u2D0B\u2D0C\u2D0D\u2D0E\u2D0F\u2D10\u2D11\u2D12"
  6464. U"\u2D13\u2D14\u2D15\u2D16\u2D17\u2D18\u2D19\u2D1A\u2D1B\u2D1C\u2D1D"
  6465. U"\u2D1E\u2D1F\u2D20\u2D21\u2D22\u2D23\u2D24\u2D25\u2D27\u2D2D\uAB70"
  6466. U"\uAB71\uAB72\uAB73\uAB74\uAB75\uAB76\uAB77\uAB78\uAB79\uAB7A\uAB7B"
  6467. U"\uAB7C\uAB7D\uAB7E\uAB7F\uAB80\uAB81\uAB82\uAB83\uAB84\uAB85\uAB86"
  6468. U"\uAB87\uAB88\uAB89\uAB8A\uAB8B\uAB8C\uAB8D\uAB8E\uAB8F\uAB90\uAB91"
  6469. U"\uAB92\uAB93\uAB94\uAB95\uAB96\uAB97\uAB98\uAB99\uAB9A\uAB9B\uAB9C"
  6470. U"\uAB9D\uAB9E\uAB9F\uABA0\uABA1\uABA2\uABA3\uABA4\uABA5\uABA6\uABA7"
  6471. U"\uABA8\uABA9\uABAA\uABAB\uABAC\uABAD\uABAE\uABAF\uABB0\uABB1\uABB2"
  6472. U"\uABB3\uABB4\uABB5\uABB6\uABB7\uABB8\uABB9\uABBA\uABBB\uABBC\uABBD"
  6473. U"\uABBE\uABBF\u13F8\u13F9\u13FA\u13FB\u13FC\u13FD\u10D0\u10D1\u10D2"
  6474. U"\u10D3\u10D4\u10D5\u10D6\u10D7\u10D8\u10D9\u10DA\u10DB\u10DC\u10DD"
  6475. U"\u10DE\u10DF\u10E0\u10E1\u10E2\u10E3\u10E4\u10E5\u10E6\u10E7\u10E8"
  6476. U"\u10E9\u10EA\u10EB\u10EC\u10ED\u10EE\u10EF\u10F0\u10F1\u10F2\u10F3"
  6477. U"\u10F4\u10F5\u10F6\u10F7\u10F8\u10F9\u10FA\u10FD\u10FE\u10FF\u1E01"
  6478. U"\u1E03\u1E05\u1E07\u1E09\u1E0B\u1E0D\u1E0F\u1E11\u1E13\u1E15\u1E17"
  6479. U"\u1E19\u1E1B\u1E1D\u1E1F\u1E21\u1E23\u1E25\u1E27\u1E29\u1E2B\u1E2D"
  6480. U"\u1E2F\u1E31\u1E33\u1E35\u1E37\u1E39\u1E3B\u1E3D\u1E3F\u1E41\u1E43"
  6481. U"\u1E45\u1E47\u1E49\u1E4B\u1E4D\u1E4F\u1E51\u1E53\u1E55\u1E57\u1E59"
  6482. U"\u1E5B\u1E5D\u1E5F\u1E61\u1E63\u1E65\u1E67\u1E69\u1E6B\u1E6D\u1E6F"
  6483. U"\u1E71\u1E73\u1E75\u1E77\u1E79\u1E7B\u1E7D\u1E7F\u1E81\u1E83\u1E85"
  6484. U"\u1E87\u1E89\u1E8B\u1E8D\u1E8F\u1E91\u1E93\u1E95\u00DF\u1EA1\u1EA3"
  6485. U"\u1EA5\u1EA7\u1EA9\u1EAB\u1EAD\u1EAF\u1EB1\u1EB3\u1EB5\u1EB7\u1EB9"
  6486. U"\u1EBB\u1EBD\u1EBF\u1EC1\u1EC3\u1EC5\u1EC7\u1EC9\u1ECB\u1ECD\u1ECF"
  6487. U"\u1ED1\u1ED3\u1ED5\u1ED7\u1ED9\u1EDB\u1EDD\u1EDF\u1EE1\u1EE3\u1EE5"
  6488. U"\u1EE7\u1EE9\u1EEB\u1EED\u1EEF\u1EF1\u1EF3\u1EF5\u1EF7\u1EF9\u1EFB"
  6489. U"\u1EFD\u1EFF\u1F00\u1F01\u1F02\u1F03\u1F04\u1F05\u1F06\u1F07\u1F10"
  6490. U"\u1F11\u1F12\u1F13\u1F14\u1F15\u1F20\u1F21\u1F22\u1F23\u1F24\u1F25"
  6491. U"\u1F26\u1F27\u1F30\u1F31\u1F32\u1F33\u1F34\u1F35\u1F36\u1F37\u1F40"
  6492. U"\u1F41\u1F42\u1F43\u1F44\u1F45\u1F51\u1F53\u1F55\u1F57\u1F60\u1F61"
  6493. U"\u1F62\u1F63\u1F64\u1F65\u1F66\u1F67\u1FB0\u1FB1\u1F70\u1F71\u1F72"
  6494. U"\u1F73\u1F74\u1F75\u1FD0\u1FD1\u1F76\u1F77\u1FE0\u1FE1\u1F7A\u1F7B"
  6495. U"\u1FE5\u1F78\u1F79\u1F7C\u1F7D\u03C9\u006B\u00E5\u214E\u2184\u2C30"
  6496. U"\u2C31\u2C32\u2C33\u2C34\u2C35\u2C36\u2C37\u2C38\u2C39\u2C3A\u2C3B"
  6497. U"\u2C3C\u2C3D\u2C3E\u2C3F\u2C40\u2C41\u2C42\u2C43\u2C44\u2C45\u2C46"
  6498. U"\u2C47\u2C48\u2C49\u2C4A\u2C4B\u2C4C\u2C4D\u2C4E\u2C4F\u2C50\u2C51"
  6499. U"\u2C52\u2C53\u2C54\u2C55\u2C56\u2C57\u2C58\u2C59\u2C5A\u2C5B\u2C5C"
  6500. U"\u2C5D\u2C5E\u2C61\u026B\u1D7D\u027D\u2C68\u2C6A\u2C6C\u0251\u0271"
  6501. U"\u0250\u0252\u2C73\u2C76\u023F\u0240\u2C81\u2C83\u2C85\u2C87\u2C89"
  6502. U"\u2C8B\u2C8D\u2C8F\u2C91\u2C93\u2C95\u2C97\u2C99\u2C9B\u2C9D\u2C9F"
  6503. U"\u2CA1\u2CA3\u2CA5\u2CA7\u2CA9\u2CAB\u2CAD\u2CAF\u2CB1\u2CB3\u2CB5"
  6504. U"\u2CB7\u2CB9\u2CBB\u2CBD\u2CBF\u2CC1\u2CC3\u2CC5\u2CC7\u2CC9\u2CCB"
  6505. U"\u2CCD\u2CCF\u2CD1\u2CD3\u2CD5\u2CD7\u2CD9\u2CDB\u2CDD\u2CDF\u2CE1"
  6506. U"\u2CE3\u2CEC\u2CEE\u2CF3\uA641\uA643\uA645\uA647\uA649\uA64B\uA64D"
  6507. U"\uA64F\uA651\uA653\uA655\uA657\uA659\uA65B\uA65D\uA65F\uA661\uA663"
  6508. U"\uA665\uA667\uA669\uA66B\uA66D\uA681\uA683\uA685\uA687\uA689\uA68B"
  6509. U"\uA68D\uA68F\uA691\uA693\uA695\uA697\uA699\uA69B\uA723\uA725\uA727"
  6510. U"\uA729\uA72B\uA72D\uA72F\uA733\uA735\uA737\uA739\uA73B\uA73D\uA73F"
  6511. U"\uA741\uA743\uA745\uA747\uA749\uA74B\uA74D\uA74F\uA751\uA753\uA755"
  6512. U"\uA757\uA759\uA75B\uA75D\uA75F\uA761\uA763\uA765\uA767\uA769\uA76B"
  6513. U"\uA76D\uA76F\uA77A\uA77C\u1D79\uA77F\uA781\uA783\uA785\uA787\uA78C"
  6514. U"\u0265\uA791\uA793\uA797\uA799\uA79B\uA79D\uA79F\uA7A1\uA7A3\uA7A5"
  6515. U"\uA7A7\uA7A9\u0266\u025C\u0261\u026C\u026A\u029E\u0287\u029D\uAB53"
  6516. U"\uA7B5\uA7B7\uA7B9\uA7BB\uA7BD\uA7BF\uA7C3\uA794\u0282\u1D8E\uFF41"
  6517. U"\uFF42\uFF43\uFF44\uFF45\uFF46\uFF47\uFF48\uFF49\uFF4A\uFF4B\uFF4C"
  6518. U"\uFF4D\uFF4E\uFF4F\uFF50\uFF51\uFF52\uFF53\uFF54\uFF55\uFF56\uFF57"
  6519. U"\uFF58\uFF59\uFF5A\U00010428\U00010429\U0001042A\U0001042B\U0001042C"
  6520. U"\U0001042D\U0001042E\U0001042F\U00010430\U00010431\U00010432\U00010433"
  6521. U"\U00010434\U00010435\U00010436\U00010437\U00010438\U00010439\U0001043A"
  6522. U"\U0001043B\U0001043C\U0001043D\U0001043E\U0001043F\U00010440\U00010441"
  6523. U"\U00010442\U00010443\U00010444\U00010445\U00010446\U00010447\U00010448"
  6524. U"\U00010449\U0001044A\U0001044B\U0001044C\U0001044D\U0001044E\U0001044F"
  6525. U"\U000104D8\U000104D9\U000104DA\U000104DB\U000104DC\U000104DD\U000104DE"
  6526. U"\U000104DF\U000104E0\U000104E1\U000104E2\U000104E3\U000104E4\U000104E5"
  6527. U"\U000104E6\U000104E7\U000104E8\U000104E9\U000104EA\U000104EB\U000104EC"
  6528. U"\U000104ED\U000104EE\U000104EF\U000104F0\U000104F1\U000104F2\U000104F3"
  6529. U"\U000104F4\U000104F5\U000104F6\U000104F7\U000104F8\U000104F9\U000104FA"
  6530. U"\U000104FB\U00010CC0\U00010CC1\U00010CC2\U00010CC3\U00010CC4\U00010CC5"
  6531. U"\U00010CC6\U00010CC7\U00010CC8\U00010CC9\U00010CCA\U00010CCB\U00010CCC"
  6532. U"\U00010CCD\U00010CCE\U00010CCF\U00010CD0\U00010CD1\U00010CD2\U00010CD3"
  6533. U"\U00010CD4\U00010CD5\U00010CD6\U00010CD7\U00010CD8\U00010CD9\U00010CDA"
  6534. U"\U00010CDB\U00010CDC\U00010CDD\U00010CDE\U00010CDF\U00010CE0\U00010CE1"
  6535. U"\U00010CE2\U00010CE3\U00010CE4\U00010CE5\U00010CE6\U00010CE7\U00010CE8"
  6536. U"\U00010CE9\U00010CEA\U00010CEB\U00010CEC\U00010CED\U00010CEE\U00010CEF"
  6537. U"\U00010CF0\U00010CF1\U00010CF2\U000118C0\U000118C1\U000118C2\U000118C3"
  6538. U"\U000118C4\U000118C5\U000118C6\U000118C7\U000118C8\U000118C9\U000118CA"
  6539. U"\U000118CB\U000118CC\U000118CD\U000118CE\U000118CF\U000118D0\U000118D1"
  6540. U"\U000118D2\U000118D3\U000118D4\U000118D5\U000118D6\U000118D7\U000118D8"
  6541. U"\U000118D9\U000118DA\U000118DB\U000118DC\U000118DD\U000118DE\U000118DF"
  6542. U"\U00016E60\U00016E61\U00016E62\U00016E63\U00016E64\U00016E65\U00016E66"
  6543. U"\U00016E67\U00016E68\U00016E69\U00016E6A\U00016E6B\U00016E6C\U00016E6D"
  6544. U"\U00016E6E\U00016E6F\U00016E70\U00016E71\U00016E72\U00016E73\U00016E74"
  6545. U"\U00016E75\U00016E76\U00016E77\U00016E78\U00016E79\U00016E7A\U00016E7B"
  6546. U"\U00016E7C\U00016E7D\U00016E7E\U00016E7F\U0001E922\U0001E923\U0001E924"
  6547. U"\U0001E925\U0001E926\U0001E927\U0001E928\U0001E929\U0001E92A\U0001E92B"
  6548. U"\U0001E92C\U0001E92D\U0001E92E\U0001E92F\U0001E930\U0001E931\U0001E932"
  6549. U"\U0001E933\U0001E934\U0001E935\U0001E936\U0001E937\U0001E938\U0001E939"
  6550. U"\U0001E93A\U0001E93B\U0001E93C\U0001E93D\U0001E93E\U0001E93F\U0001E940"
  6551. U"\U0001E941\U0001E942\U0001E943";
  6552.  
  6553. constexpr char32_t grossbuchstaben[] =
  6554. U"\u0041\u0042\u0043\u0044\u0045\u0046\u0047\u0048\u0049\u004A\u004B"
  6555. U"\u004C\u004D\u004E\u004F\u0050\u0051\u0052\u0053\u0054\u0055\u0056"
  6556. U"\u0057\u0058\u0059\u005A\u00C0\u00C1\u00C2\u00C3\u00C4\u00C5\u00C6"
  6557. U"\u00C7\u00C8\u00C9\u00CA\u00CB\u00CC\u00CD\u00CE\u00CF\u00D0\u00D1"
  6558. U"\u00D2\u00D3\u00D4\u00D5\u00D6\u00D8\u00D9\u00DA\u00DB\u00DC\u00DD"
  6559. U"\u00DE\u0100\u0102\u0104\u0106\u0108\u010A\u010C\u010E\u0110\u0112"
  6560. U"\u0114\u0116\u0118\u011A\u011C\u011E\u0120\u0122\u0124\u0126\u0128"
  6561. U"\u012A\u012C\u012E\u0130\u0132\u0134\u0136\u0139\u013B\u013D\u013F"
  6562. U"\u0141\u0143\u0145\u0147\u014A\u014C\u014E\u0150\u0152\u0154\u0156"
  6563. U"\u0158\u015A\u015C\u015E\u0160\u0162\u0164\u0166\u0168\u016A\u016C"
  6564. U"\u016E\u0170\u0172\u0174\u0176\u0178\u0179\u017B\u017D\u0181\u0182"
  6565. U"\u0184\u0186\u0187\u0189\u018A\u018B\u018E\u018F\u0190\u0191\u0193"
  6566. U"\u0194\u0196\u0197\u0198\u019C\u019D\u019F\u01A0\u01A2\u01A4\u01A6"
  6567. U"\u01A7\u01A9\u01AC\u01AE\u01AF\u01B1\u01B2\u01B3\u01B5\u01B7\u01B8"
  6568. U"\u01BC\u01C4\u01C7\u01CA\u01CD\u01CF\u01D1\u01D3\u01D5\u01D7\u01D9"
  6569. U"\u01DB\u01DE\u01E0\u01E2\u01E4\u01E6\u01E8\u01EA\u01EC\u01EE\u01F1"
  6570. U"\u01F4\u01F6\u01F7\u01F8\u01FA\u01FC\u01FE\u0200\u0202\u0204\u0206"
  6571. U"\u0208\u020A\u020C\u020E\u0210\u0212\u0214\u0216\u0218\u021A\u021C"
  6572. U"\u021E\u0220\u0222\u0224\u0226\u0228\u022A\u022C\u022E\u0230\u0232"
  6573. U"\u023A\u023B\u023D\u023E\u0241\u0243\u0244\u0245\u0246\u0248\u024A"
  6574. U"\u024C\u024E\u0370\u0372\u0376\u037F\u0386\u0388\u0389\u038A\u038C"
  6575. U"\u038E\u038F\u0391\u0392\u0393\u0394\u0395\u0396\u0397\u0398\u0399"
  6576. U"\u039A\u039B\u039C\u039D\u039E\u039F\u03A0\u03A1\u03A3\u03A4\u03A5"
  6577. U"\u03A6\u03A7\u03A8\u03A9\u03AA\u03AB\u03CF\u03D8\u03DA\u03DC\u03DE"
  6578. U"\u03E0\u03E2\u03E4\u03E6\u03E8\u03EA\u03EC\u03EE\u03F4\u03F7\u03F9"
  6579. U"\u03FA\u03FD\u03FE\u03FF\u0400\u0401\u0402\u0403\u0404\u0405\u0406"
  6580. U"\u0407\u0408\u0409\u040A\u040B\u040C\u040D\u040E\u040F\u0410\u0411"
  6581. U"\u0412\u0413\u0414\u0415\u0416\u0417\u0418\u0419\u041A\u041B\u041C"
  6582. U"\u041D\u041E\u041F\u0420\u0421\u0422\u0423\u0424\u0425\u0426\u0427"
  6583. U"\u0428\u0429\u042A\u042B\u042C\u042D\u042E\u042F\u0460\u0462\u0464"
  6584. U"\u0466\u0468\u046A\u046C\u046E\u0470\u0472\u0474\u0476\u0478\u047A"
  6585. U"\u047C\u047E\u0480\u048A\u048C\u048E\u0490\u0492\u0494\u0496\u0498"
  6586. U"\u049A\u049C\u049E\u04A0\u04A2\u04A4\u04A6\u04A8\u04AA\u04AC\u04AE"
  6587. U"\u04B0\u04B2\u04B4\u04B6\u04B8\u04BA\u04BC\u04BE\u04C0\u04C1\u04C3"
  6588. U"\u04C5\u04C7\u04C9\u04CB\u04CD\u04D0\u04D2\u04D4\u04D6\u04D8\u04DA"
  6589. U"\u04DC\u04DE\u04E0\u04E2\u04E4\u04E6\u04E8\u04EA\u04EC\u04EE\u04F0"
  6590. U"\u04F2\u04F4\u04F6\u04F8\u04FA\u04FC\u04FE\u0500\u0502\u0504\u0506"
  6591. U"\u0508\u050A\u050C\u050E\u0510\u0512\u0514\u0516\u0518\u051A\u051C"
  6592. U"\u051E\u0520\u0522\u0524\u0526\u0528\u052A\u052C\u052E\u0531\u0532"
  6593. U"\u0533\u0534\u0535\u0536\u0537\u0538\u0539\u053A\u053B\u053C\u053D"
  6594. U"\u053E\u053F\u0540\u0541\u0542\u0543\u0544\u0545\u0546\u0547\u0548"
  6595. U"\u0549\u054A\u054B\u054C\u054D\u054E\u054F\u0550\u0551\u0552\u0553"
  6596. U"\u0554\u0555\u0556\u10A0\u10A1\u10A2\u10A3\u10A4\u10A5\u10A6\u10A7"
  6597. U"\u10A8\u10A9\u10AA\u10AB\u10AC\u10AD\u10AE\u10AF\u10B0\u10B1\u10B2"
  6598. U"\u10B3\u10B4\u10B5\u10B6\u10B7\u10B8\u10B9\u10BA\u10BB\u10BC\u10BD"
  6599. U"\u10BE\u10BF\u10C0\u10C1\u10C2\u10C3\u10C4\u10C5\u10C7\u10CD\u13A0"
  6600. U"\u13A1\u13A2\u13A3\u13A4\u13A5\u13A6\u13A7\u13A8\u13A9\u13AA\u13AB"
  6601. U"\u13AC\u13AD\u13AE\u13AF\u13B0\u13B1\u13B2\u13B3\u13B4\u13B5\u13B6"
  6602. U"\u13B7\u13B8\u13B9\u13BA\u13BB\u13BC\u13BD\u13BE\u13BF\u13C0\u13C1"
  6603. U"\u13C2\u13C3\u13C4\u13C5\u13C6\u13C7\u13C8\u13C9\u13CA\u13CB\u13CC"
  6604. U"\u13CD\u13CE\u13CF\u13D0\u13D1\u13D2\u13D3\u13D4\u13D5\u13D6\u13D7"
  6605. U"\u13D8\u13D9\u13DA\u13DB\u13DC\u13DD\u13DE\u13DF\u13E0\u13E1\u13E2"
  6606. U"\u13E3\u13E4\u13E5\u13E6\u13E7\u13E8\u13E9\u13EA\u13EB\u13EC\u13ED"
  6607. U"\u13EE\u13EF\u13F0\u13F1\u13F2\u13F3\u13F4\u13F5\u1C90\u1C91\u1C92"
  6608. U"\u1C93\u1C94\u1C95\u1C96\u1C97\u1C98\u1C99\u1C9A\u1C9B\u1C9C\u1C9D"
  6609. U"\u1C9E\u1C9F\u1CA0\u1CA1\u1CA2\u1CA3\u1CA4\u1CA5\u1CA6\u1CA7\u1CA8"
  6610. U"\u1CA9\u1CAA\u1CAB\u1CAC\u1CAD\u1CAE\u1CAF\u1CB0\u1CB1\u1CB2\u1CB3"
  6611. U"\u1CB4\u1CB5\u1CB6\u1CB7\u1CB8\u1CB9\u1CBA\u1CBD\u1CBE\u1CBF\u1E00"
  6612. U"\u1E02\u1E04\u1E06\u1E08\u1E0A\u1E0C\u1E0E\u1E10\u1E12\u1E14\u1E16"
  6613. U"\u1E18\u1E1A\u1E1C\u1E1E\u1E20\u1E22\u1E24\u1E26\u1E28\u1E2A\u1E2C"
  6614. U"\u1E2E\u1E30\u1E32\u1E34\u1E36\u1E38\u1E3A\u1E3C\u1E3E\u1E40\u1E42"
  6615. U"\u1E44\u1E46\u1E48\u1E4A\u1E4C\u1E4E\u1E50\u1E52\u1E54\u1E56\u1E58"
  6616. U"\u1E5A\u1E5C\u1E5E\u1E60\u1E62\u1E64\u1E66\u1E68\u1E6A\u1E6C\u1E6E"
  6617. U"\u1E70\u1E72\u1E74\u1E76\u1E78\u1E7A\u1E7C\u1E7E\u1E80\u1E82\u1E84"
  6618. U"\u1E86\u1E88\u1E8A\u1E8C\u1E8E\u1E90\u1E92\u1E94\u1E9E\u1EA0\u1EA2"
  6619. U"\u1EA4\u1EA6\u1EA8\u1EAA\u1EAC\u1EAE\u1EB0\u1EB2\u1EB4\u1EB6\u1EB8"
  6620. U"\u1EBA\u1EBC\u1EBE\u1EC0\u1EC2\u1EC4\u1EC6\u1EC8\u1ECA\u1ECC\u1ECE"
  6621. U"\u1ED0\u1ED2\u1ED4\u1ED6\u1ED8\u1EDA\u1EDC\u1EDE\u1EE0\u1EE2\u1EE4"
  6622. U"\u1EE6\u1EE8\u1EEA\u1EEC\u1EEE\u1EF0\u1EF2\u1EF4\u1EF6\u1EF8\u1EFA"
  6623. U"\u1EFC\u1EFE\u1F08\u1F09\u1F0A\u1F0B\u1F0C\u1F0D\u1F0E\u1F0F\u1F18"
  6624. U"\u1F19\u1F1A\u1F1B\u1F1C\u1F1D\u1F28\u1F29\u1F2A\u1F2B\u1F2C\u1F2D"
  6625. U"\u1F2E\u1F2F\u1F38\u1F39\u1F3A\u1F3B\u1F3C\u1F3D\u1F3E\u1F3F\u1F48"
  6626. U"\u1F49\u1F4A\u1F4B\u1F4C\u1F4D\u1F59\u1F5B\u1F5D\u1F5F\u1F68\u1F69"
  6627. U"\u1F6A\u1F6B\u1F6C\u1F6D\u1F6E\u1F6F\u1FB8\u1FB9\u1FBA\u1FBB\u1FC8"
  6628. U"\u1FC9\u1FCA\u1FCB\u1FD8\u1FD9\u1FDA\u1FDB\u1FE8\u1FE9\u1FEA\u1FEB"
  6629. U"\u1FEC\u1FF8\u1FF9\u1FFA\u1FFB\u2126\u212A\u212B\u2132\u2183\u2C00"
  6630. U"\u2C01\u2C02\u2C03\u2C04\u2C05\u2C06\u2C07\u2C08\u2C09\u2C0A\u2C0B"
  6631. U"\u2C0C\u2C0D\u2C0E\u2C0F\u2C10\u2C11\u2C12\u2C13\u2C14\u2C15\u2C16"
  6632. U"\u2C17\u2C18\u2C19\u2C1A\u2C1B\u2C1C\u2C1D\u2C1E\u2C1F\u2C20\u2C21"
  6633. U"\u2C22\u2C23\u2C24\u2C25\u2C26\u2C27\u2C28\u2C29\u2C2A\u2C2B\u2C2C"
  6634. U"\u2C2D\u2C2E\u2C60\u2C62\u2C63\u2C64\u2C67\u2C69\u2C6B\u2C6D\u2C6E"
  6635. U"\u2C6F\u2C70\u2C72\u2C75\u2C7E\u2C7F\u2C80\u2C82\u2C84\u2C86\u2C88"
  6636. U"\u2C8A\u2C8C\u2C8E\u2C90\u2C92\u2C94\u2C96\u2C98\u2C9A\u2C9C\u2C9E"
  6637. U"\u2CA0\u2CA2\u2CA4\u2CA6\u2CA8\u2CAA\u2CAC\u2CAE\u2CB0\u2CB2\u2CB4"
  6638. U"\u2CB6\u2CB8\u2CBA\u2CBC\u2CBE\u2CC0\u2CC2\u2CC4\u2CC6\u2CC8\u2CCA"
  6639. U"\u2CCC\u2CCE\u2CD0\u2CD2\u2CD4\u2CD6\u2CD8\u2CDA\u2CDC\u2CDE\u2CE0"
  6640. U"\u2CE2\u2CEB\u2CED\u2CF2\uA640\uA642\uA644\uA646\uA648\uA64A\uA64C"
  6641. U"\uA64E\uA650\uA652\uA654\uA656\uA658\uA65A\uA65C\uA65E\uA660\uA662"
  6642. U"\uA664\uA666\uA668\uA66A\uA66C\uA680\uA682\uA684\uA686\uA688\uA68A"
  6643. U"\uA68C\uA68E\uA690\uA692\uA694\uA696\uA698\uA69A\uA722\uA724\uA726"
  6644. U"\uA728\uA72A\uA72C\uA72E\uA732\uA734\uA736\uA738\uA73A\uA73C\uA73E"
  6645. U"\uA740\uA742\uA744\uA746\uA748\uA74A\uA74C\uA74E\uA750\uA752\uA754"
  6646. U"\uA756\uA758\uA75A\uA75C\uA75E\uA760\uA762\uA764\uA766\uA768\uA76A"
  6647. U"\uA76C\uA76E\uA779\uA77B\uA77D\uA77E\uA780\uA782\uA784\uA786\uA78B"
  6648. U"\uA78D\uA790\uA792\uA796\uA798\uA79A\uA79C\uA79E\uA7A0\uA7A2\uA7A4"
  6649. U"\uA7A6\uA7A8\uA7AA\uA7AB\uA7AC\uA7AD\uA7AE\uA7B0\uA7B1\uA7B2\uA7B3"
  6650. U"\uA7B4\uA7B6\uA7B8\uA7BA\uA7BC\uA7BE\uA7C2\uA7C4\uA7C5\uA7C6\uFF21"
  6651. U"\uFF22\uFF23\uFF24\uFF25\uFF26\uFF27\uFF28\uFF29\uFF2A\uFF2B\uFF2C"
  6652. U"\uFF2D\uFF2E\uFF2F\uFF30\uFF31\uFF32\uFF33\uFF34\uFF35\uFF36\uFF37"
  6653. U"\uFF38\uFF39\uFF3A\U00010400\U00010401\U00010402\U00010403\U00010404"
  6654. U"\U00010405\U00010406\U00010407\U00010408\U00010409\U0001040A\U0001040B"
  6655. U"\U0001040C\U0001040D\U0001040E\U0001040F\U00010410\U00010411\U00010412"
  6656. U"\U00010413\U00010414\U00010415\U00010416\U00010417\U00010418\U00010419"
  6657. U"\U0001041A\U0001041B\U0001041C\U0001041D\U0001041E\U0001041F\U00010420"
  6658. U"\U00010421\U00010422\U00010423\U00010424\U00010425\U00010426\U00010427"
  6659. U"\U000104B0\U000104B1\U000104B2\U000104B3\U000104B4\U000104B5\U000104B6"
  6660. U"\U000104B7\U000104B8\U000104B9\U000104BA\U000104BB\U000104BC\U000104BD"
  6661. U"\U000104BE\U000104BF\U000104C0\U000104C1\U000104C2\U000104C3\U000104C4"
  6662. U"\U000104C5\U000104C6\U000104C7\U000104C8\U000104C9\U000104CA\U000104CB"
  6663. U"\U000104CC\U000104CD\U000104CE\U000104CF\U000104D0\U000104D1\U000104D2"
  6664. U"\U000104D3\U00010C80\U00010C81\U00010C82\U00010C83\U00010C84\U00010C85"
  6665. U"\U00010C86\U00010C87\U00010C88\U00010C89\U00010C8A\U00010C8B\U00010C8C"
  6666. U"\U00010C8D\U00010C8E\U00010C8F\U00010C90\U00010C91\U00010C92\U00010C93"
  6667. U"\U00010C94\U00010C95\U00010C96\U00010C97\U00010C98\U00010C99\U00010C9A"
  6668. U"\U00010C9B\U00010C9C\U00010C9D\U00010C9E\U00010C9F\U00010CA0\U00010CA1"
  6669. U"\U00010CA2\U00010CA3\U00010CA4\U00010CA5\U00010CA6\U00010CA7\U00010CA8"
  6670. U"\U00010CA9\U00010CAA\U00010CAB\U00010CAC\U00010CAD\U00010CAE\U00010CAF"
  6671. U"\U00010CB0\U00010CB1\U00010CB2\U000118A0\U000118A1\U000118A2\U000118A3"
  6672. U"\U000118A4\U000118A5\U000118A6\U000118A7\U000118A8\U000118A9\U000118AA"
  6673. U"\U000118AB\U000118AC\U000118AD\U000118AE\U000118AF\U000118B0\U000118B1"
  6674. U"\U000118B2\U000118B3\U000118B4\U000118B5\U000118B6\U000118B7\U000118B8"
  6675. U"\U000118B9\U000118BA\U000118BB\U000118BC\U000118BD\U000118BE\U000118BF"
  6676. U"\U00016E40\U00016E41\U00016E42\U00016E43\U00016E44\U00016E45\U00016E46"
  6677. U"\U00016E47\U00016E48\U00016E49\U00016E4A\U00016E4B\U00016E4C\U00016E4D"
  6678. U"\U00016E4E\U00016E4F\U00016E50\U00016E51\U00016E52\U00016E53\U00016E54"
  6679. U"\U00016E55\U00016E56\U00016E57\U00016E58\U00016E59\U00016E5A\U00016E5B"
  6680. U"\U00016E5C\U00016E5D\U00016E5E\U00016E5F\U0001E900\U0001E901\U0001E902"
  6681. U"\U0001E903\U0001E904\U0001E905\U0001E906\U0001E907\U0001E908\U0001E909"
  6682. U"\U0001E90A\U0001E90B\U0001E90C\U0001E90D\U0001E90E\U0001E90F\U0001E910"
  6683. U"\U0001E911\U0001E912\U0001E913\U0001E914\U0001E915\U0001E916\U0001E917"
  6684. U"\U0001E918\U0001E919\U0001E91A\U0001E91B\U0001E91C\U0001E91D\U0001E91E"
  6685. U"\U0001E91F\U0001E920\U0001E921";
  6686. }
  6687.  
  6688. Unicode::Unicode(){
  6689. for(size_t i = 0; i < sizeof(grossbuchstaben)/sizeof(char32_t)-1; ++i){
  6690. gross_in_klein[grossbuchstaben[i]] = kleinbuchstaben[i];
  6691. buchstaben.insert(grossbuchstaben[i]);
  6692. buchstaben.insert(kleinbuchstaben[i]);
  6693. }
  6694. }
  6695.  
  6696. char32_t
  6697. Unicode::kleinbuchstabe(char32_t c) const {
  6698. const auto i = gross_in_klein.find(c);
  6699. return i == gross_in_klein.end() ? c : i->second;
  6700. }
  6701. bool
  6702. Unicode::ist_buchstabe(char32_t c) const {
  6703. return buchstaben.find(c) != buchstaben.end();
  6704. }
  6705.  
  6706. //--------------- src/utfhilfe.cc ---------------
  6707. //#include "utfhilfe.hh"
  6708.  
  6709. #include <vector>
  6710.  
  6711. namespace {
  6712. int
  6713. utf8_laenge(const char* s, bool& fehler)
  6714. {
  6715. if(*s == 0) return 0;
  6716. const unsigned c = *s & 0xff;
  6717.  
  6718. if(c < 0x80) return 1;
  6719. if(c >= 0xc2){
  6720. if(c < 0xe0) return 2;
  6721. if(c < 0xf0) return 3;
  6722. if(c < 0xf5) return 4; // nicht alle 4-Zeichen-Sequenzen sind erlaubt.
  6723. // 5- und 6-Zeichen-Sequenzen sind nicht erlaubt.
  6724. }
  6725. fehler = true;
  6726. return 0;
  6727. }
  6728.  
  6729. char*
  6730. utf32_in_utf8_l(char32_t c, char* acc) {
  6731. if(c < 0x80){
  6732. *acc = c & 0x7f;
  6733. return acc;
  6734. }
  6735.  
  6736. char32_t hochwertig = 0x80, add = 0x40;
  6737. do{
  6738. char r = c & 0x3f;
  6739. c = (c-r) >> 6;
  6740. *acc-- = r+0x80;
  6741. hochwertig = hochwertig+add;
  6742. add = add >> 1;
  6743. }while(c >= add);
  6744. *acc = hochwertig+c;
  6745. return acc;
  6746. }
  6747.  
  6748. inline char32_t
  6749. folgezeichen(const char c, bool& fehler){
  6750. const char32_t z = c & 0xff;
  6751. if(z < 0x80 || z >= 0xc0) fehler = true;
  6752. return z;
  6753. }
  6754. }
  6755.  
  6756. std::string
  6757. utf32_in_utf8(char32_t c) {
  6758. char acc[5], *e = acc+4, *p = utf32_in_utf8_l(c, acc+3);
  6759. *e = 0;
  6760. return std::string(p, e-p);
  6761. }
  6762.  
  6763. std::string
  6764. utf32_in_utf8(const std::u32string& s){
  6765. const size_t l = s.length();
  6766. std::vector<char> res(4*l+1);
  6767. char *e = &res[4*l], *p = e;
  6768. *e = 0;
  6769. for(size_t i = l; i-- > 0;) p = utf32_in_utf8_l(s[i], --p);
  6770. return std::string(p, e-p);
  6771. }
  6772. std::string
  6773. utf32_in_utf8(uint64_t u){
  6774. char res[17], *e = res+16, *p = e;
  6775. *e = 0;
  6776. while(u){
  6777. p = utf32_in_utf8_l(u & utf_maske, --p);
  6778. u >>= 21;
  6779. }
  6780. return std::string(p, e-p);
  6781. }
  6782.  
  6783. char32_t
  6784. utf8_in_utf32(const char*& s, bool& fehler){
  6785. if(*s == 0) return 0;
  6786. const int l = utf8_laenge(s, fehler);
  6787. char32_t sum = *s++ & 0xff;
  6788. if(l < 2) return sum;
  6789.  
  6790. sum &= (1 << (7-l))-1;
  6791. for(int i = 1; !fehler && i < l; ++i)
  6792. sum = (sum << 6)+(folgezeichen(*s++, fehler)-0x80);
  6793.  
  6794. return sum;
  6795. }
  6796.  
  6797. std::u32string zahl_in_utf32(int z){
  6798. const std::string s = std::to_string(z);
  6799. const size_t l = s.length();
  6800. std::u32string u;
  6801. for(size_t i = 0; i < l; ++i) u.push_back(s[i] & 0xff);
  6802. return u;
  6803. }
  6804.  
  6805.  
  6806. #ifdef AUSGABE_8BIT
  6807.  
  6808. std::string
  6809. utf32_in_ausgabe(char32_t c){
  6810. char acc[2]; acc[0] = c; acc[1] = 0;
  6811. return std::string(acc, 1);
  6812. }
  6813.  
  6814. std::string
  6815. utf32_in_ausgabe(const std::u32string& s){
  6816. const size_t l = s.length();
  6817. std::string res; res.reserve(l);
  6818. for(size_t i = 0; i < l; ++i) res.push_back(s[i]);
  6819. return res;
  6820. }
  6821.  
  6822. #else
  6823.  
  6824. std::string utf32_in_ausgabe(char32_t c)
  6825. { return utf32_in_utf8(c); }
  6826.  
  6827. std::string utf32_in_ausgabe(const std::u32string& s)
  6828. { return utf32_in_utf8(s);}
  6829.  
  6830. #endif // !AUSGABE_8BIT
  6831.  
  6832. bool ist_ziffer(char32_t c){ return c >= U'0' && c <= U'9'; }
  6833. bool ist_zwischenraum(char32_t c){ return c == U' ' || c == U'\t'; }
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement