IdentifiantMot de passe
Loading...
Mot de passe oublié ?Je m'inscris ! (gratuit)
Navigation

Inscrivez-vous gratuitement
pour pouvoir participer, suivre les réponses en temps réel, voter pour les messages, poser vos propres questions et recevoir la newsletter

Langage PHP Discussion :

[Algorithme] Dijkstra : plus court chemin [PHP 5.0]


Sujet :

Langage PHP

  1. #1
    Futur Membre du Club
    Homme Profil pro
    Inscrit en
    Avril 2012
    Messages
    8
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France

    Informations forums :
    Inscription : Avril 2012
    Messages : 8
    Points : 5
    Points
    5
    Par défaut [Algorithme] Dijkstra : plus court chemin
    Bonjour,

    J'essaie d'utiliser un algorithme de Dijkstra trouvé sur le web mais je rencontre un problème lorsque cet algo doit traiter plus de 66 chemins.
    En dessous de 67 chemins, il me donne un résultat très rapidement (< 1 seconde) par contre dès que j'ai plus de 66 chemins, mon serveur se met à mouliner en utilisant toutes les ressources proc jusqu'à aboutir au timeout de PHP (300 secondes).

    J'ai tenté d'essayer une autre liste avec des chemins différents (> 67 chemins) -> NOK
    Augmentation de la mémoire et timeout dans php.ini -> NOK

    J'utilise CodeIgniter 2.1.0 et je suis plus que débutant en programmation, il va donc falloir être patient avec moi

    Je vous joins le code de l'algo Dijkstra :

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    46
    47
    48
    49
    50
    51
    52
    53
    54
    55
    56
    57
    58
    59
    60
    61
    62
    63
    64
    65
    66
    67
    68
    69
    70
    71
    72
    73
    74
    75
    76
    77
    78
    79
    80
    81
    82
    83
    84
    85
    86
    87
    88
    89
    90
    91
    92
    93
    94
    95
    96
    97
    98
    99
    100
    101
    102
    103
    104
    105
    106
    107
    108
    109
    110
    111
    112
    113
    114
    115
    116
    117
    118
    119
    120
    121
    122
    123
    124
    125
    126
    127
    128
    129
    130
    131
    132
    133
    134
    135
    136
    137
    138
    139
    140
    141
    142
    143
    144
    145
    146
    147
    148
    149
    150
    151
    152
    153
    154
    155
    156
    157
    158
    159
    160
    161
    162
    163
    164
    165
    166
    167
    168
    169
    170
    171
    172
    173
    174
    175
    176
    177
    178
    179
    180
    181
    182
    183
    184
    185
    186
    187
    188
    189
    190
    191
    192
    193
    194
    195
    196
    197
    198
    199
    200
    201
    202
    203
    204
    205
    206
    207
    208
    209
    210
    211
    212
    213
    214
    215
    216
    217
    218
    219
    220
    221
    222
    223
    224
    225
    226
    227
    228
    229
    230
    231
    232
    233
    234
    235
    236
    237
    238
    239
    240
    241
    242
    243
    244
    245
    246
    247
    248
    249
    250
    251
    252
    253
    254
    255
    256
    257
    258
    259
    260
    261
    262
    263
    264
    265
    266
    267
    268
    269
    270
    271
    272
    273
    274
    275
    276
    277
    278
    279
    280
    281
    282
    283
    284
    285
    286
    287
    288
    289
    290
    291
    292
    293
    294
    295
    296
    297
    298
    299
    300
    301
    302
    303
    304
    305
    306
    307
    308
    309
    310
    311
    312
    313
    314
    315
    316
    317
    318
    319
    320
    321
    322
    323
    324
    325
    326
     
    <?php
     
    define('I',100000); // define infinite distance
     
     
     
    /**
    
     * class to Build Dijkstra model
    
     * To build the class 
    
     * Use int to index all the points on the map
    
     * @param int startPoint
    
     * @param array routes[] = array($startPoint,$endPoint,$distance)
    
     * @author Rick.purple
    
     */
     
     
     
    class Dijkstra{
     
    	private $intStartPoint; 
     
    	private $aRoutes = array(); // all possible routes between each two points (single direction) 
     
    	private $aPoints = array(); // all the points on the map
     
    	private $aReds = array();   
     
    	private $aBlues = array(); 
     
    	private $aComp = array();
     
    	private $aDistances = array(); // the closest distance from start point to each points
     
    	private $aPathes = array(); // path from each points to its neibor on the best path to the start point
     
    	private $aFullPathes; // path from start point to each points
     
     
     
    	/**
    
    	 * Build Dijkstra model, find best path and closest distance from start point to each point on the map 
    
    	 * @return null
    
    	 * @param object $intStartPoint 
    
    	 * @param object $aRoutes
    
    	 */
     
    	public function __construct($intStartPoint,$aRoutes){
     
    		$this->aRoutes = $aRoutes;
     
    		$this->intStartPoint = $intStartPoint;
     
     
     
    		foreach($aRoutes as $aRoute){
     
    			if(!in_array($aRoute[0],$this->aPoints)){
     
    				$this->aPoints[] = $aRoute[0];
     
    			}
     
    			if(!in_array($aRoute[1],$this->aPoints)){
     
    				$this->aPoints[] = $aRoute[1];
     
    			}	
     
    		}	
     
     
     
    		$this->aReds = array($intStartPoint);
     
    		$this->aBlues = $this->array_remove($this->aPoints, $intStartPoint);	
     
     
     
    		foreach($this->aBlues as $intPoint){
     
    				$this->aDistances[$intPoint] = I;
     
    		}
     
    		$this->aDistances[$intStartPoint] = 0;	
     
     
     
    		$this->findPath();
     
    	}
     
     
     
    	/**
    
    	 * function to get the best path
    
    	 * @return pathes for each node on the map
    
    	 */	
     
    	public function getPath(){
     
    		foreach($this->aPoints as $intPoint){
     
    			$this->fillFullPath($intPoint,$intPoint);
     
    		}
     
    		return $this->aFullPathes;
     
    	}
     
     
     
    	/**
    
    	 * function to get the closest distance	 
    
    	 * @return 
    
    	 */
     
    	public function getDistance(){
     
    		return $this->aDistances;
     
    	}	
     
     
     
    	public function get_company(){
     
    		return  $this->aComp;
     
    	}
     
     
     
    	/**
    
    	 * Remove specified element from array
    
    	 * @return array 
    
    	 * @param array $arr : array to be processing
    
    	 * @param array $value : the element to be remove from the array
    
    	 */	
     
    	private function array_remove($arr,$value) {
     
    		return array_values(array_diff($arr,array($value)));
     
    	}
     
     
     
    	/**
    
    	 * Dijkstra algorithm implementation
    
    	 * @return null
    
    	 */
     
    	private function findPath(){
     
    		while(!empty($this->aBlues)){
     
    			$intShortest = I;
     
    			foreach($this->aReds as $intRed){
     
    				# find possible rounte
     
    				foreach($this->aRoutes as $aRoute){
     
    					if($intRed == $aRoute[0]){
     
    						$aDis[$intRed][$aRoute[1]] = $aRoute[2];
     
    						# rewrite distance
     
    						$intDistance = $this->aDistances[$intRed] + $aRoute[2];
     
    						if($this->aDistances[$aRoute[1]] > $intDistance){
     
    							$this->aDistances[$aRoute[1]] = $intDistance;
     
    							$this->aComp[$aRoute[1]][$aRoute[2]] = $aRoute[3];
     
    							# change the path
     
    							if($intRed==$this->intStartPoint ||$intRed==$aRoute[1]){}
     
    							else{
     
    								$this->aPathes[$aRoute[1]] = $intRed;
     
    							}
     
    						}
     
     
     
    						# find the nearest	neighbor
     
    						if(!in_array($aRoute[1],$this->aReds)&&$aRoute[2]<$intShortest){
     
    							$intShortest = $aRoute[2];
     
    							$intAddPoint = $aRoute[1];
     
    						}		
     
    					}
     
    				}
     
    			}
     
     
     
    			$this->aReds[] = $intAddPoint;
     
    			$this->aBlues = $this->array_remove($this->aBlues, $intAddPoint);	
     
    		}
     
    	}
     
     
     
    	/**
    
    	 * mid step function to find full path from start point to the end point.
    
    	 * @return null
    
    	 * @param int $intEndPoint
    
    	 * @param int $intMidPoint
    
    	 */		
     
    	private function fillFullPath($intEndPoint,$intMidPoint){
     
    		if(isset($this->aPathes[$intMidPoint])){
     
    			$this->aFullPathes[$intEndPoint][] = $this->aPathes[$intMidPoint];
     
    			$this->fillFullPath($intEndPoint,$this->aPathes[$intMidPoint]);
     
    		}
     
    		else{
     
    			$this->aFullPathes[$intEndPoint][] = $this->intStartPoint;
     
    		}					
     
    	}
     
    }
     
    /*
    
    # Examples 
    
    // single direction route path
    
    $aRoutes = array(
    
    	array(0,0,0),
    
    	array(0,1,10),
    
    	array(0,3,30), // use something like array(3,0,20) to define a two way map   
    
    	array(0,4,100),
    
    	array(1,1,0),
    
    	array(1,2,50),
    
    	array(2,2,0),
    
    	array(2,4,10),
    
    	array(3,3,0),
    
    	array(3,2,20),
    
    	array(3,4,60),
    
    	array(4,4,0),
    
    );
    
    $oDijk = new Dijkstra(0,$aRoutes); // startPoint = 0
    
    
    
    print_r($oDijk->getPath());
    
    print_r($oDijk->getDistance());
    
    */
     
    ?>
    En PHP, existe-t-il une limitation du nombre d'éléments que peut avoir un tableau ?

    Merci pour votre aide.
    Julien.

  2. #2
    Expert éminent
    Avatar de Benjamin Delespierre
    Profil pro
    Développeur Web
    Inscrit en
    Février 2010
    Messages
    3 929
    Détails du profil
    Informations personnelles :
    Âge : 36
    Localisation : France, Alpes Maritimes (Provence Alpes Côte d'Azur)

    Informations professionnelles :
    Activité : Développeur Web
    Secteur : High Tech - Opérateur de télécommunications

    Informations forums :
    Inscription : Février 2010
    Messages : 3 929
    Points : 7 762
    Points
    7 762
    Par défaut
    Non, il n'y a à priori aucune limitation à la taille des tableau hormis bien sûr la mémoire que PHP est autorisée à allouer (128mo par défaut).

    Le problème c'est que l'algo de Djikstra est récursif, sa complexité est O(n²) donc le nombre de cycles augmente exponentiellement avec le nombre de sommets de ton graphe.

    Sur Wikipedia il y a la meilleure implem possible de cet algo en pseudo code. Comme ça m'intéresse, je vais voir si je peux le sortir en PHP si ça peux t'aider.

    En attendant, pour corriger le problème de timeout, tu peux passer la directive time limit à 0 pour contourner le problème:

  3. #3
    Futur Membre du Club
    Homme Profil pro
    Inscrit en
    Avril 2012
    Messages
    8
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France

    Informations forums :
    Inscription : Avril 2012
    Messages : 8
    Points : 5
    Points
    5
    Par défaut
    Merci Benjamin pour l'idée de passer la directive set_time_limit(), malheureusement même après 15 min d'attente je n'obtiens aucun retour.
    Pour l'implémentation disponible sur Wikipédia, je n'ai pas les compétences en programmation pour le coder et honnêtement j'ai du mal à le comprendre (l'histoire du vertex)
    Sinon j'ai trouvé un autre code avec un tri en tas : https://github.com/bmichotte/php5-Di...s/Dijkstra.php
    J'ai jeté un coup d'oeil rapide mais je ne sais pas à quoi peut correspondre la variable $positions.

    Je n'ai pourtant que 30 sommets et 66 arcs à mouliner avec l'algo. Cela ne me semble pas énorme non plus.

    J'ai l'impression que l'algo part dans une sorte de boucle infinie, voici la boucle qui semble être responsable :

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
     
    				foreach($this->aRoutes as $aRoute){
     
    					if($intRed == $aRoute[0]){			
     
    						$aDis[$intRed][$aRoute[1]] = $aRoute[2];
     
    						# rewrite distance
     
    						$intDistance = $this->aDistances[$intRed] + $aRoute[2];
     
    						if($this->aDistances[$aRoute[1]] > $intDistance){
     
    							$this->aDistances[$aRoute[1]] = $intDistance;
     
    							//$this->aComp[$aRoute[1]][$aRoute[2]] = $aRoute[3];
     
    							# change the path
     
    							if($intRed==$this->intStartPoint ||$intRed==$aRoute[1]){}
     
    							else{
     
    								$this->aPathes[$aRoute[1]] = $intRed;
     
    							}
     
    						}
     
     
     
    						# find the nearest neighbor
     
    						if(!in_array($aRoute[1],$this->aReds)&&$aRoute[2]<$intShortest){
     
    							$intShortest = $aRoute[2];
     
    							$intAddPoint = $aRoute[1];
     
    						}		
     
    					}
     
    				}
    Je joins aussi une capture d'écran de l'erreur détaillée, si ça peut aider.



    Merci pour votre aide.
    Julien.

  4. #4
    Expert éminent
    Avatar de Benjamin Delespierre
    Profil pro
    Développeur Web
    Inscrit en
    Février 2010
    Messages
    3 929
    Détails du profil
    Informations personnelles :
    Âge : 36
    Localisation : France, Alpes Maritimes (Provence Alpes Côte d'Azur)

    Informations professionnelles :
    Activité : Développeur Web
    Secteur : High Tech - Opérateur de télécommunications

    Informations forums :
    Inscription : Février 2010
    Messages : 3 929
    Points : 7 762
    Points
    7 762
    Par défaut
    Moi même j'ai eu du mal avec l'implem, d'ailleurs je n'ai pas encore réussi

    Suivant l'algo utilisé, 30 sommets et 66 arcs peuvent suffire à mettre ne rade l'algo (il est tout de même assez velu).

    Je vais tenter de trouver quelqu'un de plus doué que moi sur la théorie des graphes parce que la dernière fois que j'ai modélisé cet algo, j'étais au lycée; je m'en rappelle plus

  5. #5
    Futur Membre du Club
    Homme Profil pro
    Inscrit en
    Avril 2012
    Messages
    8
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France

    Informations forums :
    Inscription : Avril 2012
    Messages : 8
    Points : 5
    Points
    5
    Par défaut
    Bon après quelques echo() et var_dump(), l'algorithme part bien en boucle et reste bloqué sur un sommet. Il semble bien y avoir un soucis dans la fonction findPath() au niveau de la mise à jour de la variable $intShortest, la valeur de celle-ci reste à 100000 (pour symboliser l'infini) et ne se met plus à jour.

    Maintenant que j'ai trouvé l'origine du problème, j'imagine que ce doit être un jeu d'enfant mais j'ai encore du mal à comprendre l'algo et l'implémentation utilisée dans ce code.

    Quelqu'un aurait-il une piste ?

    Merci.

  6. #6
    Futur Membre du Club
    Homme Profil pro
    Inscrit en
    Avril 2012
    Messages
    8
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France

    Informations forums :
    Inscription : Avril 2012
    Messages : 8
    Points : 5
    Points
    5
    Par défaut Toujours en galère
    Je suis toujours bloqué avec cette histoire de boucle infinie.
    Je suis assez désespéré et c'est pourquoi je souhaite offrir 15 euros à celui ou celle qui pourra m'apporter une solution concrète.

    C'est tout ce que je peux me permettre d'offrir. Cette algo est à destination de mon site personnel qui n'a aucun objectif lucratif. Vous pouvez jeter un oeil sur ce qui fonctionne actuellement, ici (<30 arcs et <10 sommets sur le site)

    Je joins l'algo en question ainsi qu'un tableau initialisé avec les trajets.
    Un trajet se compose ainsi (ville de départ, ville d'arrivée, compagnie de transport, coût)
    Fichiers attachés Fichiers attachés

  7. #7
    Expert éminent sénior
    Avatar de rawsrc
    Homme Profil pro
    Dev indep
    Inscrit en
    Mars 2004
    Messages
    6 142
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 48
    Localisation : France, Bouches du Rhône (Provence Alpes Côte d'Azur)

    Informations professionnelles :
    Activité : Dev indep

    Informations forums :
    Inscription : Mars 2004
    Messages : 6 142
    Points : 16 545
    Points
    16 545
    Billets dans le blog
    12
    Par défaut
    Salut,

    l'algo est bon et attend par défaut :
    Un trajet se compose ainsi (ville de départ, ville d'arrivée, compagnie de transport, coût)
    Déja que c'est chaud, essayer de le modifier pour y rajouter la gestion des compagnies n'est pas chose aisée.

  8. #8
    Membre éprouvé Avatar de I_believe_in_code
    Profil pro
    Inscrit en
    Décembre 2008
    Messages
    219
    Détails du profil
    Informations personnelles :
    Âge : 46
    Localisation : France

    Informations forums :
    Inscription : Décembre 2008
    Messages : 219
    Points : 1 043
    Points
    1 043
    Par défaut
    Question toute bête : es-tu sûr que ton graphe est bien connexe ?

  9. #9
    Futur Membre du Club
    Homme Profil pro
    Inscrit en
    Avril 2012
    Messages
    8
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France

    Informations forums :
    Inscription : Avril 2012
    Messages : 8
    Points : 5
    Points
    5
    Par défaut
    Citation Envoyé par I_believe_in_code Voir le message
    Question toute bête : es-tu sûr que ton graphe est bien connexe ?
    La question n'était pas bête du tout, c'est plutôt moi qui le suis car effectivement c'était bien un problème de graphe non connexe.

    Merci beaucoup de m'avoir débloqué sur un problème tout con :p
    Merci aussi aux autres qui ont participé à ce topic.

    Je t'envoie un MP pour s'arranger sur la méthode d'envoi des 15 euros.

+ Répondre à la discussion
Cette discussion est résolue.

Discussions similaires

  1. Recherche algorithme de plus court chemin
    Par WileECoyote dans le forum Intelligence artificielle
    Réponses: 1
    Dernier message: 20/02/2011, 15h44
  2. Algorithme du plus court chemin
    Par ndjeur dans le forum Débuter
    Réponses: 2
    Dernier message: 29/12/2009, 15h00
  3. Algorithme du plus court chemin
    Par Didier77 dans le forum C
    Réponses: 4
    Dernier message: 24/05/2007, 20h54
  4. Algorithme du plus court chemin
    Par greg3105 dans le forum Algorithmes et structures de données
    Réponses: 13
    Dernier message: 04/05/2006, 17h26
  5. Algorithme du plus court chemin
    Par greg3105 dans le forum Langage
    Réponses: 6
    Dernier message: 29/04/2006, 20h02

Partager

Partager
  • Envoyer la discussion sur Viadeo
  • Envoyer la discussion sur Twitter
  • Envoyer la discussion sur Google
  • Envoyer la discussion sur Facebook
  • Envoyer la discussion sur Digg
  • Envoyer la discussion sur Delicious
  • Envoyer la discussion sur MySpace
  • Envoyer la discussion sur Yahoo