Contenu | Rechercher | Menus

Annonce

Si vous avez des soucis pour rester connecté, déconnectez-vous puis reconnectez-vous depuis ce lien en cochant la case
Me connecter automatiquement lors de mes prochaines visites.

À propos de l'équipe du forum.

#1 Le 18/10/2008, à 23:03

thurston

[RESOLU] Combiner x repertoires parmi y pour remplir un CD

Bonjour,

Je suis en train d'écrire un soft qui m'automatise la création de CD Mp3s pour écoute en voiture. Je prends donc y repertoires (1 repertoire = 1 album), je les passe tous à la moulinette mp3, et je me retrouve avec mes y repertoires, dont la somme représente bien plus que la capacité d'un CD.
Avez vous déjà écrit un script qui permette de déterminer quelle est la combinaison gagnante pour arriver à remplir au mieux un CD?
On parle à mon avis de prendre toutes les combinaisons possibles, de n repertoire et d'en additionner la taille, et de ne garder que la plus élevée tant qu'inférieure à 650Mb par exemple. Bien sûr, one ne connait pas n, et il faut tester n, de 1 à y, tout en n'oubliant aucune possibilité.
Je vais m'y atteler tout doucement; si vous avez déjà fait ce script, je prends, sinon, je posterai un jour, quand je serai devenu plus malin...:rolleyes:
Amitiés
Thurston

Dernière modification par thurston (Le 24/10/2008, à 16:33)

Hors ligne

#2 Le 19/10/2008, à 02:11

nicolas66

Re : [RESOLU] Combiner x repertoires parmi y pour remplir un CD

C'est un problème d'optimisation combinatoire classique qui peut se formuler sous la forme d'un programme linéaire en nombres entiers (PLNE) :

a1*x1 + a2*x2 + ... + an*xn <= N (1)
ai >= 0 qq soit 1 <= i <= n
xi >= 0, xi entiers qq soit 1 <= i <= n (2)

-----------------------------------------------------

n -> Nombre d'albums
ai -> Taille du ième l'album
xi -> Variable représentant le ième l'album
N -> Taille du CD (ex : 650 Mb)

En résumé, on souhaite trouver une certaine combinaison d'albums qui maximise (1) sous les contraintes (2). La formulation de ton problème est simple mais sa résolution l'est nettement moins : lorsque n est peu élevé, ton script pourra tester chaque combinaison dans un temps raisonnable. En revanche, lorsque n devient grand, il est inconcevable d'envisager un dénombrement exhaustif puisque le nombre de solutions est égal à 2^n : la résolution d'un PLNE appartient à la classe des problèmes NP-difficiles.

Dès lors, il convient de s'orienter vers des algorithmes polynomiaux comme le simplexe ou la méthode des points intérieurs.

En pratique, pour l'algorithme du simplex, tu peux utiliser des logiciels comme SoPlex, GLPK (GNU Linear Programming Kit) ou bien lp_solve. Vu la nature de ton problème, ça ne devrait pas prendre trop de temps à résoudre. Sinon combien penses-tu avoir d'albums ?

Dernière modification par nicolas66 (Le 19/10/2008, à 02:12)


"The computer was born to solve problems that did not exist before." (B. Gates)

Hors ligne

#3 Le 19/10/2008, à 03:06

®om

Re : [RESOLU] Combiner x repertoires parmi y pour remplir un CD

Ton problème est équivalent au problème du sac à dos. smile

Hors ligne

#4 Le 19/10/2008, à 04:05

nicolas66

Re : [RESOLU] Combiner x repertoires parmi y pour remplir un CD

Oui c'est effectivement le problème du sac-à-dos. Bah si veux t'amuser, tu peux aussi commencer par implémenter un algorithme glouton puis passer à un algorithme génétique smile


"The computer was born to solve problems that did not exist before." (B. Gates)

Hors ligne

#5 Le 19/10/2008, à 04:10

®om

Re : [RESOLU] Combiner x repertoires parmi y pour remplir un CD

nicolas66 a écrit :

Dès lors, il convient de s'orienter vers des algorithmes polynomiaux comme le simplexe ou la méthode des points intérieurs.

En pratique, pour l'algorithme du simplex, tu peux utiliser des logiciels comme SoPlex, GLPK (GNU Linear Programming Kit) ou bien lp_solve. Vu la nature de ton problème, ça ne devrait pas prendre trop de temps à résoudre. Sinon combien penses-tu avoir d'albums ?

Juste une précision, le simplexe résoud le "problème du sac à dos relâché" (PL et non PLNE).
Et dans certains cas, la solution des 2 problèmes n'est pas la même smile

