LightJason - AgentSpeak(L++)
language/CCommon.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.language;
25 
26 import com.google.common.hash.Hasher;
27 import com.google.common.hash.Hashing;
28 import com.rits.cloning.Cloner;
29 import org.apache.commons.compress.compressors.bzip2.BZip2CompressorOutputStream;
30 import org.apache.commons.compress.compressors.deflate.DeflateCompressorOutputStream;
31 import org.apache.commons.compress.compressors.gzip.GzipCompressorOutputStream;
32 import org.apache.commons.compress.compressors.pack200.Pack200CompressorOutputStream;
33 import org.apache.commons.compress.compressors.xz.XZCompressorOutputStream;
34 import org.apache.commons.compress.utils.IOUtils;
35 import org.apache.commons.io.output.NullOutputStream;
36 import org.apache.commons.lang3.tuple.ImmutablePair;
37 import org.apache.commons.lang3.tuple.Pair;
48 
49 import javax.annotation.Nonnull;
50 import javax.annotation.Nullable;
51 import java.io.ByteArrayInputStream;
52 import java.io.DataOutputStream;
53 import java.io.IOException;
54 import java.io.InputStream;
55 import java.io.OutputStream;
56 import java.nio.charset.StandardCharsets;
57 import java.util.Arrays;
58 import java.util.Collection;
59 import java.util.Collections;
60 import java.util.List;
61 import java.util.Locale;
62 import java.util.Map;
63 import java.util.Objects;
64 import java.util.Set;
65 import java.util.stream.Collectors;
66 import java.util.stream.IntStream;
67 import java.util.stream.Stream;
68 
69 
73 public final class CCommon
74 {
78  private static final Cloner CLONER = new Cloner();
79 
83  private CCommon()
84  {
85  }
86 
87  //--- plan / rule instantiation ----------------------------------------------------------------------------------------------------------------------------
88 
96  @Nonnull
97  public static IContext updatecontext( @Nonnull final IContext p_context, @Nonnull final Stream<IVariable<?>> p_unifiedvariables )
98  {
99  p_unifiedvariables.parallel().forEach( i -> p_context.instancevariables().get( i.fqnfunctor() ).set( i.raw() ) );
100  return p_context;
101  }
102 
111  @Nonnull
112  public static IContext instantiate( @Nonnull final IInstantiable p_instance, @Nonnull final IAgent<?> p_agent, @Nonnull final Stream<IVariable<?>> p_variable )
113  {
114  final Set<IVariable<?>> l_variables = p_instance.variables().parallel().map( i -> i.shallowcopy() ).collect( Collectors.toSet() );
115  Stream.concat(
116  p_variable,
117  p_agent.variablebuilder().apply( p_agent, p_instance )
118  )
119  .peek( l_variables::remove )
120  .forEach( l_variables::add );
121 
122  return new CContext( p_agent, p_instance, Collections.unmodifiableSet( l_variables ) );
123  }
124 
125 
135  @Nonnull
136  public static Pair<Boolean, Set<IVariable<?>>> unifytrigger( @Nonnull final IUnifier p_unifier,
137  @Nonnull final ITrigger p_source, @Nonnull final ITrigger p_target )
138  {
139  // filter for avoid duplicated instantiation on non-existing values
140  if ( !( p_source.literal().emptyValues() == p_target.literal().emptyValues() ) )
141  return new ImmutablePair<>( false, Collections.emptySet() );
142 
143  // unify variables, source trigger literal must be copied
144  final Set<IVariable<?>> l_variables = p_unifier.unify( p_source.literal(), p_target.literal().deepcopy().<ILiteral>raw() );
145 
146  // check for completely unification (of all variables)
147  return l_variables.size() == CCommon.variablefrequency( p_target.literal() ).size()
148  ? new ImmutablePair<>( true, l_variables )
149  : new ImmutablePair<>( false, Collections.emptySet() );
150  }
151 
160  @Nonnull
161  public static Pair<IPlanStatistic, IContext> instantiateplan( @Nonnull final IPlanStatistic p_planstatistic,
162  @Nonnull final IAgent<?> p_agent, @Nonnull final Set<IVariable<?>> p_variables )
163  {
164  return new ImmutablePair<>(
165  p_planstatistic,
166  p_planstatistic.plan().instantiate(
167  p_agent,
168  Stream.concat( p_variables.stream(), p_planstatistic.variables() )
169  )
170  );
171  }
172 
173  // --- variable / term helpers -----------------------------------------------------------------------------------------------------------------------------
174 
182  @Nonnull
183  @SafeVarargs
184  @SuppressWarnings( "varargs" )
185  public static <T> Stream<T> streamconcat( @Nonnull final Stream<T>... p_streams )
186  {
187  return Arrays.stream( p_streams ).reduce( Stream::concat ).orElseGet( Stream::empty );
188  }
189 
196  @Nonnull
197  public static Map<IVariable<?>, Integer> variablefrequency( @Nonnull final ILiteral p_literal )
198  {
199  return Collections.unmodifiableMap(
200  flattenrecursive( p_literal.orderedvalues() )
201  .filter( i -> i instanceof IVariable<?> )
202  .map( i -> (IVariable<?>) i )
203  .collect( Collectors.toMap( i -> i, i -> 1, Integer::sum ) )
204  );
205  }
206 
214  @SuppressWarnings( "unchecked" )
215  public static <T> boolean rawvalueAssignableTo( @Nonnull final T p_value, @Nonnull final Class<?>... p_class )
216  {
217  if ( p_value instanceof IVariable<?> )
218  return ( (IVariable<?>) p_value ).valueassignableto( p_class );
219  if ( p_value instanceof IRawTerm<?> )
220  return ( (IRawTerm<?>) p_value ).valueassignableto( p_class );
221 
222  return Arrays.stream( p_class ).anyMatch( i -> i.isAssignableFrom( p_value.getClass() ) );
223  }
224 
225 
233  @Nonnull
234  public static List<ITerm> replaceFromContext( @Nonnull final IContext p_context, @Nonnull final Collection<? extends ITerm> p_terms )
235  {
236  return p_terms.stream().map( i -> replaceFromContext( p_context, i ) ).collect( Collectors.toList() );
237  }
238 
247  @Nonnull
248  public static ITerm replaceFromContext( @Nonnull final IContext p_context, @Nonnull final ITerm p_term )
249  {
250  if ( !( p_term instanceof IVariable<?> ) )
251  return p_term;
252 
253  final IVariable<?> l_variable = p_context.instancevariables().get( p_term.fqnfunctor() );
254  if ( Objects.nonNull( l_variable ) )
255  return l_variable;
256 
257  throw new CIllegalArgumentException(
258  org.lightjason.agentspeak.common.CCommon.languagestring( CCommon.class, "variablenotfoundincontext", p_term.fqnfunctor() )
259  );
260  }
261 
262 
270  @Nonnull
271  public static Stream<ITerm> flatten( @Nonnull final Collection<? extends ITerm> p_terms )
272  {
273  return flattenstream( p_terms.stream() );
274  }
275 
283  @Nonnull
284  public static Stream<ITerm> flatten( @Nonnull final Stream<? extends ITerm> p_terms )
285  {
286  return flattenstream( p_terms );
287  }
288 
295  @Nonnull
296  public static Stream<ITerm> flattenrecursive( @Nonnull final Stream<ITerm> p_input )
297  {
298  return p_input.flatMap( i -> i instanceof ILiteral ? flattenrecursive( ( i.<ILiteral>raw() ).orderedvalues() ) : Stream.of( i ) );
299  }
300 
301  /*
302  * recursive flattering of a stream structure
303  *
304  * @param p_list any stream
305  * @return term stream
306  */
307  @Nonnull
308  @SuppressWarnings( "unchecked" )
309  private static Stream<ITerm> flattenstream( @Nonnull final Stream<?> p_stream )
310  {
311  return p_stream.flatMap( i ->
312  {
313  final Object l_value = i instanceof ITerm ? ( (ITerm) i ).raw() : i;
314  return l_value instanceof Collection<?>
315  ? flattenstream( ( (Collection<?>) l_value ).stream() )
316  : Stream.of( CRawTerm.from( l_value ) );
317  } );
318  }
319 
325  @Nonnull
326  public static Hasher getTermHashing()
327  {
328  return Hashing.sipHash24().newHasher();
329  }
330 
338  @Nullable
339  @SuppressWarnings( "unchecked" )
340  public static <T> T deepclone( @Nullable final T p_object )
341  {
342  return Objects.isNull( p_object ) ? null : CLONER.deepClone( p_object );
343  }
344 
345  // --- compression algorithm -------------------------------------------------------------------------------------------------------------------------------
346 
358  public static double levenshtein( @Nonnull final String p_first, @Nonnull final String p_second, final double p_insertweight,
359  final double p_replaceweight, final double p_deleteweight )
360  {
361  // the array of distances
362  double[] l_cost = IntStream.range( 0, p_first.length() + 1 ).mapToDouble( i -> i ).toArray();
363  double[] l_newcost = new double[l_cost.length];
364 
365  for ( int j = 1; j < p_second.length() + 1; j++ )
366  {
367  l_newcost[0] = j;
368 
369  // calculate cost of operation for all characters
370  for ( int i = 1; i < l_cost.length; i++ )
371  l_newcost[i] = min(
372  l_cost[i - 1] + ( p_first.charAt( i - 1 ) == p_second.charAt( j - 1 ) ? 0 : p_replaceweight ),
373  l_newcost[i - 1] + p_deleteweight,
374  l_cost[i] + p_insertweight
375  );
376 
377  final double[] l_swap = l_cost;
378  l_cost = l_newcost;
379  l_newcost = l_swap;
380  }
381 
382  return l_cost[p_first.length()];
383  }
384 
385 
394  public static double min( final double p_first, final double p_second, final double p_third )
395  {
396  return Math.min( Math.min( p_first, p_second ), p_third );
397  }
398 
399 
408  public static double ncd( @Nonnull final ECompression p_compression, @Nonnull final String p_first, @Nonnull final String p_second )
409  {
410  if ( p_first.equals( p_second ) )
411  return 0;
412 
413  final double l_first = compress( p_compression, p_first );
414  final double l_second = compress( p_compression, p_second );
415  return ( compress( p_compression, p_first + p_second ) - Math.min( l_first, l_second ) ) / Math.max( l_first, l_second );
416  }
417 
418 
427  private static double compress( @Nonnull final ECompression p_compression, @Nonnull final String p_input )
428  {
429  final DataOutputStream l_counting = new DataOutputStream( new NullOutputStream() );
430 
431  try (
432  final InputStream l_input = new ByteArrayInputStream( p_input.getBytes( StandardCharsets.UTF_8 ) );
433  final OutputStream l_compress = p_compression.get( l_counting )
434  )
435  {
436  IOUtils.copy( l_input, l_compress );
437  }
438  catch ( final IOException l_exception )
439  {
440  return 0;
441  }
442 
443  return l_counting.size();
444  }
445 
446 
450  public enum ECompression
451  {
456  XZ;
457 
461  private static final Set<String> ALGORITHMS = Collections.unmodifiableSet(
462  Arrays.stream( ECompression.values() )
463  .map( i -> i.name().toUpperCase( Locale.ROOT ) )
464  .collect( Collectors.toSet() )
465  );
466 
474  @Nonnull
475  public final OutputStream get( @Nonnull final DataOutputStream p_datastream ) throws IOException
476  {
477  switch ( this )
478  {
479  case BZIP : return new BZip2CompressorOutputStream( p_datastream );
480 
481  case GZIP : return new GzipCompressorOutputStream( p_datastream );
482 
483  case DEFLATE : return new DeflateCompressorOutputStream( p_datastream );
484 
485  case PACK200 : return new Pack200CompressorOutputStream( p_datastream );
486 
487  case XZ : return new XZCompressorOutputStream( p_datastream );
488 
489  default :
490  throw new CIllegalStateException( org.lightjason.agentspeak.common.CCommon.languagestring( this, "unknown", this ) );
491  }
492  }
493 
500  @Nonnull
501  public static ECompression from( @Nonnull final String p_value )
502  {
503  return ECompression.valueOf( p_value.toUpperCase( Locale.ROOT ) );
504  }
505 
506 
513  public static boolean exist( @Nonnull final String p_value )
514  {
515  return ALGORITHMS.contains( p_value.toUpperCase( Locale.ROOT ) );
516  }
517 
518  }
519 
520 
521 }
static double min(final double p_first, final double p_second, final double p_third)
returns the minimum of three elemens
interface for (instantiable) plans and logical-rules
static ECompression from( @Nonnull final String p_value)
returns a compression value
static boolean exist( @Nonnull final String p_value)
checks if a compression exists
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
static Stream< ITerm > flattenrecursive( @Nonnull final Stream< ITerm > p_input)
recursive stream of term values
execution context with local data
Definition: IContext.java:42
static Pair< Boolean, Set< IVariable<?> > > unifytrigger( @Nonnull final IUnifier p_unifier, @Nonnull final ITrigger p_source, @Nonnull final ITrigger p_target)
unifies trigger and creates the set of variables
static Stream< ITerm > flatten( @Nonnull final Collection<? extends ITerm > p_terms)
flat term-in-term collection into a straight term list
static List< ITerm > replaceFromContext( @Nonnull final IContext p_context, @Nonnull final Collection<? extends ITerm > p_terms)
replace variables with context variables
static Hasher getTermHashing()
returns the hasing function for term data
static Map< IVariable<?>, Integer > variablefrequency( @Nonnull final ILiteral p_literal)
consts the variables within a literal
static IContext updatecontext( @Nonnull final IContext p_context, @Nonnull final Stream< IVariable<?>> p_unifiedvariables)
updates within an instance context all variables of the stream
static Pair< IPlanStatistic, IContext > instantiateplan( @Nonnull final IPlanStatistic p_planstatistic, @Nonnull final IAgent<?> p_agent, @Nonnull final Set< IVariable<?>> p_variables)
instantiate a plan with context and plan-specific variables
static ITerm replaceFromContext( @Nonnull final IContext p_context, @Nonnull final ITerm p_term)
replace variable with context variable other values will be passed without context access ...
static Stream< ITerm > flattenstream( @Nonnull final Stream<?> p_stream)
< T > T raw()
cast to any raw value type
static< N > CRawTerm< N > from(final N p_value)
factory for a raw term
Definition: CRawTerm.java:104
CCommon()
private ctor - avoid instantiation
static double ncd( @Nonnull final ECompression p_compression, @Nonnull final String p_first, @Nonnull final String p_second)
normalized-compression-distance
static double levenshtein( @Nonnull final String p_first, @Nonnull final String p_second, final double p_insertweight, final double p_replaceweight, final double p_deleteweight)
calculates the levenshtein distance
static IContext instantiate( @Nonnull final IInstantiable p_instance, @Nonnull final IAgent<?> p_agent, @Nonnull final Stream< IVariable<?>> p_variable)
creates the instantiate execution context with default variables
term structure for simple datatypes
Definition: CRawTerm.java:45
static double compress( @Nonnull final ECompression p_compression, @Nonnull final String p_input)
compression algorithm
static Stream< ITerm > flatten( @Nonnull final Stream<? extends ITerm > p_terms)
flat term-in-term stream into a straight term list