// Engine.java // (C) 2009 by Michael Peter Christen; mc@yacy.net, Frankfurt a. M., Germany // first published 03.12.2009 on http://yacy.net; // // This is a part of YaCy, a peer-to-peer based web search engine // // $LastChangedDate: 2009-05-28 01:51:34 +0200 (Do, 28 Mai 2009) $ // $LastChangedRevision: 5988 $ // $LastChangedBy: orbiter $ // // LICENSE // // 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 2 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, write to the Free Software // Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA package net.yacy.ai.greedy; import java.util.List; import java.util.PriorityQueue; import java.util.concurrent.ConcurrentHashMap; import java.util.concurrent.PriorityBlockingQueue; public class Engine< SpecificRole extends Role, SpecificFinding extends Finding, SpecificModel extends Model > { private PriorityBlockingQueue> agentQueue; private PriorityBlockingQueue> challengeQueue; private Agent poisonAgent; private Challenge poisonChallenge; private ConcurrentHashMap> settings; private ConcurrentHashMap, SpecificModel> assets; private int cores; public Engine(int cores) { this.cores = cores; this.poisonAgent = new Agent(); this.poisonChallenge = new Challenge(); this.agentQueue = new PriorityBlockingQueue>(); this.challengeQueue = new PriorityBlockingQueue>(); this.settings = new ConcurrentHashMap>(); this.assets = new ConcurrentHashMap, SpecificModel>(); } public void start() { int c = (this.cores == 0) ? Runtime.getRuntime().availableProcessors() : this.cores; for (int i = 0; i < c; i++) { new SettingRunner().start(); new AssetRunner().start(); } } public void stop() { int c = (this.cores == 0) ? Runtime.getRuntime().availableProcessors() : this.cores; for (int i = 0; i < c; i++) { this.agentQueue.put(this.poisonAgent); this.challengeQueue.put(this.poisonChallenge); } } public void inject(Agent agent) { agent.getContext().reset(); this.agentQueue.put(agent); } public class SettingRunner extends Thread { public void run() { Agent agent; Challenge challenge; Context context; SpecificModel model; List findings; PriorityQueue> preChallenge = new PriorityQueue>(); try { while ((agent = agentQueue.take()) != poisonAgent) { // check termination of that goal context = agent.getContext(); if (context.isCompleted()) continue; // produce findings in a setting environment and try to get it from a cache model = agent.getModel(); findings = settings.get(model); if (findings == null) { findings = model.explore(); settings.put(model, findings); } // branch for (SpecificFinding finding: findings) { challenge = new Challenge(agent, finding); //System.out.println("finding: " + finding.toString() + ", priority: " + finding.getPriority()); preChallenge.add(challenge); } challengefeeder: while (!preChallenge.isEmpty()) { if (context.isCompleted()) break challengefeeder; challengeQueue.put(preChallenge.poll()); agent.incInstances(); } //while (!challengeQueue.isEmpty()) System.out.println("finding: " + challengeQueue.take().getChallenge().getFinding().toString()); } } catch (InterruptedException e) { e.printStackTrace(); } } } public class AssetRunner extends Thread { @SuppressWarnings("unchecked") public void run() { Challenge challenge; Agent agent, nextAgent; Goal goal; Context context; Asset asset; SpecificRole role; SpecificModel nextModel = null; try { while ((challenge = challengeQueue.take()) != poisonChallenge) { assert challenge != null; agent = challenge.getAgent(); agent.decInstances(); context = agent.getContext(); goal = context.getGoal(); role = challenge.getFinding().getRole(); // check termination by catching the global termination signal // and check expiration before applying finding // this shall not place the model to the results because // it has not the last finding assigned to the current user if (context.isCompleted()) continue; //System.out.println(agent.getCurrentModel().toString()); //System.out.println("will apply " + challenge.getFinding().toString()); // apply finding: compute next model // avoid double computation of findings using cached assets if (context.useAssetCache()) { asset = new Asset(agent.getModel(), challenge.getFinding()); nextModel = assets.get(asset); if (nextModel == null) { // generate model clone and apply finding try { nextModel = (SpecificModel) agent.getModel().clone(); } catch (CloneNotSupportedException e) { e.printStackTrace(); } nextModel.applyFinding(challenge.getFinding()); nextModel.nextRole(); if (context.feedAssetCache()) assets.put(asset, nextModel); } } else { // generate model clone and apply finding try { nextModel = (SpecificModel) agent.getModel().clone(); } catch (CloneNotSupportedException e) { e.printStackTrace(); } nextModel.applyFinding(challenge.getFinding()); nextModel.nextRole(); if (context.feedAssetCache()) { asset = new Asset(agent.getModel(), challenge.getFinding()); assets.put(asset, nextModel); } } // prune double-occurring models: // while it appears not to be a very good idea to produce models from the // asset cache above and then prune with double appearing models here, this is // still useful if the assets come from an earlier injection of an other agent. // Because the asset cache is a global cache owned by the engine it can produce // ready-computed models that not already exist in the agent cache if (agent.getContext().isKnownModel(nextModel)) { agent.checkInstanceCount(); continue; } // place new model into agent and record finding nextAgent = new Agent(agent, nextModel, challenge.getFinding()); nextAgent.checkInstanceCount(); // check if we arrived at a termination point SpecificRole terminationRole = nextModel.isTermination(); if (terminationRole != null) { // the current role has a termination situation. In case that it is the start user, add a result nextAgent.addResult(); // one of the roles has terminated. // prune this branch for other branches from the parent //System.out.println("terminationRole = " + terminationRole); if (agent.getFinding() == null) { // this is the root of the search tree: a fail in the search //agent.getContext().getGoal().announceFullfillment(); } else { assert agent.getFinding() != null; assert agent.getFinding().getRole() != null; agent.setFindingFail(); } //System.out.println("found winner model for " + terminationRole.toString() + ", latest finding: " + challenge.getFinding().toString() + "\n" + nextModel.toString()); agent.checkInstanceCount(); continue; } // check pruning if (goal.pruning(nextModel)) { agent.checkInstanceCount(); continue; } // do not follow situations where it is known that somebody has made a fatal move in the past if (agent.isPrunedByTerminationInHistory() != null) { agent.checkInstanceCount(); continue; } // check best move criteria int ranking = agent.getRanking(role); if (context.setBestMove(role, ranking)) { nextAgent.addResult(); } // check snapshot if (goal.isSnapshot(nextModel)) { nextAgent.addResult(); // no pruning here } if (context.hasNoResults()) nextAgent.addResult(); if (context.isCompleted()) { continue; } // stack agent for next loop // using the priority of the next role agentQueue.put(nextAgent); } } catch (InterruptedException e) { e.printStackTrace(); } } } }