Hors ligne

#6 Le 19/10/2008, à 07:51

thurston

Re : [RESOLU] Combiner x repertoires parmi y pour remplir un CD

Oui ok, merci pour l'info, je ne connaissais pas l'expression du sac à dos.
Je pense que cela doit pouvoir s'écrire simplement en bash.
Je vais bosser dessus. J'étais plus parti sur un algorithme genetique.
A+
Thurston

Hors ligne

#7 Le 19/10/2008, à 08:17

cep

Re : [RESOLU] Combiner x repertoires parmi y pour remplir un CD

thurston a écrit :

Je suis en train d'écrire un soft qui m'automatise la création de CD Mp3s . . .inférieure à 650Mb

Tu peux t'inspirer de datapacker :
http://www.cepcasa.info/blog/?p=154

Hors ligne

#8 Le 19/10/2008, à 12:53

nicolas66

Re : [RESOLU] Combiner x repertoires parmi y pour remplir un CD

@Rom
Oui tu as raison de préciser ^^

@thurston

thurston a écrit :

Je pense que cela doit pouvoir s'écrire simplement en bash.

Bash n'est pas vraiment adapté à ce genre de chose. Perso, je te conseillerai plutôt de le faire en C ou C++ hmm


"The computer was born to solve problems that did not exist before." (B. Gates)

Hors ligne

#9 Le 19/10/2008, à 13:11

thurston

Re : [RESOLU] Combiner x repertoires parmi y pour remplir un CD

Ok, je le prends comme exercice. Ce ne sont que quelques boucles à priori, avec quelques tests d'échappement.
Je ne suis franchement pas programmeur, et je souhaite me restreindre à bash, car pas le temps de me cogner le langage C ou C++, même si pas très éloigné de bash. Je préferre mieux connaitre un langage plutot qu'un peu plusieurs.
A+
Thurston

Hors ligne

#10 Le 19/10/2008, à 15:54

nicolas66

Re : [RESOLU] Combiner x repertoires parmi y pour remplir un CD

Ok pas de soucis. En tout cas, tiens-nous au courant lorsque tu auras obtenu des résultats smile


"The computer was born to solve problems that did not exist before." (B. Gates)

Hors ligne

#11 Le 21/10/2008, à 02:06

nicolas66

Re : [RESOLU] Combiner x repertoires parmi y pour remplir un CD

De mon côté, après avoir tâtonné un peu sur la syntaxe de GLPK, je pense avoir trouvé un truc pas mal.

Fichier du PL `albums.mod'

/******* Set *******/
set I;

/**** Parameters ***/
param size{i in I};
param N := 700;

/**** Variables ****/
var x{i in I} binary;

/**** Objective ****/
maximize profit: sum{i in I} size[i]*x[i];

/*** Constraints ***/
subject to
	constraint: sum{i in I} size[i]*x[i] <= N;

end;

Fichier de données `albums.dat'

/******* Data ******/
data;

set I := "Selection Naturelle",
	 "Amore",
	 "Bel Canto",
	 "Meteora",
	 "Experience",
	 "Diorama",
	 "L'air de rien",
	 "Le Sacre des Lemmings",
	 "The Fat of the Land",
	 "Not sokute",
	 "Rouge sang",
	 "Attache ta Tuque",
	 "La Radiolina",
	 "Thriller 2008",
	 "Eye to the Telescope",
	 "Cocoon Crash",
	 "All the Lost Souls",
	 "Back to Bedlam",
	 "Allo le Monde",
	 "Black Holes and Revelations",
	 "Au Milieu des Autres",
	 "Break Syndical",
	 "La Grand-Messe",
	 "A Plus Tard Crocodile";

param size := "Selection Naturelle" 97,
	      "Amore" 82,
	      "Bel Canto" 154,
	      "Meteora" 44,
	      "Experience" 63,
	      "Diorama" 79,
	      "L'air de rien" 80,
	      "Le Sacre des Lemmings" 49,
	      "The Fat of the Land" 78,
	      "Not sokute" 92,
	      "Rouge sang" 80,
	      "Attache ta Tuque" 194,
	      "La Radiolina" 72,
	      "Thriller 2008" 97,
	      "Eye to the Telescope" 66,
	      "Cocoon Crash" 69,
	      "All the Lost Souls" 59,
	      "Back to Bedlam" 91,
	      "Allo le Monde" 58,
	      "Black Holes and Revelations" 105,
	      "Au Milieu des Autres" 40,
	      "Break Syndical" 68,
	      "La Grand-Messe" 58,
	      "A Plus Tard Crocodile" 85;

