package aima.core.nlp.parsing.grammars;
import java.util.ArrayList;
import java.util.List;
/**
* The CYK algorithm exploits the structure of grammars in
* Chomsky Normal Form in order to parse efficiently.
*
* A context-free grammar is in Chomsky Normal Form (CNF) if each
* rule has one of the following forms:
*
* 1. A -> BC,
* 2. A -> a,
* 3. S -> null, where B,C are non-start variables (V - {S}),
* and a is a terminal.
*
* @author Jonathon
*
*/
public class ProbCNFGrammar extends ProbContextFreeGrammar {
// TODO: Implement conversion from ContextFree to ChomskyNormalForm
// default constructor
public ProbCNFGrammar() {
type = 4;
rules = new ArrayList<Rule>();
}
public ProbCNFGrammar( ProbCNFGrammar grammar ) {
type = 4;
rules = grammar.rules;
}
/**
* Add a ruleList as the grammar's rule list if all rules in it pass
* both the restrictions of the Context-free grammar, and all rules
* or in Chomsky-Normal-Form
*/
public boolean addRules( List<Rule> ruleList ) {
for( int i=0; i < ruleList.size(); i++ ) {
if( !validRule(ruleList.get(i)) ) {
return false;
}
}
if( !validateRuleProbabilities(ruleList)) {
return false;
}
this.rules = ruleList;
updateVarsAndTerminals();
return true;
}
/**
* Add a rule to the grammar's rule list if it passes
* both the restrictions of the Context-free grammar, and the rule is
* in Chomsky Normal Form.
*/
public boolean addRule( Rule r ) {
if( !validRule(r) ) {
return false;
}
rules.add(r);
updateVarsAndTerminals(r);
return true;
}
/**
* For a grammar rule to be valid in a context-free grammar,
* all the restrictions of the context-free grammar must hold,
* and the rule must be in one of three forms.
*
* 1. A -> BC,
* 2. A -> a,
* 3. S -> null, where B,C are non-start variables (V - {S}),
* and a is a terminal.
*
* @param r, a rule
* @return true, if rule is in CNF. false, otherwise
*/
public boolean validRule( Rule r ){
if( !super.validRule(r) ){
return false;
}
// 3. rhs is null
if( r.rhs == null || r.rhs.size() == 0) { return true; }
// 2. rhs is a terminal (a)
else if( r.rhs.size() == 1 && isTerminal(r.rhs.get(0))) {
return true;
}
// 1. rhs is 2 variables (BC)
else if( r.rhs.size() == 2 && isVariable(r.rhs.get(0))
&& isVariable(r.rhs.get(1))) {
return true;
}
// rule is not in one of the 3 CNF forms
return false;
}
} // end of CNFGrammar()