/*
* This file is part of the HyperGraphDB source distribution. This is copyrighted
* software. For permitted uses, licensing options and redistribution, please see
* the LicensingInformation file at the root level of the distribution.
*
* Copyright (c) 2005-2010 Kobrix Software, Inc. All rights reserved.
*/
package org.hypergraphdb.algorithms;
import java.util.HashMap;
import java.util.Map;
import java.util.Stack;
import org.hypergraphdb.HGHandle;
import org.hypergraphdb.HGSearchResult;
import org.hypergraphdb.HGQuery.hg;
import org.hypergraphdb.util.Pair;
import org.hypergraphdb.util.Ref;
/**
* <p>
* Implements a depth-first search of a graph. As a reminder, depth-first will visit atoms adjacent
* to the current before visiting its siblings.
* </p>
*
* @author Borislav Iordanov
*/
public class HGDepthFirstTraversal implements HGTraversal
{
private Ref<HGHandle> startAtom;
// The following maps contains all atoms that have been reached: if they have
// been actually visited (i.e. returned by the 'next' method), they map to
// Boolean.TRUE, otherwise they map to Boolean.FALSE.
private Map<HGHandle, Boolean> examined = new HashMap<HGHandle, Boolean>();
private Stack<Pair<HGHandle, HGHandle>> to_explore = new Stack<Pair<HGHandle, HGHandle>>();
private HGALGenerator adjListGenerator;
private boolean initialized = false;
private void init()
{
examined.put(startAtom.get(), Boolean.TRUE);
advance(startAtom.get());
initialized = true;
}
private void advance(HGHandle from)
{
HGSearchResult<Pair<HGHandle, HGHandle>> i = adjListGenerator.generate(from);
while (i.hasNext())
{
Pair<HGHandle, HGHandle> p = i.next();
if (!examined.containsKey(p.getSecond()))
{
to_explore.push(p);
examined.put(p.getSecond(), Boolean.FALSE);
}
}
i.close();
}
public HGDepthFirstTraversal()
{
}
public HGDepthFirstTraversal(HGHandle startAtom, HGALGenerator adjListGenerator)
{
this(hg.constant(startAtom), adjListGenerator);
}
public HGDepthFirstTraversal(Ref<HGHandle> startAtom, HGALGenerator adjListGenerator)
{
this.startAtom = startAtom;
this.adjListGenerator = adjListGenerator;
init();
}
public Ref<HGHandle> getStartAtomReference()
{
return startAtom;
}
public void setStartAtomReference(Ref<HGHandle> startAtom)
{
this.startAtom = startAtom;
}
public void setStartAtom(HGHandle startAtom)
{
this.startAtom = hg.constant(startAtom);
}
public HGHandle getStartAtom()
{
return startAtom == null ? null : startAtom.get();
}
public HGALGenerator getAdjListGenerator()
{
return adjListGenerator;
}
public void setAdjListGenerator(HGALGenerator adjListGenerator)
{
this.adjListGenerator = adjListGenerator;
}
public boolean hasNext()
{
if (!initialized)
init();
return !to_explore.isEmpty();
}
public Pair<HGHandle, HGHandle> next()
{
if (!initialized)
init();
Pair<HGHandle, HGHandle> rvalue = null;
if (!to_explore.isEmpty())
{
rvalue = to_explore.pop();
examined.put(rvalue.getSecond(), Boolean.TRUE);
advance(rvalue.getSecond());
}
return rvalue;
}
public boolean isVisited(HGHandle handle)
{
Boolean b = examined.get(handle);
return b != null && b;
}
public void remove()
{
throw new UnsupportedOperationException();
}
public void reset()
{
examined.clear();
to_explore.clear();
init();
}
}