All Downloads are FREE. Search and download functionalities are using the official Maven repository.

it.unibo.alchemist.model.cognitive.properties.Orienting.kt Maven / Gradle / Ivy

There is a newer version: 35.0.0
Show newest version
/*
 * Copyright (C) 2010-2023, Danilo Pianini and contributors
 * listed, for each module, in the respective subproject's build.gradle.kts file.
 *
 * This file is part of Alchemist, and is distributed under the terms of the
 * GNU General Public License, with a linking exception,
 * as described in the file LICENSE in the Alchemist distribution's top directory.
 */

package it.unibo.alchemist.model.cognitive.properties

import it.unibo.alchemist.model.Node
import it.unibo.alchemist.model.Node.Companion.asProperty
import it.unibo.alchemist.model.Position
import it.unibo.alchemist.model.cognitive.OrientingProperty
import it.unibo.alchemist.model.environments.EnvironmentWithGraph
import it.unibo.alchemist.model.geometry.ConvexShape
import it.unibo.alchemist.model.geometry.Transformation
import it.unibo.alchemist.model.geometry.Vector
import it.unibo.alchemist.model.geometry.navigationgraph.NavigationGraph
import it.unibo.alchemist.model.geometry.navigationgraph.UndirectedNavigationGraph
import it.unibo.alchemist.model.physics.properties.OccupiesSpaceProperty
import it.unibo.alchemist.model.properties.AbstractNodeProperty
import it.unibo.alchemist.util.Iterables.shuffled
import it.unibo.alchemist.util.Lists.takeFraction
import org.apache.commons.math3.random.RandomGenerator
import org.jgrapht.Graph
import org.jgrapht.alg.shortestpath.DijkstraShortestPath
import org.jgrapht.alg.spanning.PrimMinimumSpanningTree
import org.jgrapht.graph.AsWeightedGraph
import org.jgrapht.graph.DefaultEdge

/**
 * Base implementation of a node's [OrientingProperty].
 */
abstract class Orienting @JvmOverloads constructor(
    /**
     * The simulation [RandomGenerator].
     */
    val randomGenerator: RandomGenerator,
    override val environment: EnvironmentWithGraph<*, T, P, A, N, DefaultEdge>,
    override val node: Node,
    override val knowledgeDegree: Double,
    /**
     * Environment's areas whose diameter is smaller than ([minArea] * the diameter of this pedestrian) will be
     * regarded as too small and discarded when generating the cognitive map (i.e. no landmark will be placed inside
     * them).
     */
    private val minArea: Double = 10.0,
) : AbstractNodeProperty(node), OrientingProperty
    where P : Position

, P : Vector

, A : Transformation

, L : ConvexShape, N : ConvexShape { override val volatileMemory: MutableMap, Int> = HashMap() override val cognitiveMap: NavigationGraph by lazy { val environmentGraph = environment.graph /* * The rooms in which landmarks will be placed. */ val rooms = environmentGraph.vertexSet() .filter { it.diameter > node.asProperty>().shape.diameter * minArea } .shuffled(randomGenerator) .toList() .takeFraction(knowledgeDegree) .toMutableList() /* * landmarks[i] will contain the landmark generated in rooms[i]. */ val landmarks = rooms.map { createLandmarkIn(it) } val fullGraph = UndirectedNavigationGraph(DefaultEdge::class.java) landmarks.forEach { fullGraph.addVertex(it) } rooms.indices.forEach { i -> rooms.indices.forEach { j -> if (i != j && environmentGraph.pathExists(rooms[i], rooms[j])) { fullGraph.addEdge(landmarks[i], landmarks[j]) } } } /* * The environment's graph is unweighted, but edges' weights defaults to 1.0 */ val dijkstra = DijkstraShortestPath(environmentGraph) val weightFunction: (DefaultEdge) -> Double = { edge -> val tail = fullGraph.getEdgeSource(edge) val head = fullGraph.getEdgeTarget(edge) /* * The weight of the shortest path between two rooms (tail, head) is the number * of rooms that need to be traversed to go from tail to head. */ dijkstra.getPathWeight(rooms[landmarks.indexOf(tail)], rooms[landmarks.indexOf(head)]) } val fullGraphWeighted = AsWeightedGraph(fullGraph, weightFunction, false, false) /* * Only the edges in the spanning tree are maintained. */ fullGraph.removeAllEdges( fullGraph.edgeSet() - PrimMinimumSpanningTree(fullGraphWeighted).spanningTree.edges, ) fullGraph } /** * Creates a landmark entirely contained in the given area. If such area contains one or more destinations, the * returned landmark must contain at least one of them. */ abstract override fun createLandmarkIn(area: N): L override fun toString() = "${super.toString()}[knoledgeDegree=$knowledgeDegree]" companion object { /** * Checks whether a path exists between [source] and [sink]. * [DijkstraShortestPath] is used instead of [org.jgrapht.alg.connectivity.ConnectivityInspector.pathExists], * because, in case of directed graph, the latter checks whether the given vertices lay in the same weakly * connected component, which is not the desired behavior. * As unweighted graphs have a default edge weight of 1.0, shortest path algorithms can always be applied * meaningfully. */ fun Graph.pathExists(source: V, sink: V): Boolean = DijkstraShortestPath.findPathBetween(this, source, sink) != null } }





© 2015 - 2024 Weber Informatics LLC | Privacy Policy