Algorithme de répartition de quantités bornées pondérées

Bonjour,

Je cherche à écrire un algorithme pas trop compliqué (réalisable en script shell) dont le but est de calculer N quantités Q[i] dont la somme est égale à une quantité totale Qt.

  • Chaque quantité Q[i] est encadrée par un minimum Min[i] strictement positif et un maximum Max[i] strictement supérieur au minimum et qui peut être infini.

  • Chaque quantité Q[i] est aussi associée à un poids P[i] strictement positif.

  • Le rapport de deux quantités Q[i]/Q[j] qui ne sont pas limitées par leur minimum ni leur maximum doit être égal au rapport de leurs poids respectifs P[i]/P[j].

Autrement dit approximativement, chaque quantité doit être proportionnelle à son poids sauf si cette valeur est inférieure à son mimimum ou supérieure à son maximum.

Merci pour vos idées et suggestions car je sèche, toutes mes approches finissent en usines à gaz inextricables.

Edit: application pratique (certains l’auront deviné) : partitionner un disque.

Bojour,

Il y a quelque chose qui ne va pas.
Qt=Somme(Q[i])
Q[i] est associé à un poids P[i]
Q[i] est associé à Min[i] et Max[i]

Que veux tu calculer? Ca n’est pas très clair dans ton message.

mais ca ressemble beaucoup à ce que fait le preseed :wink:

en fait il te faut un algorithme Itératif pour déterminer le poid.
Déjà le Max[i] = taille du disque, l’infini n’est pas une bonne idée :slight_smile:

Il fat que je retrouve car j’avais un lien vers la façon dont la taille des partitions est calculée dans le cadre du preseed

Lien: doc/devel/partman-auto-recipe.txt · master · Debian Installer / debian-installer · GitLab

6. HOW THE ACTUAL PARTITION SIZES ARE COMPUTED
----------------------------------------------

Suppose we have to create N partitions and min[i], max[i] and
priority[i] are the minimal size, the maximal size and the priority of
the partition #i as described in section 1.

Let free_space be the size of the free space to partition.

Then do the following:

for(i=1;i<=N;i++) {
   factor[i] = priority[i] - min[i];
}
ready = FALSE;
while (! ready) {
   minsum = min[1] + min[2] + ... + min[N];
   factsum = factor[1] + factor[2] + ... + factor[N];
   ready = TRUE;
   for(i=1;i<=N;i++) {
      x = min[i] + (free_space - minsum) * factor[i] / factsum;
      if (x > max[i])
         x = max[i];
      if (x != min[i]) {
         ready = FALSE;
         min[i] = x;
      }
   }
}

Then min[i] will be the size of partition #i.

Tout le reste est connu.

Oui mais il ne fait pas entrer le mimimum dans la prise en compte du poids.

Non, les poids sont donnés.

Peu importe, du moment que ce n’est pas un facteur limitant.

En fait si, tu as trois donnée: la taille voulue qui est la taille minimal, le max, et le poid

Je cherche à calculer les tailles qui remplissent les conditions. Tout le reste est donné.

Normalement, tu as l’algorithme dans le chapitre 6, au pire tu l’adaptes avec le fait que Min[i] <> Q[i]

Oui, j’ai même étudié le script lib/recipes.sh. Mais comme écrit plus haut, il ne fait pas exactement ce que je recherche et ça fait une grosse différence.

Hélas ce n’est pas si simple sinon j’aurais déjà résolu le problème… L’application du minimum à une quantité peut impacter l’application du maximum d’une autre quantité et vice versa.

Oui c’est normal, c’est un algorithme itératif. Mais ca s’adapte, car pour ce qui est du preseed, je peux te dire que ça marche parfaitement bien, je l’utilise et j’ai fait pas loin de 1000 installation en 2 ans avec des résultat correspondants aux attendus.

salut
je n’ai pas compris :

