org.vesalainen.grammar.state.DFADistributor Maven / Gradle / Ivy
Show all versions of lpg Show documentation
/*
* Copyright (C) 2012 Timo Vesalainen
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see .
*/
package org.vesalainen.grammar.state;
import java.util.ArrayList;
import java.util.Collections;
import java.util.Comparator;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import org.vesalainen.parser.util.NumMap;
import org.vesalainen.parser.util.VisitSet;
import org.vesalainen.regex.Regex;
/**
* DFADistributor tries to distribute DFA graph into subgraphs which are connected
* with only one transition.
*
*
* @author Timo Vesalainen
*/
public class DFADistributor extends DiGraph>
{
private int maxStates;
private DFA dfa;
private List candidateList = new ArrayList<>();
private Map,Candidate> candidateMap = new NumMap<>();
private List> distributedDFAs = new ArrayList<>();
private VisitSet> incomingSet = new VisitSet<>();
private VisitSet> closure = new VisitSet<>();
public DFADistributor(DFA dfa, int maxStates)
{
this.dfa = dfa;
this.maxStates = maxStates;
}
public void distribute()
{
distribute(dfa.getRoot(), dfa.initialSize());
}
private void distribute(DFAState state, int rootCount)
{
CandidateComparator comp = new CandidateComparator(rootCount - maxStates);
List firstLevel = new ArrayList<>();
for (DFAState s : state.edges())
{
candidateList.clear();
candidateMap.clear();
incomingSet.clear();
closure.clear();
reset();
traverse(s);
Collections.sort(candidateList, comp);
if (!candidateList.isEmpty())
{
firstLevel.add(candidateList.get(0));
}
}
int distCount = 0;
Collections.sort(firstLevel, comp);
for (Candidate c : firstLevel)
{
distCount += c.getCount();
c.getState().setDistributed(true);
DFA ndfa = new DFA<>(c.getState(), c.getCount(), dfa);
distributedDFAs.add(ndfa);
if (rootCount - distCount < maxStates)
{
break;
}
}
if (rootCount - distCount > maxStates)
{
throw new IllegalArgumentException("DFA too big to fit in java method");
}
dfa.subtractDistributedSize(distCount);
List> redistributeList = new ArrayList<>();
Iterator> it = distributedDFAs.iterator();
while (it.hasNext())
{
DFA ddfa = it.next();
if (ddfa.initialSize() > maxStates)
{
redistributeList.add(ddfa);
}
}
for (DFA ddfa : redistributeList)
{
DFADistributor dfaDistributor = new DFADistributor<>(ddfa, maxStates);
dfaDistributor.distribute();
distributedDFAs.addAll(dfaDistributor.distributedDFAs);
}
}
public List> getDistributedDFAs()
{
return distributedDFAs;
}
@Override
protected void enter(DFAState x)
{
closure.add(x);
incomingSet.addAll(x.inStates());
}
@Override
protected void branch(DFAState x)
{
addCandidate(x);
}
@Override
protected void exit(DFAState x, int count)
{
Candidate c = getCandidate(x);
if (c != null)
{
VisitSet> complement = incomingSet.complement(closure);
if (complement.size() == 1)
{
c.setCount(count);
}
}
}
private void addCandidate(DFAState state)
{
Candidate c = new Candidate(state);
candidateList.add(c);
candidateMap.put(state, c);
}
private Candidate getCandidate(DFAState state)
{
return candidateMap.get(state);
}
private class Candidate
{
private DFAState state;
private int count;
public Candidate(DFAState state)
{
this.state = state;
}
public int getCount()
{
return count;
}
public void setCount(int count)
{
this.count = count;
}
public DFAState getState()
{
return state;
}
public void setState(DFAState state)
{
this.state = state;
}
public String toString()
{
return "Candidate{" + "state=" + state + ", count=" + count + '}';
}
}
private class CandidateComparator implements Comparator
{
private int opt;
public CandidateComparator(int opt)
{
this.opt = opt;
}
@Override
public int compare(Candidate o1, Candidate o2)
{
if (o1.count > opt && o2.count > opt)
{
return o1.count - o2.count;
}
else
{
return o2.count - o1.count;
}
}
}
/**
* @param args the command line arguments
*/
public static void main(String[] args)
{
try
{
DFA dfa = Regex.createDFA("qwertyuio|asdfghjkl|zxcvbnm|[qwe]+");
DFADistributor distributor = new DFADistributor<>(dfa, 10);
distributor.distribute();
}
catch (Exception ex)
{
ex.printStackTrace();
}
}
}