Algorithms Library Toolkit
A toolkit for algorithms, especially for algorithms on formal languages
GNF.h
Go to the documentation of this file.
1
6/*
7 * This file is part of Algorithms library toolkit.
8 * Copyright (C) 2017 Jan Travnicek (jan.travnicek@fit.cvut.cz)
9
10 * Algorithms library toolkit is free software: you can redistribute it and/or modify
11 * it under the terms of the GNU General Public License as published by
12 * the Free Software Foundation, either version 3 of the License, or
13 * (at your option) any later version.
14
15 * Algorithms library toolkit is distributed in the hope that it will be useful,
16 * but WITHOUT ANY WARRANTY; without even the implied warranty of
17 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
18 * GNU General Public License for more details.
19
20 * You should have received a copy of the GNU General Public License
21 * along with Algorithms library toolkit. If not, see <http://www.gnu.org/licenses/>.
22 */
23
24#pragma once
25
26
27#include <ext/algorithm>
28
29#include <alib/map>
30#include <alib/set>
31#include <alib/vector>
32
33#include <core/components.hpp>
34
36
38
39#include <core/normalize.hpp>
42
43namespace grammar {
44
45class TerminalAlphabet;
46class NonterminalAlphabet;
47class InitialSymbol;
48
64template < class TerminalSymbolType = DefaultSymbolType, class NonterminalSymbolType = DefaultSymbolType >
65class GNF final : public core::Components < GNF < TerminalSymbolType, NonterminalSymbolType >, ext::set < TerminalSymbolType >, component::Set, TerminalAlphabet, ext::set < NonterminalSymbolType >, component::Set, NonterminalAlphabet, NonterminalSymbolType, component::Value, InitialSymbol > {
70
74 bool generatesEpsilon;
75
76public:
82 explicit GNF ( NonterminalSymbolType initialSymbol );
83
91 explicit GNF ( ext::set < NonterminalSymbolType > nonterminalAlphabet, ext::set < TerminalSymbolType > terminalAlphabet, NonterminalSymbolType initialSymbol );
92
103 bool addRule ( NonterminalSymbolType leftHandSide, ext::pair < TerminalSymbolType, ext::vector < NonterminalSymbolType > > rightHandSide );
104
113 void addRules ( NonterminalSymbolType leftHandSide, ext::set < ext::pair < TerminalSymbolType, ext::vector < NonterminalSymbolType > > > rightHandSide );
114
121
128
137 bool removeRule ( const NonterminalSymbolType & leftHandSide, const ext::pair < TerminalSymbolType, ext::vector < NonterminalSymbolType > > & rightHandSide );
138
144 const NonterminalSymbolType & getInitialSymbol ( ) const & {
145 return this->template accessComponent < InitialSymbol > ( ).get ( );
146 }
147
153 NonterminalSymbolType && getInitialSymbol ( ) && {
154 return std::move ( this->template accessComponent < InitialSymbol > ( ).get ( ) );
155 }
156
164 bool setInitialSymbol ( NonterminalSymbolType symbol ) {
165 return this->template accessComponent < InitialSymbol > ( ).set ( std::move ( symbol ) );
166 }
167
174 return this->template accessComponent < NonterminalAlphabet > ( ).get ( );
175 }
176
183 return std::move ( this->template accessComponent < NonterminalAlphabet > ( ).get ( ) );
184 }
185
193 bool addNonterminalSymbol ( NonterminalSymbolType symbol ) {
194 return this->template accessComponent < NonterminalAlphabet > ( ).add ( std::move ( symbol ) );
195 }
196
203 this->template accessComponent < NonterminalAlphabet > ( ).set ( std::move ( symbols ) );
204 }
205
212 return this->template accessComponent < TerminalAlphabet > ( ).get ( );
213 }
214
221 return std::move ( this->template accessComponent < TerminalAlphabet > ( ).get ( ) );
222 }
223
231 bool addTerminalSymbol ( TerminalSymbolType symbol ) {
232 return this->template accessComponent < TerminalAlphabet > ( ).add ( std::move ( symbol ) );
233 }
234
241 this->template accessComponent < TerminalAlphabet > ( ).set ( std::move ( symbols ) );
242 }
243
249 void setGeneratesEpsilon ( bool genEps );
250
256 bool getGeneratesEpsilon ( ) const;
257
265 auto operator <=> ( const GNF & other ) const {
266 return std::tie ( getTerminalAlphabet ( ), getNonterminalAlphabet ( ), getInitialSymbol ( ), rules ) <=> std::tie ( other.getTerminalAlphabet ( ), other.getNonterminalAlphabet ( ), other.getInitialSymbol ( ), other.rules );
267 }
268
276 bool operator == ( const GNF & other ) const {
277 return std::tie ( getTerminalAlphabet ( ), getNonterminalAlphabet ( ), getInitialSymbol ( ), rules ) == std::tie ( other.getTerminalAlphabet ( ), other.getNonterminalAlphabet ( ), other.getInitialSymbol ( ), other.rules );
278 }
279
288 friend ext::ostream & operator << ( ext::ostream & out, const GNF & instance ) {
289 return out << "(GNF"
290 << " nonterminalAlphabet = " << instance.getNonterminalAlphabet ( )
291 << " terminalAlphabet = " << instance.getTerminalAlphabet ( )
292 << " initialSymbol = " << instance.getInitialSymbol ( )
293 << " rules = " << instance.getRules ( )
294 << ")";
295 }
296};
297
298template < class TerminalSymbolType, class NonterminalSymbolType >
299GNF < TerminalSymbolType, NonterminalSymbolType >::GNF ( NonterminalSymbolType initialSymbol ) : GNF ( ext::set < NonterminalSymbolType > { initialSymbol }, ext::set < TerminalSymbolType > ( ), initialSymbol ) {
300}
301
302template < class TerminalSymbolType, class NonterminalSymbolType >
303GNF < TerminalSymbolType, NonterminalSymbolType >::GNF ( ext::set < NonterminalSymbolType > nonterminalAlphabet, ext::set < TerminalSymbolType > terminalAlphabet, NonterminalSymbolType initialSymbol ) : core::Components < GNF, ext::set < TerminalSymbolType >, component::Set, TerminalAlphabet, ext::set < NonterminalSymbolType >, component::Set, NonterminalAlphabet, NonterminalSymbolType, component::Value, InitialSymbol > ( std::move ( terminalAlphabet), std::move ( nonterminalAlphabet ), std::move ( initialSymbol ) ), generatesEpsilon ( false ) {
304}
305
306template < class TerminalSymbolType, class NonterminalSymbolType >
308 if ( !getNonterminalAlphabet ( ).count ( leftHandSide ) )
309 throw GrammarException ( "Rule must rewrite nonterminal symbol" );
310
311 if ( !getTerminalAlphabet ( ).count ( rightHandSide.first ) )
312 throw GrammarException ( "Rule must rewrite to terminal symbol" );
313
314 for ( const NonterminalSymbolType & rhsNTs : rightHandSide.second )
315 if ( !getNonterminalAlphabet ( ).count ( rhsNTs ) )
316 throw GrammarException ( "Symbol \"" + ext::to_string ( rhsNTs ) + "\" is not a nonterminal symbol" );
317
318 return rules[std::move ( leftHandSide )].insert ( std::move ( rightHandSide ) ).second;
319}
320
321template < class TerminalSymbolType, class NonterminalSymbolType >
323 if ( !getNonterminalAlphabet ( ).count ( leftHandSide ) )
324 throw GrammarException ( "Rule must rewrite nonterminal symbol" );
325
326 for ( const ext::pair < TerminalSymbolType, ext::vector < NonterminalSymbolType > > & rhs : rightHandSide ) {
327 if ( ! getTerminalAlphabet ( ).count ( rhs.first ) )
328 throw GrammarException ( "Rule must rewrite to terminal symbol" );
329
330 for ( const NonterminalSymbolType & rhsNTs : rhs.second )
331 if ( !getNonterminalAlphabet ( ).count ( rhsNTs ) )
332 throw GrammarException ( "Symbol \"" + ext::to_string ( rhsNTs ) + "\" is not a nonterminal symbol" );
333 }
334
335 rules[std::move ( leftHandSide )].insert ( ext::make_mover ( rightHandSide ).begin ( ), ext::make_mover ( rightHandSide ).end ( ) );
336}
337
338template < class TerminalSymbolType, class NonterminalSymbolType >
340 return rules;
341}
342
343template < class TerminalSymbolType, class NonterminalSymbolType >
345 return std::move ( rules );
346}
347
348template < class TerminalSymbolType, class NonterminalSymbolType >
350 return rules[leftHandSide].erase ( rightHandSide );
351}
352
353template < class TerminalSymbolType, class NonterminalSymbolType >
355 generatesEpsilon = genEps;
356}
357
358template < class TerminalSymbolType, class NonterminalSymbolType >
360 return generatesEpsilon;
361}
362
363} /* namespace grammar */
364
365namespace core {
366
373template < class TerminalSymbolType, class NonterminalSymbolType >
374class SetConstraint< grammar::GNF < TerminalSymbolType, NonterminalSymbolType >, TerminalSymbolType, grammar::TerminalAlphabet > {
375public:
384 static bool used ( const grammar::GNF < TerminalSymbolType, NonterminalSymbolType > & grammar, const TerminalSymbolType & symbol ) {
385 for ( const std::pair < const NonterminalSymbolType, ext::set < ext::pair < TerminalSymbolType, ext::vector < NonterminalSymbolType > > > > & rule : grammar.getRules ( ) )
386 for ( const ext::pair < TerminalSymbolType, ext::vector < NonterminalSymbolType > > & rhs : rule.second )
387 if ( rhs.first == symbol )
388 return true;
389
390 return false;
391 }
392
401 static bool available ( const grammar::GNF < TerminalSymbolType, NonterminalSymbolType > &, const TerminalSymbolType & ) {
402 return true;
403 }
404
413 static void valid ( const grammar::GNF < TerminalSymbolType, NonterminalSymbolType > & grammar, const TerminalSymbolType & symbol ) {
414 if ( grammar.template accessComponent < grammar::NonterminalAlphabet > ( ).get ( ).count ( ext::poly_comp ( symbol ) ) )
415 throw grammar::GrammarException ( "Symbol " + ext::to_string ( symbol ) + " cannot be in the terminal alphabet since it is already in the nonterminal alphabet." );
416 }
417};
418
425template < class TerminalSymbolType, class NonterminalSymbolType >
426class SetConstraint< grammar::GNF < TerminalSymbolType, NonterminalSymbolType >, NonterminalSymbolType, grammar::NonterminalAlphabet > {
427public:
436 static bool used ( const grammar::GNF < TerminalSymbolType, NonterminalSymbolType > & grammar, const NonterminalSymbolType & symbol ) {
437 for ( const std::pair < const NonterminalSymbolType, ext::set < ext::pair < TerminalSymbolType, ext::vector < NonterminalSymbolType > > > > & rule : grammar.getRules ( ) ) {
438 if ( rule.first == symbol )
439 return true;
440
441 for ( const ext::pair < TerminalSymbolType, ext::vector < NonterminalSymbolType > > & rhs : rule.second )
442 if ( std::find ( rhs.second.begin ( ), rhs.second.end ( ), symbol ) != rhs.second.end ( ) )
443 return true;
444 }
445
446 return grammar.template accessComponent < grammar::InitialSymbol > ( ).get ( ) == symbol;
447 }
448
457 static bool available ( const grammar::GNF < TerminalSymbolType, NonterminalSymbolType > &, const NonterminalSymbolType & ) {
458 return true;
459 }
460
469 static void valid ( const grammar::GNF < TerminalSymbolType, NonterminalSymbolType > & grammar, const NonterminalSymbolType & symbol ) {
470 if ( grammar.template accessComponent < grammar::TerminalAlphabet > ( ).get ( ).count ( ext::poly_comp ( symbol ) ) )
471 throw grammar::GrammarException ( "Symbol " + ext::to_string ( symbol ) + " cannot be in the nonterminal alphabet since it is already in the terminal alphabet." );
472 }
473};
474
481template < class TerminalSymbolType, class NonterminalSymbolType >
482class ElementConstraint< grammar::GNF < TerminalSymbolType, NonterminalSymbolType >, NonterminalSymbolType, grammar::InitialSymbol > {
483public:
492 static bool available ( const grammar::GNF < TerminalSymbolType, NonterminalSymbolType > & grammar, const NonterminalSymbolType & symbol ) {
493 return grammar.template accessComponent < grammar::NonterminalAlphabet > ( ).get ( ).count ( symbol );
494 }
495
502 static void valid ( const grammar::GNF < TerminalSymbolType, NonterminalSymbolType > &, const NonterminalSymbolType & ) {
503 }
504};
505
511template < class TerminalSymbolType, class NonterminalSymbolType >
512struct normalize < grammar::GNF < TerminalSymbolType, NonterminalSymbolType > > {
514 ext::set < DefaultSymbolType > nonterminals = alphabet::SymbolNormalize::normalizeAlphabet ( std::move ( value ).getNonterminalAlphabet ( ) );
515 ext::set < DefaultSymbolType > terminals = alphabet::SymbolNormalize::normalizeAlphabet ( std::move ( value ).getTerminalAlphabet ( ) );
516 DefaultSymbolType initialSymbol = alphabet::SymbolNormalize::normalizeSymbol ( std::move ( value ).getInitialSymbol ( ) );
517
518 grammar::GNF < > res ( std::move ( nonterminals ), std::move ( terminals ), std::move ( initialSymbol ) );
519
520 for ( std::pair < NonterminalSymbolType, ext::set < ext::pair < TerminalSymbolType, ext::vector < NonterminalSymbolType > > > > && rule : ext::make_mover ( std::move ( value ).getRules ( ) ) ) {
521
523 for ( ext::pair < TerminalSymbolType, ext::vector < NonterminalSymbolType > > && target : ext::make_mover ( rule.second ) )
524 rhs.insert ( grammar::GrammarNormalize::normalizeRHS ( std::move ( target ) ) );
525
526 DefaultSymbolType lhs = alphabet::SymbolNormalize::normalizeSymbol ( std::move ( rule.first ) );
527
528 res.addRules ( std::move ( lhs ), std::move ( rhs ) );
529 }
530
531 res.setGeneratesEpsilon ( value.getGeneratesEpsilon ( ) );
532
533 return res;
534 }
535};
536
537} /* namespace core */
538
539extern template class grammar::GNF < >;
540
static ext::set< DefaultSymbolType > normalizeAlphabet(ext::set< SymbolType > &&symbols)
Definition: SymbolNormalize.h:50
static DefaultSymbolType normalizeSymbol(SymbolType &&symbol)
Definition: SymbolNormalize.h:68
Definition: components.hpp:181
static void valid(const grammar::GNF< TerminalSymbolType, NonterminalSymbolType > &, const NonterminalSymbolType &)
Definition: GNF.h:502
static bool available(const grammar::GNF< TerminalSymbolType, NonterminalSymbolType > &grammar, const NonterminalSymbolType &symbol)
Definition: GNF.h:492
Definition: components.hpp:25
static bool used(const grammar::GNF< TerminalSymbolType, NonterminalSymbolType > &grammar, const NonterminalSymbolType &symbol)
Definition: GNF.h:436
static void valid(const grammar::GNF< TerminalSymbolType, NonterminalSymbolType > &grammar, const NonterminalSymbolType &symbol)
Definition: GNF.h:469
static bool available(const grammar::GNF< TerminalSymbolType, NonterminalSymbolType > &, const NonterminalSymbolType &)
Definition: GNF.h:457
static bool available(const grammar::GNF< TerminalSymbolType, NonterminalSymbolType > &, const TerminalSymbolType &)
Definition: GNF.h:401
static void valid(const grammar::GNF< TerminalSymbolType, NonterminalSymbolType > &grammar, const TerminalSymbolType &symbol)
Definition: GNF.h:413
static bool used(const grammar::GNF< TerminalSymbolType, NonterminalSymbolType > &grammar, const TerminalSymbolType &symbol)
Definition: GNF.h:384
Definition: setComponents.hpp:26
Class extending the map class from the standard library. Original reason is to allow printing of the ...
Definition: map.hpp:48
Definition: ostream.h:14
Class extending the pair class from the standard library. Original reason is to allow printing of the...
Definition: pair.hpp:43
Definition: set.hpp:44
Class extending the vector class from the standard library. Original reason is to allow printing of t...
Definition: vector.hpp:45
Greibach normal form of a context free grammar in Chomsky hierarchy or type 2 in Chomsky hierarchy....
Definition: GNF.h:65
void setNonterminalAlphabet(ext::set< NonterminalSymbolType > symbols)
Definition: GNF.h:202
bool operator==(const GNF &other) const
Definition: GNF.h:276
bool setInitialSymbol(NonterminalSymbolType symbol)
Definition: GNF.h:164
bool addRule(NonterminalSymbolType leftHandSide, ext::pair< TerminalSymbolType, ext::vector< NonterminalSymbolType > > rightHandSide)
Add a new rule of a grammar.
Definition: GNF.h:307
const ext::set< TerminalSymbolType > & getTerminalAlphabet() const &
Definition: GNF.h:211
GNF(NonterminalSymbolType initialSymbol)
Creates a new instance of the grammar with a concrete initial symbol.
Definition: GNF.h:299
NonterminalSymbolType && getInitialSymbol() &&
Definition: GNF.h:153
const ext::map< NonterminalSymbolType, ext::set< ext::pair< TerminalSymbolType, ext::vector< NonterminalSymbolType > > > > & getRules() const &
Definition: GNF.h:339
bool addTerminalSymbol(TerminalSymbolType symbol)
Definition: GNF.h:231
bool removeRule(const NonterminalSymbolType &leftHandSide, const ext::pair< TerminalSymbolType, ext::vector< NonterminalSymbolType > > &rightHandSide)
Definition: GNF.h:349
void setGeneratesEpsilon(bool genEps)
Definition: GNF.h:354
friend ext::ostream & operator<<(ext::ostream &out, const GNF &instance)
Definition: GNF.h:288
ext::set< NonterminalSymbolType > && getNonterminalAlphabet() &&
Definition: GNF.h:182
ext::set< TerminalSymbolType > && getTerminalAlphabet() &&
Definition: GNF.h:220
bool addNonterminalSymbol(NonterminalSymbolType symbol)
Definition: GNF.h:193
bool getGeneratesEpsilon() const
Definition: GNF.h:359
void setTerminalAlphabet(ext::set< TerminalSymbolType > symbols)
Definition: GNF.h:240
auto operator<=>(const GNF &other) const
Definition: GNF.h:265
const NonterminalSymbolType & getInitialSymbol() const &
Definition: GNF.h:144
const ext::set< NonterminalSymbolType > & getNonterminalAlphabet() const &
Definition: GNF.h:173
void addRules(NonterminalSymbolType leftHandSide, ext::set< ext::pair< TerminalSymbolType, ext::vector< NonterminalSymbolType > > > rightHandSide)
Add new rules of a grammar.
Definition: GNF.h:322
Definition: GrammarException.h:15
static ext::pair< DefaultSymbolType, ext::vector< DefaultSymbolType > > normalizeRHS(ext::pair< FirstSymbolType, ext::vector< SecondSymbolType > > &&symbol)
Definition: GrammarNormalize.h:40
Definition: Object.h:16
return res
Definition: MinimizeByPartitioning.h:145
Definition: normalize.hpp:10
constexpr tuple< Elements &... > tie(Elements &... args) noexcept
Helper of extended tuple of references construction. The tuple is constructed to reffer to values in ...
Definition: tuple.hpp:218
reference_mover< T > make_mover(T &param)
Move adaptor construction function specialized to lvalue reference parameter.
Definition: iterator.hpp:468
std::string to_string(const T &value)
To string method designated for objects that can be casted to string.
Definition: string.hpp:131
PolyComp< T > poly_comp(const T &inst)
Definition: functional.hpp:60
auto begin(Container &&cont) -> decltype(std::forward(cont).begin())
Definition: iterator.hpp:900
Definition: ToAutomaton.h:24
void end()
Definition: measurements.cpp:19
auto & get(ext::ptr_array< Type, N > &tpl)
Specialisation of get function for pointer arrays.
Definition: ptr_array.hpp:693
static grammar::GNF< > eval(grammar::GNF< TerminalSymbolType, NonterminalSymbolType > &&value)
Definition: GNF.h:513
Definition: normalize.hpp:13