si Q[i]/Q[j] = P[i]/P[j]. alors Qj=Qi/Pi xPj
donc Somme(Qj)=Qi/Pi x Somme(Pj)
donc Qi=Qt x Pi/Somme(Pj)

en fait ce que tu veux n’est pas clair.
Si on considère des partitions Qi qui doit etre comprise entre Min(i) et Max(i), et dont somme(Qi)<=Qt, cela implique que Somme(Min(i))<=somme(Qi)<=somme(max(i)<=Qt>

l’algorithme que j’ai donne est lui capable de prendre en compte le fait la possibilité que somme(Max(i)>=Qt mais la somme des Min(i)<=Qt dans tous les cas

la variable d’ajustement c’est Pi.

Tu as oublié de prendre en compte les contraintes de minimum et maximum.

Qu’est-ce qui n’est pas clair exactement ?

Non, ça implique que Somme(Min[i]) <= somme(Q[i]) = Qt
Il n’y a aucune relation entre Qt et les Max[i].

Si tu parles de l’algorithme de partman-auto, il applique le poids P[i] à la différence (Q[i] - Min[i]) et non à Q[i]. Ça simplifie le calcul mais les tailles résultantes ne sont pas exactement proportionnelles à leurs poids. Peut-être qu’il fait très bien ce qu’il est censé faire mais il ne fait pas (ou très approximativement) ce que je veux, merci d’arrêter d’essayer de me le vendre.

Non, ce sont des paramètres fixés.

salut
tu pourrais doner une exemple avec données de départ et d’arrivée?

ce que tu n’a pas compris c’est que la taille n’est pas resultant du poids. le poids determine la priorité d’une partition a etre de la taille donnée en max si celui ci est inférieur à la taille du disque, ou bien à lui donner la préseance si le max est supérieur au disque.
Qi est un résultat pas une valeur que tu fixe, ou alors considère qu’au départ, Qi=Min(i).

personnellement j’ai fait mes calcul pour partman pour travailler avec des pourcentages plutot que des valeurs.
et ca marche. mes partitions gardent toutes les mêmes proportion quelque soit la taille du disque en ayant au départ défini ma valeur Qt

J’en ai bien conscience.
Je voulais juste montrer que les contraintes hors min/max imposent une valeur et donc que la prise en compte de la contrainte min/max n’est pas possible.
Et donc que probablement je n’avais pas bien compris les contraintes.

En supposant que j’ai plus ou moins bien compris :
0. EnsI={1…N} , Qt0=Qt

  1. tu calcules les q[i] avec ma formule pour I dans EnsI
  2. MIN
    2a. tu crées l’ensemble EnsMin des i tels que qi<min[i]
    2b pour i dans EnsMin, qi= min[i]
  3. MAX
    3a. tu crée l’ensemble EnsMax des i tels que qi>max[i]
    3b. pour i dans EnsMax, qi= max[i]
  4. tu recalcules le nouveau EnsI=EnsI-EnsMin-EnsMax , le nouveau QT et tu reprends 1,2,3,4
  5. tu vérifies que Som(qi)<=Qt0

Un exemple simple avec deux partitions avec des poids identiques.
Partition 1 : min=2G maxi=20G poids=50
Partition 2 : min=5G maxi=infini poids=50

Le résultat de mes spécifications est :

Pour un disque de taille comprise entre 7G et 10G :
Partition 1 = taille disque - 5G
Partition 2 = 5G

Pour un disque de taille comprise entre 10G et 40G :
Partition 1 = taille disque * 0,5
Partition 2 = taille disque * 0,5

Pour un disque de taille supérieure à 40G :
Partition 1 = 20 G
Partition 2 = taille disque - 20G

Le résultat de l’algorithme de partman-auto est :

Pour un disque de taille comprise entre 7G et 43G :
Partition 1 = 2G + (taille disque - 7G) * 0,5
Partition 2 = 5G + (taille disque - 7G) * 0,5

Pour un disque de taille supérieure à 43G :
Partition 1 = 20 G
Partition 2 = taille disque - 20G

Bien que les deux partitions aient des poids identiques, il y a un écart de 3 Go entre elles pour les tailles de disque comprises entre 10G et 40G (où elles ne sont limitées ni par leurs minimums ni par leur maximums) avec l’algorithme de partman-auto, alors qu’elles sont égales avec mes spécifications.

Tu es en train de m’expliquer que je n’ai pas compris mes propres spécifications ? C’est plutôt toi qui n’as pas compris, parce que ce que tu décris ne correspond pas du tout à mes spécifications. C’est moi qui décide à quoi sert le poids.

C’est faux, voir l’exemple ci-dessus.

Absurde. Qt, c’est la taille du disque. Tu ne peux pas en même temps la fixer et dire quelle qu’elle soit.

Si car il y a une priorité entre les contraintes. Les contraintes min et max sont prioritaires sur les contraintes de poids.

[Edit] J’ai étudié ton algorithme. Si j’ai bien compris, l’entrée dans EnsMin ou EnsMax est définitive. Or cela ne doit pas forcément être le cas :

  • Si une quantité entre dans EnsMin, cela diminue le total disponible pour les autres quantités, donc une autre quantité qui était dans EnsMax pourrait en sortir.

  • Réciproquement si une quantité entre dans EnsMax, cela augmente le total disponible pour les autres quantités, donc une autre quantité qui était dans EnsMin pourrait en sortir.

en python


class partition(object):
	def __init__(self,MIN=2,MAX=20,POIDS=0.5):
		self._trouvee=False
		self._MIN=MIN
		self._MAX=MAX
		self._POIDS=POIDS
		pass


p1=partition(MIN=2,MAX=20,POIDS=0.5)
p2=partition(MIN=5,MAX=1E100,POIDS=0.5)

P=[p1,p2]
N=len(P)


Qt0=50
EnsI=[i for i in range(N) if P[i]._trouvee==False]



MINMAX=True
while len(EnsI)!=0 and MINMAX==True:
	print('##'*5)
	print("EnsI=",EnsI)
	no=no-1
	Qt=Qt0-sum([P[i]._q for i in range(N) if P[i]._trouvee==True])
	print("Qt=",Qt)
	PoidsRestant=sum([P[i]._POIDS for i in range(N) if P[i]._trouvee==False])
	print("PoidsRestant=",PoidsRestant)

	MINMAX=False
	for i in EnsI:
		P[i]._q=Qt*P[i]._POIDS/PoidsRestant
		print("P["+str(i)+"]._q=",P[i]._q)
		if P[i]._q < P[i]._MIN:
			P[i]._q = P[i]._MIN
			P[i]._trouvee=True
			MINMAX=True
		if P[i]._q > P[i]._MAX:
			P[i]._q = P[i]._MAX
			P[i]._trouvee=True
			MINMAX=True
		print("P["+str(i)+"]._q=",P[i]._q)
	EnsI=[i for i in range(N) if P[i]._trouvee==False]

print("# "*20)
for i in range(N):
	print("P["+str(i)+"]._q=",P[i]._q)







salut
en essayant de passer le programme en bash , sachant que e bash n’est pas objet
j’ai essayé un truc comme ça :

declare -A p1=(["_MIN"]=2 ["_MAX"]=20 ["_POIDS"]=0.5 ['trouvee']=false)
declare -A p2=(["_MIN"]=5 ["_MAX"]=10000000 ["_POIDS"]=0.5 ['trouvee']=false)
declare -a P=($p1 $p2)

mais je n’arrive pas à accéder
à p1["_MIN"] à partir : P :

echo ${p1[@]}
marche bien
20 2 false 0.5

mais
aa=${P[0]}
echo ${aa[@]}
ne donne rien

ici c’est echo $aauniquement, sinonc a auait du etre aa+=(${P[0]})

ça ne marche pas non plus

et tu fait echo ${P[@]} ?