yacy_search_server/source/net/yacy/ai/greedy/Engine.java

258 lines
12 KiB
Java
Raw Normal View History

// 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<SpecificRole>,
SpecificModel extends Model<SpecificRole, SpecificFinding>
> {
private final PriorityBlockingQueue<Agent<SpecificRole, SpecificFinding, SpecificModel>> agentQueue;
private final PriorityBlockingQueue<Challenge<SpecificRole, SpecificFinding, SpecificModel>> challengeQueue;
private final Agent<SpecificRole, SpecificFinding, SpecificModel> poisonAgent;
private final Challenge<SpecificRole, SpecificFinding, SpecificModel> poisonChallenge;
private final ConcurrentHashMap<SpecificModel, List<SpecificFinding>> settings;
private final ConcurrentHashMap<Asset<SpecificRole, SpecificFinding, SpecificModel>, SpecificModel> assets;
private final int cores;
public Engine(int cores) {
this.cores = cores;
this.poisonAgent = new Agent<SpecificRole, SpecificFinding, SpecificModel>();
this.poisonChallenge = new Challenge<SpecificRole, SpecificFinding, SpecificModel>();
this.agentQueue = new PriorityBlockingQueue<Agent<SpecificRole, SpecificFinding, SpecificModel>>();
this.challengeQueue = new PriorityBlockingQueue<Challenge<SpecificRole, SpecificFinding, SpecificModel>>();
this.settings = new ConcurrentHashMap<SpecificModel, List<SpecificFinding>>();
this.assets = new ConcurrentHashMap<Asset<SpecificRole, SpecificFinding, SpecificModel>, 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<SpecificRole, SpecificFinding, SpecificModel> agent) {
agent.getContext().reset();
this.agentQueue.put(agent);
}
public class SettingRunner extends Thread {
public void run() {
Agent<SpecificRole, SpecificFinding, SpecificModel> agent;
Challenge<SpecificRole, SpecificFinding, SpecificModel> challenge;
Context<SpecificRole, SpecificFinding, SpecificModel> context;
SpecificModel model;
List<SpecificFinding> findings;
PriorityQueue<Challenge<SpecificRole, SpecificFinding, SpecificModel>> preChallenge = new PriorityQueue<Challenge<SpecificRole, SpecificFinding, SpecificModel>>();
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<SpecificRole, SpecificFinding, SpecificModel>(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<SpecificRole, SpecificFinding, SpecificModel> challenge;
Agent<SpecificRole, SpecificFinding, SpecificModel> agent, nextAgent;
Goal<SpecificRole, SpecificFinding, SpecificModel> goal;
Context<SpecificRole, SpecificFinding, SpecificModel> context;
Asset<SpecificRole, SpecificFinding, SpecificModel> 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();
}
}
}
}