LightJason - AgentSpeak(L++)
CConsistency.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.consistency;
25 
26 import cern.colt.function.tdouble.DoubleFunction;
27 import cern.colt.matrix.tdouble.DoubleFactory1D;
28 import cern.colt.matrix.tdouble.DoubleMatrix1D;
29 import cern.colt.matrix.tdouble.DoubleMatrix2D;
30 import cern.colt.matrix.tdouble.algo.DenseDoubleAlgebra;
31 import cern.colt.matrix.tdouble.algo.decomposition.DenseDoubleEigenvalueDecomposition;
32 import cern.colt.matrix.tdouble.impl.DenseDoubleMatrix1D;
33 import cern.colt.matrix.tdouble.impl.DenseDoubleMatrix2D;
34 import cern.jet.math.tdouble.DoubleFunctions;
35 import cern.jet.math.tdouble.DoubleMult;
36 import org.apache.commons.math3.stat.descriptive.DescriptiveStatistics;
37 import org.apache.commons.math3.stat.descriptive.SynchronizedDescriptiveStatistics;
43 
44 import javax.annotation.Nonnegative;
45 import javax.annotation.Nonnull;
46 import java.text.MessageFormat;
47 import java.util.AbstractMap;
48 import java.util.ArrayList;
49 import java.util.Map;
50 import java.util.concurrent.ConcurrentHashMap;
51 import java.util.stream.IntStream;
52 import java.util.stream.Stream;
53 
54 
58 public final class CConsistency implements IConsistency
59 {
63  private static final Map.Entry<Double, Double> DEFAULTNONEXISTING = new AbstractMap.SimpleImmutableEntry<>( 1.0, 0.0 );
67  private static final DenseDoubleAlgebra ALGEBRA = DenseDoubleAlgebra.DEFAULT;
71  private static final DoubleFunction PROBABILITYINVERT = p_value -> 1 - p_value;
75  private final EAlgorithm m_algorithm;
79  private final Map<IAgent<?>, Map.Entry<Double, Double>> m_data = new ConcurrentHashMap<>();
83  private final DescriptiveStatistics m_statistic = new SynchronizedDescriptiveStatistics();
87  private final IFilter m_filter;
91  private final IMetric m_metric;
95  private final double m_epsilon;
99  private final int m_iteration;
100 
101 
111  private CConsistency( @Nonnull final EAlgorithm p_algorithm, @Nonnull final IFilter p_filter, @Nonnull final IMetric p_metric,
112  final int p_iteration, final double p_epsilon )
113  {
114  m_filter = p_filter;
115  m_metric = p_metric;
116  m_algorithm = p_algorithm;
117  m_iteration = p_iteration;
118  m_epsilon = p_epsilon;
119  }
120 
121  @Nonnull
122  @Override
123  public final DescriptiveStatistics statistic()
124  {
125  return m_statistic;
126  }
127 
128  @Nonnull
129  @Override
130  public final IConsistency add( @Nonnull final IAgent<?> p_object )
131  {
132  m_data.putIfAbsent( p_object, DEFAULTNONEXISTING );
133  return this;
134  }
135 
136  @Override
137  public final IConsistency call() throws Exception
138  {
139  if ( m_data.size() < 2 )
140  return this;
141 
142  // get key list of map for addressing elements in the correct order
143  final ArrayList<IAgent<?>> l_keys = new ArrayList<>( m_data.keySet() );
144 
145  // calculate markov chain transition matrix
146  final DoubleMatrix2D l_matrix = new DenseDoubleMatrix2D( m_data.size(), m_data.size() );
147  IntStream.range( 0, l_keys.size() )
148  .parallel()
149  .boxed()
150  .forEach( i ->
151  {
152  final IAgent<?> l_item = l_keys.get( i );
153  IntStream.range( i + 1, l_keys.size() )
154  .boxed()
155  .forEach( j ->
156  {
157  final double l_value = this.getMetricValue( l_item, l_keys.get( j ) );
158  l_matrix.setQuick( i, j, l_value );
159  l_matrix.setQuick( j, i, l_value );
160  } );
161 
162  // row-wise normalization for getting probabilities
163  final double l_norm = ALGEBRA.norm1( l_matrix.viewRow( i ) );
164  if ( l_norm != 0 )
165  l_matrix.viewRow( i ).assign( DoubleMult.div( l_norm ) );
166 
167  // set epsilon slope for preventing periodic markov chains
168  l_matrix.setQuick( i, i, m_epsilon );
169  } );
170 
171  // check for a zero-matrix
172  final DoubleMatrix1D l_eigenvector = l_matrix.zSum() <= m_data.size() * m_epsilon
173  ? new DenseDoubleMatrix1D( m_data.size() )
174  : m_algorithm.getStationaryDistribution( m_iteration, l_matrix );
175 
176  // calculate the inverted probability and normalize with 1-norm
177  final DoubleMatrix1D l_invertedeigenvector = new DenseDoubleMatrix1D( l_eigenvector.toArray() );
178  l_invertedeigenvector.assign( PROBABILITYINVERT );
179  l_invertedeigenvector.assign( DoubleFunctions.div( ALGEBRA.norm1( l_eigenvector ) ) );
180 
181  // set consistency for each entry and update statistic
182  m_statistic.clear();
183  IntStream.range( 0, l_keys.size() )
184  .boxed()
185  .forEach( i ->
186  {
187  m_statistic.addValue( l_eigenvector.get( i ) );
188  m_data.put( l_keys.get( i ), new AbstractMap.SimpleImmutableEntry<>( l_invertedeigenvector.get( i ), l_eigenvector.get( i ) ) );
189  } );
190 
191  return this;
192  }
193 
194  @Nonnull
195  @Override
196  public final IConsistency remove( @Nonnull final IAgent<?> p_object )
197  {
198  m_data.remove( p_object );
199  return this;
200  }
201 
202  @Nonnull
203  @Override
204  public final IConsistency clear()
205  {
206  m_statistic.clear();
207  m_data.clear();
208  return this;
209  }
210 
211  @Nonnull
212  @Override
213  public final IMetric metric()
214  {
215  return m_metric;
216  }
217 
218  @Nonnull
219  @Override
220  public final IFilter filter()
221  {
222  return m_filter;
223  }
224 
225  @Nonnull
226  @Override
227  public final Stream<Map.Entry<IAgent<?>, Double>> consistency()
228  {
229  return m_data.entrySet().stream().map( i -> new AbstractMap.SimpleImmutableEntry<>( i.getKey(), i.getValue().getKey() ) );
230  }
231 
232  @Nonnegative
233  @Override
234  public final double consistency( @Nonnull final IAgent<?> p_object )
235  {
236  return m_data.getOrDefault( p_object, DEFAULTNONEXISTING ).getKey();
237  }
238 
239  @Nonnegative
240  @Override
241  public final double inconsistency( @Nonnull final IAgent<?> p_object )
242  {
243  return m_data.getOrDefault( p_object, DEFAULTNONEXISTING ).getValue();
244  }
245 
246  @Nonnull
247  @Override
248  public final Stream<Map.Entry<IAgent<?>, Double>> inconsistency()
249  {
250  return m_data.entrySet().stream().map( i -> new AbstractMap.SimpleImmutableEntry<>( i.getKey(), i.getValue().getValue() ) );
251  }
252 
253  @Override
254  public final String toString()
255  {
256  return MessageFormat.format( "{0}{1}", super.toString(), m_data );
257  }
258 
266  private double getMetricValue( final IAgent<?> p_first, final IAgent<?> p_second )
267  {
268  if ( p_first.equals( p_second ) )
269  return 0;
270 
271  return m_metric.apply(
272  m_filter.apply( p_first ),
273  m_filter.apply( p_second )
274  );
275  }
276 
284  public static IConsistency numeric( final IFilter p_filter, final IMetric p_metric )
285  {
286  return new CConsistency( EAlgorithm.NUMERICAL, p_filter, p_metric, 0, 0.001 );
287  }
288 
296  public static IConsistency heuristic( final IFilter p_filter, final IMetric p_metric )
297  {
298  return new CConsistency( EAlgorithm.FIXPOINT, p_filter, p_metric, 8, 0.001 );
299  }
300 
309  public static IConsistency heuristic( final IFilter p_filter, final IMetric p_metric, final int p_iteration )
310  {
311  return new CConsistency( EAlgorithm.FIXPOINT, p_filter, p_metric, p_iteration, 0.001 );
312  }
313 
323  public static IConsistency heuristic( final IFilter p_filter, final IMetric p_metric, final int p_iteration, final double p_epsilon )
324  {
325  return new CConsistency( EAlgorithm.FIXPOINT, p_filter, p_metric, p_iteration, p_epsilon );
326  }
327 
328 
329 
333  private enum EAlgorithm
334  {
343 
344 
345 
353  public final DoubleMatrix1D getStationaryDistribution( final int p_iteration, final DoubleMatrix2D p_matrix )
354  {
355  final DoubleMatrix1D l_eigenvector;
356  switch ( this )
357  {
358  case FIXPOINT:
359  l_eigenvector = getLargestEigenvector( p_matrix, p_iteration );
360  break;
361 
362  case NUMERICAL:
363  l_eigenvector = getLargestEigenvector( p_matrix );
364  break;
365 
366  default:
367  throw new CIllegalStateException( CCommon.languagestring( this, "algorithm", this ) );
368  }
369 
370  // normalize eigenvector and create positiv oriantation
371  l_eigenvector.assign( DoubleMult.div( ALGEBRA.norm1( l_eigenvector ) ) );
372  l_eigenvector.assign( DoubleFunctions.abs );
373 
374  return l_eigenvector;
375  }
376 
386  private static DoubleMatrix1D getLargestEigenvector( final DoubleMatrix2D p_matrix, final int p_iteration )
387  {
388  final DoubleMatrix1D l_probability = DoubleFactory1D.dense.random( p_matrix.rows() );
389  IntStream.range( 0, p_iteration )
390  .forEach( i ->
391  {
392  l_probability.assign( ALGEBRA.mult( p_matrix, l_probability ) );
393  l_probability.assign( DoubleMult.div( ALGEBRA.norm2( l_probability ) ) );
394  } );
395  return l_probability;
396  }
397 
404  private static DoubleMatrix1D getLargestEigenvector( final DoubleMatrix2D p_matrix )
405  {
406  final DenseDoubleEigenvalueDecomposition l_eigen = new DenseDoubleEigenvalueDecomposition( p_matrix );
407 
408  // gets the position of the largest eigenvalue in parallel and returns the eigenvector
409  final double[] l_eigenvalues = l_eigen.getRealEigenvalues().toArray();
410  return l_eigen.getV().viewColumn(
411  IntStream.range( 0, l_eigenvalues.length - 1 ).parallel()
412  .reduce( ( i, j ) -> l_eigenvalues[i] < l_eigenvalues[j] ? j : i ).orElse( 0 )
413  );
414  }
415 
416  }
417 
418 }
static DoubleMatrix1D getLargestEigenvector(final DoubleMatrix2D p_matrix)
get the largest eigen vector with QR decomposition
static IConsistency heuristic(final IFilter p_filter, final IMetric p_metric, final int p_iteration)
factory heuristic algorithm
final IMetric metric()
returns the used metric
final Stream< Map.Entry< IAgent<?>, Double > > inconsistency()
stream over all data
filtering interface of agent literal values for metric
Definition: IFilter.java:36
static final DoubleFunction PROBABILITYINVERT
function for inverting probability
metric interface of the coherency structure
Definition: IMetric.java:37
final Stream< Map.Entry< IAgent<?>, Double > > consistency()
stream over all data
final IConsistency add( @Nonnull final IAgent<?> p_object)
adds a new object
final IMetric m_metric
metric object to create the consistency of two objects
layer with consistency data based a markov-chain
final DoubleMatrix1D getStationaryDistribution(final int p_iteration, final DoubleMatrix2D p_matrix)
calculates the stationary distribution
static< T > String languagestring(final T p_source, final String p_label, final Object... p_parameter)
returns the language depend string on any object
final Map< IAgent<?>, Map.Entry< Double, Double > > m_data
map with object and consistency & inconsistency value
static final DenseDoubleAlgebra ALGEBRA
algebra
static final Map.Entry< Double, Double > DEFAULTNONEXISTING
default value on non-existing objects
CConsistency( @Nonnull final EAlgorithm p_algorithm, @Nonnull final IFilter p_filter, @Nonnull final IMetric p_metric, final int p_iteration, final double p_epsilon)
ctor
double getMetricValue(final IAgent<?> p_first, final IAgent<?> p_second)
returns metric consistency
final double consistency( @Nonnull final IAgent<?> p_object)
returns the consistency of an object
final int m_iteration
number of iterations of the stochastic algorithm
static IConsistency numeric(final IFilter p_filter, final IMetric p_metric)
factory numerical algorithm
static IConsistency heuristic(final IFilter p_filter, final IMetric p_metric, final int p_iteration, final double p_epsilon)
factory numerical algorithm
final IFilter filter()
returns the used metric filter
final EAlgorithm m_algorithm
algorithm to calculate stationary probability
NUMERICAL
use numeric algorithm (QR decomposition)
static DoubleMatrix1D getLargestEigenvector(final DoubleMatrix2D p_matrix, final int p_iteration)
get the largest eigen vector based on the perron-frobenius theorem
IConsistency remove( @Nonnull final IAgent<?> p_object)
removes an object
final DescriptiveStatistics m_statistic
descriptive statistic
final double m_epsilon
epsilon consistency to create an aperiodic markow-chain
final DescriptiveStatistics statistic()
returns statistic data of the consistency values
final double inconsistency( @Nonnull final IAgent<?> p_object)
returns the inconsistency of an object
static IConsistency heuristic(final IFilter p_filter, final IMetric p_metric)
factory heuristic algorithm