package org.jactr.eclipse.association.ui.model;
/*
* default logging
*/
import java.util.ArrayList;
import java.util.Collection;
import java.util.Collections;
import java.util.HashSet;
import java.util.Map;
import java.util.TreeMap;
import java.util.concurrent.CompletableFuture;
import java.util.concurrent.ConcurrentSkipListMap;
import java.util.concurrent.Executor;
import javolution.util.FastList;
import org.antlr.runtime.tree.CommonTree;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.jactr.core.chunk.four.ISubsymbolicChunk4;
import org.jactr.core.concurrent.ExecutorServices;
import org.jactr.eclipse.association.ui.mapper.IAssociationMapper;
import org.jactr.io.antlr3.builder.JACTRBuilder;
import org.jactr.io.antlr3.misc.ASTSupport;
public class ModelAssociations
{
/**
* Logger definition
*/
static private final transient Log LOGGER = LogFactory
.getLog(ModelAssociations.class);
private ConcurrentSkipListMap<String, Collection<Association>> _jChunks;
private ConcurrentSkipListMap<String, Collection<Association>> _iChunks;
private Collection<Association> _associations;
private IAssociationMapper _mapper;
private CommonTree _modelDescriptor;
private String _focus;
public ModelAssociations(CommonTree modelDescriptor,
IAssociationMapper mapper, String focalChunk)
{
this(mapper);
_modelDescriptor = modelDescriptor;
_focus = focalChunk;
}
public ModelAssociations(CommonTree modelDescriptor, IAssociationMapper mapper)
{
this(modelDescriptor, mapper, null);
}
public ModelAssociations(IAssociationMapper mapper)
{
_mapper = mapper;
_jChunks = new ConcurrentSkipListMap<String, Collection<Association>>();
_iChunks = new ConcurrentSkipListMap<String, Collection<Association>>();
_associations = Collections
.synchronizedCollection(new HashSet<Association>());
}
public CommonTree getModelDescriptor()
{
return _modelDescriptor;
}
public void process()
{
try
{
process(Runtime.getRuntime().availableProcessors(),
ExecutorServices.INLINE_EXECUTOR).get();
}
catch (Exception e)
{
LOGGER.error("Failed to extract model associations", e);
}
}
/**
* @param maximumProcesses
* @param executor
* @return
*/
public CompletableFuture<Void> process(final int maximumProcesses,
final Executor executor)
{
/*
* first a runnable for the map of all chunks
*/
CompletableFuture<Map<String, CommonTree>> allChunksFuture = CompletableFuture
.supplyAsync(
() -> {
Map<String, CommonTree> map = ASTSupport.getMapOfTrees(
_modelDescriptor, JACTRBuilder.CHUNK);
if (LOGGER.isDebugEnabled())
LOGGER.debug(String.format("Extracted map of trees [%d]",
map.size()));
return map;
}, executor);
/*
* once that is done, we can split
*/
CompletableFuture<Void> subProcs = allChunksFuture
.thenComposeAsync(
(m) -> {
Collection<CompletableFuture<Void>> submitted = new ArrayList<CompletableFuture<Void>>();
FastList<CommonTree> allChunks = FastList.newInstance();
int blockSize = m.size() / maximumProcesses;
final Map<String, CommonTree> allChunksMap = m;
if (LOGGER.isDebugEnabled())
LOGGER.debug(String.format(
"Subdividing %s chunks into %d blocks", m.size(),
maximumProcesses));
try
{
allChunks.addAll(m.values());
for (int i = 0; i < maximumProcesses; i++)
{
//
final Collection<CommonTree> subList = allChunks.subList(i
* blockSize, i * blockSize + blockSize);
submitted.add(CompletableFuture.runAsync(() -> {
process(subList, allChunksMap);
}, executor));
}
}
catch (Exception e)
{
LOGGER.error("Failed to dispatch subprocesses ", e);
}
CompletableFuture<Void> allDone = CompletableFuture
.allOf(submitted.toArray(new CompletableFuture[submitted
.size()]));
allDone.handle((v, t) -> {
if (t != null)
LOGGER.error("Failed to complete all processes", t);
else
LOGGER.debug("processing complete");
return null;
});
return allDone;
}, executor);
return subProcs;
}
private void process(Collection<CommonTree> chunksToProcess,
Map<String, CommonTree> allChunks)
{
Map<String, CommonTree> recycledParameters = new TreeMap<String, CommonTree>();
if (LOGGER.isDebugEnabled())
LOGGER
.debug(String.format("Processing %d chunks", chunksToProcess.size()));
for (CommonTree jChunk : chunksToProcess)
process(ASTSupport.getName(jChunk), jChunk, recycledParameters, allChunks);
}
private void process(String jChunkName, CommonTree jChunk,
Map<String, CommonTree> recycledParameters,
Map<String, CommonTree> allChunks)
{
recycledParameters.clear();
recycledParameters = ASTSupport.getMapOfTrees(jChunk,
JACTRBuilder.PARAMETER, recycledParameters);
String linkKey = ISubsymbolicChunk4.LINKS.toLowerCase();
if (!recycledParameters.containsKey(linkKey)) return;
String allLinks = recycledParameters.get(linkKey).getChild(1).getText();
try
{
for (Association association : _mapper.extractAssociations(allLinks,
jChunk, allChunks))
if (_focus == null
|| _focus.equals(ASTSupport.getName(association.getJChunk()))
|| _focus.equals(ASTSupport.getName(association.getIChunk())))
{
if (LOGGER.isDebugEnabled())
LOGGER.debug(String.format("adding Link: j:%s i:%s str:%.2f",
association.getJChunk().toStringTree(), association.getIChunk()
.toStringTree(), association.getStrength()));
addAssociation(association);
}
}
catch (Exception e)
{
if (LOGGER.isWarnEnabled())
LOGGER.warn(String.format("Failed to extract link info from %s",
allLinks), e);
}
}
// private void process(CommonTree modelDescriptor, String focus)
// {
// _modelDescriptor = modelDescriptor;
// Map<String, CommonTree> allChunks = ASTSupport.getMapOfTrees(
// modelDescriptor, JACTRBuilder.CHUNK);
//
// String linkKey = ISubsymbolicChunk4.LINKS.toLowerCase();
// Map<String, CommonTree> parameters = new TreeMap<String, CommonTree>();
// for (Map.Entry<String, CommonTree> jChunk : allChunks.entrySet())
// {
// /*
// * snag the parameter needed
// */
// parameters.clear();
// parameters = ASTSupport.getMapOfTrees(jChunk.getValue(),
// JACTRBuilder.PARAMETER, parameters);
//
// if (!parameters.containsKey(linkKey)) continue;
//
// String allLinks = parameters.get(linkKey).getChild(1).getText();
//
// try
// {
// for (Association association : _mapper.extractAssociations(allLinks,
// jChunk.getValue(), allChunks))
// if (focus == null
// || focus.equals(ASTSupport.getName(association.getJChunk()))
// || focus.equals(ASTSupport.getName(association.getIChunk())))
// {
// if (LOGGER.isDebugEnabled())
// LOGGER.debug(String.format("adding Link: j:%s i:%s str:%.2f",
// association.getJChunk().toStringTree(), association
// .getIChunk().toStringTree(), association.getStrength()));
//
// addAssociation(association);
// }
//
// }
// catch (Exception e)
// {
// if (LOGGER.isWarnEnabled())
// LOGGER.warn(String.format("Failed to extract link info from %s",
// allLinks));
// }
// }
// }
public void addAssociation(Association association)
{
String j = ASTSupport.getName(association.getJChunk()).toLowerCase();
String i = ASTSupport.getName(association.getIChunk()).toLowerCase();
// if (LOGGER.isDebugEnabled())
// LOGGER.debug(String.format("Adding j:%s i:%s %d %.2f", j, i,
// association.getCount(), association.getStrength()));
add(j, association, _jChunks);
add(i, association, _iChunks);
_associations.add(association);
}
public Collection<Association> getOutboundAssociations(String jChunkName)
{
return get(jChunkName, _jChunks);
}
public Collection<Association> getInboundAssociations(String iChunkName)
{
return get(iChunkName, _iChunks);
}
protected Collection<Association> get(String keyName,
Map<String, Collection<Association>> map)
{
Collection<Association> rtn = map.get(keyName.toLowerCase());
if (rtn == null)
rtn = Collections.EMPTY_LIST;
else
rtn = Collections.unmodifiableCollection(rtn);
return rtn;
}
public Association[] getAssociations()
{
return _associations.toArray(new Association[0]);
}
private void add(String name, Association association,
ConcurrentSkipListMap<String, Collection<Association>> container)
{
FastList<Association> addIfMissing = FastList.newInstance();
Collection<Association> collection = container.putIfAbsent(name,
addIfMissing);
// we already had a collection attached
if (collection != null)
FastList.recycle(addIfMissing);
else
collection = addIfMissing;
collection.add(association);
}
}