/*
* TaskLink.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.entity;
import java.util.ArrayDeque;
import java.util.Deque;
import java.util.Iterator;
import nars.config.Parameters;
import nars.language.Term;
/**
* Reference to a Task.
* <p>
* The reason to separate a Task and a TaskLink is that the same Task can be
* linked from multiple Concepts, with different BudgetValue.
*
* TaskLinks are unique according to the Task they reference
*/
public class TaskLink extends Item<Task> implements TLink<Task> {
/**
* The Task linked. The "target" field in TermLink is not used here.
*/
public final Task targetTask;
private final int recordLength;
/* Remember the TermLinks, and when they has been used recently with this TaskLink */
public final static class Recording {
public final TermLink link;
long time;
public Recording(TermLink link, long time) {
this.link = link;
this.time = time;
}
public long getTime() {
return time;
}
public void setTime(long t) {
this.time = t;
}
}
public final Deque<Recording> records;
/** The type of link, one of the above */
public final short type;
/** The index of the component in the component list of the compound, may have up to 4 levels */
public final short[] index;
/**
* Constructor
* <p>
* only called in Memory.continuedProcess
*
* @param t The target Task
* @param template The TermLink template
* @param v The budget
*/
public TaskLink(final Task t, final TermLink template, final BudgetValue v, int recordLength) {
super(v);
this.type =
template == null ?
TermLink.SELF :
template.type;
this.index =
template == null ?
null :
template.index
;
this.targetTask = t;
this.recordLength = recordLength;
this.records = new ArrayDeque(recordLength);
}
@Override
public int hashCode() {
return targetTask.hashCode();
}
@Override
public Task name() {
return targetTask;
}
@Override
public boolean equals(Object obj) {
if (obj == this) return true;
if (obj instanceof TaskLink) {
TaskLink t = (TaskLink)obj;
return t.targetTask.equals(targetTask);
}
return false;
}
/**
* Get one index by level
* @param i The index level
* @return The index value
*/
@Override
public final short getIndex(final int i) {
if ((index != null) && (i < index.length)) {
return index[i];
} else {
return -1;
}
}
/**
* To check whether a TaskLink should use a TermLink, return false if they
* interacted recently
* <p>
* called in TermLinkBag only
*
* @param termLink The TermLink to be checked
* @param currentTime The current time
* @return Whether they are novel to each other
*/
public boolean novel(final TermLink termLink, final long currentTime) {
final Term bTerm = termLink.target;
if (bTerm.equals(targetTask.sentence.term)) {
return false;
}
TermLink linkKey = termLink.name();
int next, i;
//iterating the FIFO deque from oldest (first) to newest (last)
Iterator<Recording> ir = records.iterator();
while (ir.hasNext()) {
Recording r = ir.next();
if (linkKey.equals(r.link)) {
if (currentTime < r.getTime() + Parameters.NOVELTY_HORIZON) {
//too recent, not novel
return false;
} else {
//happened long enough ago that we have forgotten it somewhat, making it seem more novel
r.setTime(currentTime);
ir.remove();
records.addLast(r);
return true;
}
}
}
//keep recordedLinks queue a maximum finite size
while (records.size() + 1 >= recordLength) records.removeFirst();
// add knowledge reference to recordedLinks
records.addLast(new Recording(linkKey, currentTime));
return true;
}
@Override
public String toString() {
return super.toString() + " " + getTarget().sentence.stamp;
}
public String toStringBrief() {
return super.toString();
}
/**
* Get the target Task
*
* @return The linked Task
*/
@Override public Task getTarget() {
return targetTask;
}
@Override
public void end() {
records.clear();
}
public Term getTerm() {
return getTarget().getTerm();
}
}