LightJason - AgentSpeak(L++)
IBaseAgent.java
Go to the documentation of this file.
1 /*
2  * @cond LICENSE
3  * ######################################################################################
4  * # LGPL License #
5  * # #
6  * # This file is part of the LightJason AgentSpeak(L++) #
7  * # Copyright (c) 2015-19, LightJason (info@lightjason.org) #
8  * # This program is free software: you can redistribute it and/or modify #
9  * # it under the terms of the GNU Lesser General Public License as #
10  * # published by the Free Software Foundation, either version 3 of the #
11  * # License, or (at your option) any later version. #
12  * # #
13  * # This program is distributed in the hope that it will be useful, #
14  * # but WITHOUT ANY WARRANTY; without even the implied warranty of #
15  * # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the #
16  * # GNU Lesser General Public License for more details. #
17  * # #
18  * # You should have received a copy of the GNU Lesser General Public License #
19  * # along with this program. If not, see http://www.gnu.org/licenses/ #
20  * ######################################################################################
21  * @endcond
22  */
23 
24 package org.lightjason.agentspeak.agent;
25 
26 import com.codepoetics.protonpack.StreamUtils;
27 import com.google.common.collect.HashMultimap;
28 import com.google.common.collect.ImmutableMultimap;
29 import com.google.common.collect.LinkedHashMultimap;
30 import com.google.common.collect.Multimap;
31 import com.google.common.collect.Multimaps;
32 import com.google.common.collect.TreeMultimap;
33 import org.apache.commons.lang3.StringUtils;
34 import org.apache.commons.lang3.tuple.ImmutablePair;
35 import org.apache.commons.lang3.tuple.Pair;
56 
57 import javax.annotation.Nonnegative;
58 import javax.annotation.Nonnull;
59 import javax.annotation.Nullable;
60 import java.text.MessageFormat;
61 import java.util.Arrays;
62 import java.util.Collection;
63 import java.util.Collections;
64 import java.util.Comparator;
65 import java.util.HashSet;
66 import java.util.Map;
67 import java.util.Objects;
68 import java.util.Set;
69 import java.util.concurrent.ConcurrentHashMap;
70 import java.util.concurrent.atomic.AtomicLong;
71 import java.util.logging.Logger;
72 import java.util.stream.Collectors;
73 import java.util.stream.Stream;
74 
75 
81 public abstract class IBaseAgent<T extends IAgent<?>> implements IAgent<T>
82 {
86  protected static final Logger LOGGER = org.lightjason.agentspeak.common.CCommon.logger( IAgent.class );
90  private static final long serialVersionUID = -304366902555398136L;
94  protected final IView m_beliefbase;
100  protected final Map<String, Object> m_storage = new ConcurrentHashMap<>();
104  protected final Map<Integer, ITrigger> m_trigger = new ConcurrentHashMap<>();
108  protected final Multimap<IPath, IRule> m_rules = Multimaps.synchronizedMultimap( LinkedHashMultimap.create() );
112  protected final Multimap<ITrigger, IPlanStatistic> m_plans = Multimaps.synchronizedMultimap(
113  TreeMultimap.create( IStructureHash.COMPARATOR, Comparator.<IPlanStatistic>naturalOrder() ) );
117  private final AtomicLong m_cycletime = new AtomicLong();
124  private final AtomicLong m_sleepingcycles = new AtomicLong( Long.MIN_VALUE );
128  private final Set<ITerm> m_sleepingterm = Collections.synchronizedSet( new HashSet<>() );
132  private final IUnifier m_unifier;
144  private final Multimap<IPath, ILiteral> m_runningplans = Multimaps.synchronizedSetMultimap( HashMultimap.create() );
145 
146 
147 
153  public IBaseAgent( @Nonnull final IAgentConfiguration<T> p_configuration )
154  {
155  // initialize agent
156  m_unifier = p_configuration.unifier();
157  m_beliefbase = p_configuration.beliefbase();
158  m_variablebuilder = p_configuration.variablebuilder();
159  m_fuzzy = p_configuration.fuzzy();
160 
161  // initial plans and rules
162  p_configuration.plans().parallelStream().forEach( i -> m_plans.put( i.trigger(), CPlanStatistic.from( i ) ) );
163  p_configuration.rules().parallelStream().forEach( i -> m_rules.put( i.identifier().fqnfunctor(), i ) );
164  if ( Objects.nonNull( p_configuration.initialgoal() ) )
165  m_trigger.put( p_configuration.initialgoal().hashCode(), p_configuration.initialgoal() );
166  }
167 
168  @Nonnull
169  @Override
170  public final IView beliefbase()
171  {
172  return m_beliefbase;
173  }
174 
175  @Nonnull
176  @Override
177  @SafeVarargs
178  @SuppressWarnings( "varargs" )
179  public final <N extends IInspector> Stream<N> inspect( @Nonnull final N... p_inspector )
180  {
181  return Arrays.stream( p_inspector )
182  .parallel()
183  .peek( i ->
184  {
185  i.inspectcycletime( m_cycletime.get() );
186  i.inspectsleeping( m_sleepingcycles.get() );
187  i.inspectbelief( m_beliefbase.stream() );
188  i.inspectplans( m_plans.values().stream() );
189  i.inspectrunningplans( m_runningplans.values().stream() );
190  i.inspectstorage( m_storage.entrySet().stream() );
191  i.inspectrules( m_rules.values().stream() );
192  } );
193  }
194 
195  @Nonnull
196  @Override
197  public final Multimap<IPath, ILiteral> runningplans()
198  {
199  return ImmutableMultimap.copyOf( m_runningplans );
200  }
201 
202  @Override
203  public final boolean sleeping()
204  {
205  return m_sleepingcycles.get() > 0;
206  }
207 
208  @Nonnull
209  @Override
210  public final IAgent<T> sleep( final long p_cycles, final ITerm... p_term )
211  {
212  return this.sleep(
213  p_cycles,
214  ( Objects.isNull( p_term ) ) || ( p_term.length == 0 )
215  ? Stream.of()
216  : Arrays.stream( p_term )
217  );
218  }
219 
220  @Nonnull
221  @Override
222  public final IAgent<T> sleep( final long p_cycles, @Nonnull final Stream<ITerm> p_literal )
223  {
224  m_sleepingcycles.set( p_cycles );
225  p_literal.filter( i -> !i.hasVariable() ).forEach( m_sleepingterm::add );
226  return this;
227  }
228 
229  @Nonnull
230  @Override
231  public final IAgent<T> wakeup( @Nullable final ITerm... p_term )
232  {
233  return this.wakeup(
234  ( Objects.isNull( p_term ) ) || ( p_term.length == 0 )
235  ? Stream.of()
236  : Arrays.stream( p_term )
237  );
238  }
239 
240  @Nonnull
241  @Override
242  public final IAgent<T> wakeup( @Nonnull final Stream<ITerm> p_term )
243  {
244  p_term.forEach( m_sleepingterm::add );
245  this.active( true );
246  return this;
247  }
248 
249  @Nonnull
250  @Override
251  public final Map<String, Object> storage()
252  {
253  return m_storage;
254  }
255 
256  @Nonnull
257  @Override
258  public final IUnifier unifier()
259  {
260  return m_unifier;
261  }
262 
263  @Nonnegative
264  @Override
265  public final long cycletime()
266  {
267  return m_cycletime.get();
268  }
269 
270  @Nonnull
271  @Override
272  public final Multimap<ITrigger, IPlanStatistic> plans()
273  {
274  return m_plans;
275  }
276 
277  @Nonnull
278  @Override
280  {
281  return m_fuzzy;
282  }
283 
284  @Nonnull
285  @Override
287  {
288  return m_variablebuilder;
289  }
290 
291  @Nonnull
292  @Override
293  public final Multimap<IPath, IRule> rules()
294  {
295  return m_rules;
296  }
297 
298  @Nonnull
299  @Override
300  @SuppressWarnings( "unchecked" )
301  public final <N extends IAgent<?>> N raw()
302  {
303  return (N) this;
304  }
305 
306  @Override
307  public String toString()
308  {
309  return MessageFormat.format(
310  "{0} ( {1} )",
311  super.toString(),
312  StringUtils.join(
313  StreamUtils.zip(
314  Stream.of( "Trigger", "Running Plans", "Beliefbase" ),
315  Stream.of( m_trigger.values(), m_runningplans.keySet(), m_beliefbase ),
316  ( l, c ) -> MessageFormat.format( "{0}: {1}", l, c )
317  ).toArray(),
318  " / "
319  )
320  );
321  }
322 
323  @Nonnull
324  @Override
325  public final IFuzzyValue<Boolean> trigger( @Nonnull final ITrigger p_trigger, @Nullable final boolean... p_immediately )
326  {
327  if ( m_sleepingcycles.get() > 0 )
328  return CFuzzyValue.from( false );
329 
330  // check if literal does not store any variables
331  if ( p_trigger.literal().hasVariable() )
332  throw new CIllegalArgumentException( org.lightjason.agentspeak.common.CCommon.languagestring( this, "literalvariable", p_trigger ) );
333 
334  // run plan immediatly and return
335  if ( ( Objects.nonNull( p_immediately ) ) && ( p_immediately.length > 0 ) && ( p_immediately[0] ) )
336  return this.execute( this.generateexecution( Stream.of( p_trigger ) ) );
337 
338  // add trigger for the next cycle must be synchronized to avoid indeterministic state during execution
339  synchronized ( this )
340  {
341  m_trigger.putIfAbsent( p_trigger.hashCode(), p_trigger );
342  }
343 
344  return CFuzzyValue.from( true );
345  }
346 
347  @Override
348  @SuppressWarnings( "unchecked" )
349  public T call() throws Exception
350  {
351  // run beliefbase update, because environment can be changed and decrement sleeping value
352  m_beliefbase.update( (T) this );
353  if ( !this.active( false ) )
354  // check wakup-event otherwise suspend
355  return (T) this;
356 
357  // update defuzzification
358  m_fuzzy.getValue().update( this );
359 
360  // clear running plan- and trigger list and execute elements
361  this.execute( this.generateexecutionlist() );
362 
363 
364  // set the cycle time
365  m_cycletime.set( System.nanoTime() );
366 
367  return (T) this;
368  }
369 
377  @Nonnull
378  private synchronized Collection<Pair<IPlanStatistic, IContext>> generateexecutionlist()
379  {
380  m_runningplans.clear();
381  final Collection<Pair<IPlanStatistic, IContext>> l_execution = this.generateexecution(
382  Stream.concat(
383  m_trigger.values().parallelStream(),
384  m_beliefbase.trigger().parallel()
385  )
386  );
387  m_trigger.clear();
388 
389  return l_execution;
390  }
391 
392 
399  @Nonnull
400  private Collection<Pair<IPlanStatistic, IContext>> generateexecution( @Nonnull final Stream<ITrigger> p_trigger )
401  {
402  return p_trigger
403  .filter( Objects::nonNull )
404  // get all possible plans
405  .flatMap( i -> m_plans.get( i ).stream().map( j -> new ImmutablePair<>( i, j ) ) )
406  .parallel()
407  // tries to unify trigger literal and filter of valid unification (returns set of unified variables)
408  .map( i -> new ImmutablePair<>( i, CCommon.unifytrigger( m_unifier, i.getLeft(), i.getRight().plan().trigger() ) ) )
409  // check if unification was possible
410  .filter( i -> i.getRight().getLeft() )
411  // create execution context
412  .map( i -> CCommon.instantiateplan( i.getLeft().getRight(), this, i.getRight().getRight() ) )
413  // check plan-condition
414  .filter( i -> m_fuzzy.getValue().defuzzify( i.getLeft().plan().condition( i.getRight() ) ) )
415  // collectors-call must be toList not toSet because plan-execution can be have equal elements
416  // so a set avoid multiple plan-execution
417  .collect( Collectors.toList() );
418  }
419 
426  @Nonnull
427  private IFuzzyValue<Boolean> execute( @Nonnull final Collection<Pair<IPlanStatistic, IContext>> p_execution )
428  {
429  // update executable plan list, so that test-goals are defined all the time
430  p_execution.parallelStream().forEach( i -> m_runningplans.put(
431  i.getLeft().plan().trigger().literal().fqnfunctor(),
432  i.getLeft().plan().trigger().literal().unify( i.getRight() )
433  ) );
434 
435  // execute plan and return values and return execution result
436  return p_execution.parallelStream()
437  .map( i ->
438  {
439  final IFuzzyValue<Boolean> l_result = i.getLeft()
440  .plan()
441  .execute( false, i.getRight(), Collections.emptyList(), Collections.emptyList() );
442  if ( m_fuzzy.getValue().defuzzify( l_result ) )
443  // increment successful runs
444  i.getLeft().incrementsuccessful();
445  else
446  // increment failed runs and create delete goal-event
447  i.getLeft().incrementfail();
448  return l_result;
449  } ).collect( m_fuzzy.getKey() );
450  }
451 
458  private boolean active( final boolean p_immediatly )
459  {
460  // if the sleeping time ends or the agent will wakedup by a hard call,
461  // create the trigger and reset the time value
462  if ( ( m_sleepingcycles.compareAndSet( 0, Long.MIN_VALUE ) ) || p_immediatly )
463  {
464  (
465  m_sleepingterm.isEmpty()
466 
467  ? Stream.of( CTrigger.from(
469  "wakeup"
470  )
471  ) )
472 
473  : m_sleepingterm.parallelStream()
474  .map( i -> CTrigger.from(
476  CLiteral.from( "wakeup", i )
477  ) )
478 
479  ).forEach( i -> m_trigger.put( i.structurehash(), i ) );
480 
481  m_sleepingterm.clear();
482  }
483 
484  // if the sleeping time is not infinity decrese the counter
485  if ( ( m_sleepingcycles.get() > 0 ) && ( m_sleepingcycles.get() != Long.MAX_VALUE ) )
486  m_sleepingcycles.decrementAndGet();
487 
488  return m_sleepingcycles.get() <= 0;
489  }
490 
491 }
final Multimap< IPath, ILiteral > m_runningplans
running plans (thread-safe)
Comparator< IStructureHash > COMPARATOR
comparator
final Multimap< IPath, IRule > m_rules
multimap with rules
final AtomicLong m_cycletime
nano seconds at the last cycle
static final Logger LOGGER
logger
Definition: IBaseAgent.java:86
final Map< String, Object > storage()
boolean active(final boolean p_immediatly)
runs the wakeup goal
Collection< Pair< IPlanStatistic, IContext > > generateexecution( @Nonnull final Stream< ITrigger > p_trigger)
create execution list with plan and context
final Set< ITerm > m_sleepingterm
set for waking-up literals
Stream< ITrigger > trigger()
retruns all trigger of the beliefbase
IAgent<?> update( @Nonnull final IAgent<?> p_agent)
updates all items
static< N > IFuzzyValue< N > from( @Nonnull final N p_value)
factory
final Map< String, Object > m_storage
storage map
synchronized Collection< Pair< IPlanStatistic, IContext > > generateexecutionlist()
create the plan executionlist with clearing internal structures
final IAgent< T > sleep(final long p_cycles, @Nonnull final Stream< ITerm > p_literal)
common structure for execution definition
final IFuzzyValue< Boolean > trigger( @Nonnull final ITrigger p_trigger, @Nullable final boolean... p_immediately)
final< N extends IInspector > Stream< N > inspect( @Nonnull final N... p_inspector)
static< T > String languagestring(final T p_source, final String p_label, final Object... p_parameter)
returns the language depend string on any object
interface of an unification algorithm
Definition: IUnifier.java:43
Stream< ILiteral > stream( @Nullable final IPath... p_path)
returns stream of literal
final Multimap< ITrigger, IPlanStatistic > plans()
static ITrigger from( @Nonnull final EType p_event, @Nonnull final ILiteral p_literal)
creates a trigger event^
Definition: CTrigger.java:87
final IVariableBuilder variablebuilder()
IBeliefbase beliefbase()
returns the beliefbase
view for a beliefbase that creates any access to the underlying data structures
Definition: IView.java:44
execution context with local data
Definition: IContext.java:42
static Logger logger(final Class<?> p_class)
returns a logger instance
final< N extends IAgent<?> > N raw()
static final long serialVersionUID
serial id
Definition: IBaseAgent.java:90
result for an immutable fuzzy value
final IFuzzyBundle< Boolean > m_fuzzy
fuzzy result collector
default generic literal class for agent beliefs a literal consists of a functor, an optional list of ...
Definition: CLiteral.java:64
final IAgent< T > sleep(final long p_cycles, final ITerm... p_term)
final Multimap< IPath, IRule > rules()
interface for a variable builder which is called on each plan / rule execution
final Map< Integer, ITrigger > m_trigger
execution trigger with content hash
static ILiteral from( @Nonnull final String p_functor, @Nullable final ITerm... p_values)
factory
Definition: CLiteral.java:161
final IAgent< T > wakeup( @Nullable final ITerm... p_term)
final Multimap< ITrigger, IPlanStatistic > m_plans
map with all existing plans and successful / fail runs
final AtomicLong m_sleepingcycles
number of sleeping cycles
final IFuzzyBundle< Boolean > fuzzy()
IBaseAgent( @Nonnull final IAgentConfiguration< T > p_configuration)
ctor
IFuzzyValue< Boolean > execute( @Nonnull final Collection< Pair< IPlanStatistic, IContext >> p_execution)
execute list of plans
final IVariableBuilder m_variablebuilder
variable builder
final Multimap< IPath, ILiteral > runningplans()
final IAgent< T > wakeup( @Nonnull final Stream< ITerm > p_term)
inspector interface to read agent internal data
Definition: IInspector.java:39