/*
* Operator.java
*
* Copyright (C) 2008 Pei Wang
*
* This file is part of Open-NARS.
*
* Open-NARS 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.
*
* Open-NARS 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 Open-NARS. If not, see <http://www.gnu.org/licenses/>.
*/
package nars.operator;
import nars.util.Plugin;
import java.util.Arrays;
import java.util.List;
import nars.storage.Memory;
import nars.NAR;
import nars.config.Parameters;
import nars.entity.BudgetValue;
import nars.entity.Task;
import nars.entity.TruthValue;
import nars.io.Output.EXE;
import nars.language.Product;
import nars.language.Statement;
import nars.language.Term;
/**
* An individual operator that can be execute by the system, which can be either
* inside NARS or outside it, in another system or device.
* <p>
* This is the only file to modify when registering a new operator into NARS.
*/
public abstract class Operator extends Term implements Plugin {
public static final float executionConfidence = Parameters.MAX_CONFIDENCE; // 0.9999f;
protected Operator() { super(); }
protected Operator(String name) {
super(name);
if (!name.startsWith("^"))
throw new RuntimeException("Operator name needs ^ prefix");
}
public NAR nar;
@Override
public boolean setEnabled(NAR n, boolean enabled) {
this.nar = n;
return true;
}
/**
* Required method for every operator, specifying the corresponding
* operation
*
* @param args Arguments of the operation, both input (constant) and output (variable)
* @param memory The memory to work on
* @return The direct collectable results and feedback of the
* reportExecution
*/
protected abstract List<Task> execute(Operation operation, Term[] args, Memory memory);
/**
* The standard way to carry out an operation, which invokes the execute
* method defined for the operator, and handles feedback tasks as input
*
* @param op The operator to be executed
* @param args The arguments to be taken by the operator
* @param memory The memory on which the operation is executed
* @return true if successful, false if an error occurred
*/
public final boolean call(final Operation operation, final Term[] args, final Memory memory) {
try {
List<Task> feedback = execute(operation, args, memory);
memory.executedTask(operation, new TruthValue(1f,executionConfidence));
reportExecution(operation, args, feedback, memory);
if (feedback!=null) {
for (final Task t : feedback) {
memory.inputTask(t);
}
}
return true;
}
// catch (NegativeFeedback n) {
//
// if (n.freqOcurred >=0 && n.confidenceOcurred >= 0) {
// memory.executedTask(operation, new TruthValue(n.freqOcurred, n.confidenceOcurred));
// }
//
// if (n.freqCorrection >= 0 && n.confCorrection >=0) {
// //for inputting an inversely frequent goal to counteract a repeat invocation
// BudgetValue b = operation.getTask().budget;
// float priority = b.getPriority();
// float durability = b.getDurability();
//
// memory.addNewTask(
// memory.newTask(operation, Symbols.GOAL_MARK, n.freqCorrection, n.confCorrection, priority, durability, (Tense)null),
// "Negative feedback"
// );
//
// }
//
// if (!n.quiet) {
// reportExecution(operation, args, n, memory);
// }
// }
catch (Exception e) {
//reportExecution(operation, args, e, memory);
}
return false;
}
public static String operationExecutionString(final Statement operation) {
Term operator = operation.getPredicate();
Term arguments = operation.getSubject();
String argList = arguments.toString().substring(3); // skip the product prefix "(*,"
return operator + "(" + argList;
}
@Override
public Operator clone() {
//do not clone operators, just use as-is since it's effectively immutable
return this;
}
// /**
// * Display a message in the output stream to indicate the reportExecution of
// * an operation
// * <p>
// * @param operation The content of the operation to be executed
// */
public static void reportExecution(final Operation operation, final Term[] args, Object feedback, final Memory memory) {
final Term opT = operation.getPredicate();
if(!(opT instanceof Operator)) {
return;
}
if (memory.emitting(EXE.class)) {
final Operator operator = (Operator) opT;
if (feedback instanceof Exception)
feedback = feedback.getClass().getSimpleName() + ": " + ((Throwable)feedback).getMessage();
memory.emit(EXE.class,
new ExecutionResult(operation, feedback));
}
}
public static class ExecutionResult {
private final Operation operation;
private final Object feedback;
public ExecutionResult(Operation op, Object feedback) {
this.operation = op;
this.feedback = feedback;
}
public Task getTask() { return operation.getTask(); }
@Override
public String toString() {
BudgetValue b = null;
if (getTask() != null) {
b = getTask().budget;
}
Term[] args = operation.getArguments().term;
Operator operator = operation.getOperator();
return ((b != null) ? (b.toStringExternal() + " ") : "") +
operator + "(" + Arrays.toString(args) + ")=" + feedback;
}
}
public final boolean call(final Operation op, final Memory memory) {
if(!op.isExecutable(memory)) {
return false;
}
Product args = op.getArguments();
return call(op, args.term, memory);
}
public static String addPrefixIfMissing(String opName) {
if (!opName.startsWith("^"))
return '^' + opName;
return opName;
}
// public static class NegativeFeedback extends RuntimeException {
//
// /** convenience method for creating a "never again" negative feedback"*/
// public static NegativeFeedback never(String reason, boolean quiet) {
// return new NegativeFeedback(reason, 0, executionConfidence,
// 0, executionConfidence, quiet
// );
// }
// /** convenience method for ignoring an invalid operation; does not recognize that it occurred, and does not report anything*/
// public static NegativeFeedback ignore(String reason) {
// return new NegativeFeedback(reason, -1, -1, -1, -1, true);
// }
//
// public final float freqCorrection;
// public final float confCorrection;
// public final float freqOcurred;
// public final float confidenceOcurred;
// public final boolean quiet;
//
// public NegativeFeedback(String reason, float freqOcurred, float confidenceOccurred, float freqCorrection, float confCorrection, boolean quiet) {
// super(reason);
// this.freqOcurred = freqOcurred;
// this.confidenceOcurred = confidenceOccurred;
// this.freqCorrection = freqCorrection;
// this.confCorrection = confCorrection;
// this.quiet = quiet;
// }
// }
}