You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
yacy_search_server/source/net/yacy/ai/greedy/Engine.java

266 lines
13 KiB

/**
* Engine.java
* Copyright 2009 by Michael Peter Christen, Frankfurt a. M., Germany
* First published 03.12.2009 at http://yacy.net
*
* $LastChangedDate$
* $LastChangedRevision$
* $LastChangedBy$
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
* This library 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
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public License
* along with this program in the file lgpl21.txt
* If not, see <http://www.gnu.org/licenses/>.
*/
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>
> {
protected final PriorityBlockingQueue<Agent<SpecificRole, SpecificFinding, SpecificModel>> agentQueue;
protected final PriorityBlockingQueue<Challenge<SpecificRole, SpecificFinding, SpecificModel>> challengeQueue;
protected final Agent<SpecificRole, SpecificFinding, SpecificModel> poisonAgent;
protected final Challenge<SpecificRole, SpecificFinding, SpecificModel> poisonChallenge;
protected final ConcurrentHashMap<SpecificModel, List<SpecificFinding>> settings;
protected 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 {
@Override
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")
@Override
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;
String debug = agent.getModel().toString() + "\nwill apply " + challenge.getFinding().toString();
System.out.println(debug);
if (debug.equals("[],[3, 2],[1]\nwill apply 2 -> 1")) {
System.out.println("one more please");
}
// apply finding: compute next model
// avoid double computation of findings using cached assets
if (context.useAssetCache()) {
asset = new Asset<SpecificRole, SpecificFinding, SpecificModel>(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<SpecificRole, SpecificFinding, SpecificModel>(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<SpecificRole, SpecificFinding, SpecificModel>(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();
if (goal.isFulfilled(nextAgent.getModel())) nextAgent.getContext().announceCompletion();
// 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 time-out for snapshot
if (nextAgent.getContext().isSnapshotTimeout()) {
nextAgent.addResult();
}
// 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();
}
}
}
}