On exécute le solveur via :

glpsol --binarize --model albums.mod --data albums.dat --output results.txt

Sortie du fichier `results.txt'

Problem:    albums
Rows:       2
Columns:    24 (24 integer, 24 binary)
Non-zeros:  48
Status:     INTEGER OPTIMAL
Objective:  profit = 700 (MAXimum)

   No.   Row name        Activity     Lower bound   Upper bound
------ ------------    ------------- ------------- -------------
     1 profit                    700
     2 constraint                700                         700

   No. Column name       Activity     Lower bound   Upper bound
------ ------------    ------------- ------------- -------------
     1 x['Selection Naturelle']
                    *              0             0             1
     2 x[Amore]     *              0             0             1
     3 x['Bel Canto']
                    *              1             0             1
     4 x[Meteora]   *              0             0             1
     5 x[Experience]
                    *              0             0             1
     6 x[Diorama]   *              0             0             1
     7 x['L''air de rien']
                    *              0             0             1
     8 x['Le Sacre des Lemmings']
                    *              0             0             1
     9 x['The Fat of the Land']
                    *              0             0             1
    10 x['Not sokute']
                    *              1             0             1
    11 x['Rouge sang']
                    *              0             0             1
    12 x['Attache ta Tuque']
                    *              1             0             1
    13 x['La Radiolina']
                    *              0             0             1
    14 x['Thriller 2008']
                    *              1             0             1
    15 x['Eye to the Telescope']
                    *              0             0             1
    16 x['Cocoon Crash']
                    *              0             0             1
    17 x['All the Lost Souls']
                    *              0             0             1
    18 x['Back to Bedlam']
                    *              0             0             1
    19 x['Allo le Monde']
                    *              0             0             1
    20 x['Black Holes and Revelations']
                    *              1             0             1
    21 x['Au Milieu des Autres']
                    *              0             0             1
    22 x['Break Syndical']
                    *              0             0             1
    23 x['La Grand-Messe']
                    *              1             0             1
    24 x['A Plus Tard Crocodile']
                    *              0             0             1

Integer feasibility conditions:

INT.PE: max.abs.err. = 0.00e+00 on row 0
        max.rel.err. = 0.00e+00 on row 0
        High quality

INT.PB: max.abs.err. = 0.00e+00 on row 0
        max.rel.err. = 0.00e+00 on row 0
        High quality

End of output

En espérant que ça puisse aider smile

Dernière modification par nicolas66 (Le 21/10/2008, à 02:16)


"The computer was born to solve problems that did not exist before." (B. Gates)

Hors ligne

#12 Le 21/10/2008, à 07:56

thurston

Re : [RESOLU] Combiner x repertoires parmi y pour remplir un CD

oui je bosse dessus avec un pote cale en informatique et on tente de faire du recursif dans le meme genre.
A bientot
Thurston

Hors ligne

#13 Le 21/10/2008, à 20:55

Totor

Re : [RESOLU] Combiner x repertoires parmi y pour remplir un CD

Bonsoir,

Voici un script qui devrait répondre à la demande (même s'il n'est pas optimisé) :

#!/bin/ksh

DOSSIER_SOURCE="$1"
TAILLE_MAX=$2
FICHIER_RESULTAT="$3"
FICHIER_TMP=~/"$(basename $0).tmp"

# creation tableaux des noms de dossiers et tailles
INDICE=-1
find ${DOSSIER_SOURCE} -maxdepth 1 -type d|sed 1d|while read dossier
do
 INDICE=$((INDICE+1))
  T_DOSSIERS[${INDICE}]="${dossier}"
  T_TAILLES[${INDICE}]=$(du -k "${dossier}"|tail -1|cut -f1)
done
LAST_INDICE=$((INDICE))

# indique si fin de traitement ou pas 1=fin, 0=pas fin
FinTraitement()
{
   # le traitement continue s'il reste au moins un dossier dont la taille est <= à TAILLE_MAX 
   FIN=1
   for((indice=0;indice<=${LAST_INDICE};indice++))
   do
	if [ -n "${T_TAILLES[${indice}]}" ]; then
		# il y a une taille à cet indice, est-elle <= TAILLE_MAX
		if [ ${T_TAILLES[${indice}]} -le ${TAILLE_MAX} ]; then
		  FIN=0
		fi
	fi
   done
   echo ${FIN}
}

# recherche de toutes les tailles possibles et les combinaisons de dossiers correspondantes avec les dossiers restants
RechercheCombinaisons()
{
  indice=$1
  taille=$2
  chemin=$3

  if [ $indice -gt ${LAST_INDICE} ]; then
    # on a dépassé l'indice max, on s'arrète de chercher
    [[ -n "${chemin}" ]] && echo "${taille} : ${chemin}" >> ${FICHIER_TMP}
    return
  fi

  if [ -n "${T_TAILLES[${indice}]}" ]; then
      # recherche des combinaisons avec ce dossier
      taille_dossier=T_TAILLES[${indice}]
      taille_suivante=$((taille+taille_dossier))
      if [ -z "${chemin}" ]; then
        # premier element de la combinaison
        (RechercheCombinaisons $((indice+1)) ${taille_suivante} ${indice})
      else
	# nème element de la combinaison
	(RechercheCombinaisons $((indice+1)) ${taille_suivante} "${chemin}/${indice}")
      fi
  fi
  # recherche des combinaisons sans ce dossier
  (RechercheCombinaisons $((indice+1)) ${taille} ${chemin})
}

# parmis toutes les combinaisons trouvées, recherche de la plus pertinante et écriture de celle-ci dans le fichier résultat
EcrireLaCombinaison()
{
	chemin=$(awk -F\: -v max=${TAILLE_MAX} 'BEGIN {MAX=0} max >= $1 { if ($1 > MAX) {CHEMIN=$2; MAX=$1} } END {print CHEMIN} ' ${FICHIER_TMP})
	echo "Combinaison $1 :" >> ${FICHIER_RESULTAT}
	echo ${chemin}|awk -F\/ '{ for (indice=1;indice<=NF;indice++){print $indice}}'|while read INDICE
	do
		echo "${T_DOSSIERS[${INDICE}]}" >> ${FICHIER_RESULTAT}

                # on "supprime" le dossier des tableaux car il a été utilisé pour une combinaison
		unset T_DOSSIERS[${INDICE}]
		unset T_TAILLES[${INDICE}]
	done
}

[[ -f ${FICHIER_RESULTAT} ]] && rm -f ${FICHIER_RESULTAT}
# tant que l'on a pas atteint la fin, on effectue le traitement de recherche
NUM_COMBINAISON=0
while [ $(FinTraitement) -ne 1 ];
do
  [[ -f ${FICHIER_TMP} ]] && rm -f ${FICHIER_TMP}
  NUM_COMBINAISON=$((NUM_COMBINAISON+1))

  # on recherche toutes les combinaisons possibles avec les dossiers restants
  RechercheCombinaisons 0 0 ""

  # recherche résultat le plus pertinant
  EcrireLaCombinaison ${NUM_COMBINAISON}
done

EDIT :
param1 = dossier parent des dossiers mp3
param2 = taille max en ko
param3 = fichier résultat des combinaisons

Dernière modification par Totor (Le 21/10/2008, à 21:50)


-- Lucid Lynx --

Hors ligne

#14 Le 21/10/2008, à 21:54

nicolas66

Re : [RESOLU] Combiner x repertoires parmi y pour remplir un CD

Ton algo implémente une recherche exhaustive ou pas ? Quel est le temps d'exécution pour 30 albums ?


"The computer was born to solve problems that did not exist before." (B. Gates)

Hors ligne

#15 Le 21/10/2008, à 22:44

thurston

Re : [RESOLU] Combiner x repertoires parmi y pour remplir un CD

Merci pour le scrip totor. Il y a un truc qui ne marche pas chez moi, mais je vais regarder un peu en détail.
(quand je lance le script aucune action, ni fichier résultat créé).
A+
Thurston

Hors ligne

#16 Le 22/10/2008, à 08:43

Totor

Re : [RESOLU] Combiner x repertoires parmi y pour remplir un CD

nicolas66 a écrit :

Ton algo implémente une recherche exhaustive ou pas ? Quel est le temps d'exécution pour 30 albums ?

Oui, la recherche est exhaustive.
30 albums... je n'en sais rien ! je n'en ai pas autant wink En fait, je n'ai pas fait de tests de métrologie car l'objectif était de fournir un script fonctionnel.

Et puis tout dépend de sa machine, j'ai un AMD Phenom 9950... donc plutôt rapide...


-- Lucid Lynx --

Hors ligne

#17 Le 22/10/2008, à 08:43

Totor

Re : [RESOLU] Combiner x repertoires parmi y pour remplir un CD

thurston a écrit :

Merci pour le scrip totor. Il y a un truc qui ne marche pas chez moi, mais je vais regarder un peu en détail.
(quand je lance le script aucune action, ni fichier résultat créé).
A+
Thurston

Huuuum, si pas de fichier résultat créé, c'est qu'il ne trouve pas de combinaison et donc qu'il ne trouve pas au moins un dossier dont la taille est <= TAILLE_MAX (soit 650Mo : 650*1024 = 665600 ko)

Dernière modification par Totor (Le 22/10/2008, à 09:01)


-- Lucid Lynx --

Hors ligne

#18 Le 22/10/2008, à 09:14

nicolas66

Re : [RESOLU] Combiner x repertoires parmi y pour remplir un CD

Totor a écrit :

Oui, la recherche est exhaustive.
30 albums... je n'en sais rien ! je n'en ai pas autant wink En fait, je n'ai pas fait de tests de métrologie car l'objectif était de fournir un script fonctionnel.

Comme je l'ai indiqué dans un post précédent, la recherche exhaustive est à bannir lorsque n augmente. Exemple : n=30 => 2^30=1073741824 ... A partir de ce que j'ai donné, ya moyen de faire un script pr remplir le fichier de données et récupérer la solution automatiquement pour graver le CD direct.


"The computer was born to solve problems that did not exist before." (B. Gates)

Hors ligne

#19 Le 22/10/2008, à 09:47

Totor

Re : [RESOLU] Combiner x repertoires parmi y pour remplir un CD

et bien, je te dirais ce soir combien de temps ça met avec 30 dossiers (j'ai pô d'albums !)

lol


-- Lucid Lynx --

Hors ligne

#20 Le 22/10/2008, à 11:52

nicolas66

Re : [RESOLU] Combiner x repertoires parmi y pour remplir un CD

Voire même avec n=50 pour voir smile


"The computer was born to solve problems that did not exist before." (B. Gates)

Hors ligne

#21 Le 22/10/2008, à 23:02

Totor

Re : [RESOLU] Combiner x repertoires parmi y pour remplir un CD

bon bah big pb...:/
j'ai une erreur de segmentation dès la 34867ème combinaison....:rolleyes:

big_smile


-- Lucid Lynx --

Hors ligne

#22 Le 22/10/2008, à 23:10

thurston

Re : [RESOLU] Combiner x repertoires parmi y pour remplir un CD

Bizarre ca marche pas du tout pour moi.
J'ai collé une dizaine d'albums mp3 dans le repertoire /home/thurston/script, où j'ai également installé ton script
que j'ai nommé rangedir, avec les permissions d'execution, puis je me mets dans le repertoire avec un terminal, et je lance

./rangedir ./ 665600000 ./result

et que dalle...
??
A+
Thurston

Dernière modification par thurston (Le 22/10/2008, à 23:12)

Hors ligne

#23 Le 23/10/2008, à 01:13

nicolas66

Re : [RESOLU] Combiner x repertoires parmi y pour remplir un CD

Totor a écrit :

j'ai une erreur de segmentation dès la 34867ème combinaison....

Bah tu m'étonnes, surtout que je viens de voir que tu recherchais les combinaisons récursivement hmm

Clairement, mieux vaut s'orienter vers des heuristiques simples dans un premier temps. Un algorithme glouton donnera peut-être de bons résultats :

* Trier les albums par taille de manière décroissante
* Pour chaque album
      * Si la taille totale + taille de l'album <= 650Mo
            * Augmenter la taille totale
            * Ajouter l'album à la liste résultat
      * FinSi
* FinPour


"The computer was born to solve problems that did not exist before." (B. Gates)

Hors ligne

#24 Le 23/10/2008, à 08:39

Totor

Re : [RESOLU] Combiner x repertoires parmi y pour remplir un CD

Certe, mais cela ne répond pas à la demande qui est :

thurston a écrit :

Avez vous déjà écrit un script qui permette de déterminer quelle est la combinaison gagnante pour arriver à remplir au mieux un CD?

par ailleurs, j'ai été confronté à un problème de limite numérique du shell ....


-- Lucid Lynx --

Hors ligne

#25 Le 23/10/2008, à 08:39

Totor

Re : [RESOLU] Combiner x repertoires parmi y pour remplir un CD

thurston a écrit :

Bizarre ca marche pas du tout pour moi.
J'ai collé une dizaine d'albums mp3 dans le repertoire /home/thurston/script, où j'ai également installé ton script
que j'ai nommé rangedir, avec les permissions d'execution, puis je me mets dans le repertoire avec un terminal, et je lance

./rangedir ./ 665600000 ./result

et que dalle...
??
A+
Thurston

as-tu regardé le contenu du fichier ./result ?


-- Lucid Lynx --

Hors ligne