dega2 0.1.0__py3-none-any.whl

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
dega2/BuildpopGA.py ADDED
@@ -0,0 +1,51 @@
1
+ import numpy as np
2
+
3
+ from . import ConsChekGA4, DomChekGA4
4
+
5
+
6
+ def explorer(population1, n_population, explor, p_cof1, index_p, p_cofphi1, index_phi,
7
+ n_pop, n_pop_phi):
8
+ """Phase d'exploration, vectorisée : pour chaque variable j, on ajoute +1 ou -1
9
+ sur toute la ligne concernée (au lieu de boucler colonne par colonne)."""
10
+ blocs_phi, blocs_p = [], []
11
+ tab_ind1, tab_ind1_ph = [], []
12
+ n_p = n_pop - n_pop_phi # nombre de colonnes modifiées dans la 2e moitié
13
+
14
+ for j in range(explor):
15
+ a1 = np.array(population1[:, 0:n_pop_phi])
16
+ a2 = np.array(population1[:, n_pop_phi:n_population])
17
+
18
+ r_phi = index_phi[0, j]
19
+ r_p = index_p[0, j]
20
+ a1[r_phi, :] += 1 if p_cofphi1[2, j] < 0 else -1
21
+ a2[r_p, :n_p] += 1 if p_cof1[2, j] < 0 else -1
22
+
23
+ tab_ind1_ph.extend([r_phi] * n_pop_phi)
24
+ tab_ind1.extend([r_p] * n_p)
25
+ blocs_phi.append(a1)
26
+ blocs_p.append(a2)
27
+
28
+ a3 = np.concatenate(blocs_phi, axis=1) # une seule concaténation
29
+ a4 = np.concatenate(blocs_p, axis=1)
30
+ return a3, a4, tab_ind1, tab_ind1_ph
31
+
32
+
33
+ def Build_PT(population1, n_population, explor, p_cof1, index_p, p_cofphi1, index_phi,
34
+ phi, alpha, a, b, c, n_pop, n_pop_phi, n):
35
+
36
+ ###################### Variables exploration ##############################
37
+ a3, a4, tab_ind1, tab_ind1_ph = explorer(
38
+ population1, n_population, explor, p_cof1, index_p, p_cofphi1, index_phi,
39
+ n_pop, n_pop_phi)
40
+
41
+ ############ Check the constraints and dominance of new populations ########
42
+ tab_ind11 = tab_ind1.copy()
43
+ tab_ind11_phi = tab_ind1_ph.copy()
44
+
45
+ [pop1, pop1_phi, tab_ind11, tab_ind11_phi] = ConsChekGA4.chek(
46
+ a3, a4, a, b, tab_ind11_phi, tab_ind11)
47
+
48
+ [pop2, tab_ind11_phi, tab_ind11] = DomChekGA4.nd_update(
49
+ c, population1, pop1, pop1_phi, tab_ind11, tab_ind11_phi)
50
+
51
+ return pop2, tab_ind1, tab_ind11, tab_ind1_ph, tab_ind11_phi
dega2/ConsChek.py ADDED
@@ -0,0 +1,13 @@
1
+ import numpy as np
2
+
3
+
4
+ def chek(pop, a, b):
5
+ if pop.shape[1] == 0:
6
+ return pop
7
+ return pop[:, (a @ pop <= b).all(axis=0)]
8
+
9
+
10
+
11
+
12
+
13
+
dega2/ConsChekGA4.py ADDED
@@ -0,0 +1,19 @@
1
+ import numpy as np
2
+
3
+
4
+ def _realisables(a, b, pop):
5
+ """Indices des colonnes de `pop` qui vérifient a @ x <= b (test fait pour toutes
6
+ les colonnes en un seul produit matriciel)."""
7
+ if pop.shape[1] == 0:
8
+ return np.arange(0)
9
+ return np.flatnonzero((a @ pop <= b).all(axis=0))
10
+
11
+
12
+ def chek(pop_phi, pop, a, b, tab_ind11_phi, tab_ind11):
13
+ idx = _realisables(a, b, pop)
14
+ idx_phi = _realisables(a, b, pop_phi)
15
+
16
+ return (pop[:, idx],
17
+ pop_phi[:, idx_phi],
18
+ [tab_ind11[k] for k in idx],
19
+ [tab_ind11_phi[k] for k in idx_phi])
dega2/DomChek.py ADDED
@@ -0,0 +1,19 @@
1
+ import numpy as np
2
+
3
+
4
+ def non_dominance(c, pop):
5
+ obj_val = np.dot(c, pop)
6
+ idx = np.arange(obj_val.shape[1])
7
+ i = 0
8
+ while i < len(idx) - 1:
9
+ oi = obj_val[:, idx[i]][:, None]
10
+ reste = obj_val[:, idx[i + 1:]]
11
+ le = (oi <= reste).all(axis=0) # i domine (faiblement) j -> j supprimé
12
+ gt = (oi > reste).all(axis=0) # j domine strictement i -> i supprimé
13
+ if gt.any():
14
+ jg = int(gt.argmax()) # premier j qui domine i
15
+ idx = np.delete(idx, np.append(np.flatnonzero(le[:jg]) + i + 1, i))
16
+ else:
17
+ idx = np.delete(idx, np.flatnonzero(le) + i + 1)
18
+ i += 1
19
+ return pop[:, idx]
dega2/DomChekGA4.py ADDED
@@ -0,0 +1,78 @@
1
+ import numpy as np
2
+
3
+
4
+ def _indices_non_domines(obj):
5
+ """Équivalent exact de la boucle de `non_dominance`, mais sans np.delete répétés
6
+ et avec la comparaison de i contre tous les j restants faite en une seule fois.
7
+ Renvoie les indices (dans l'ordre d'origine) des colonnes conservées."""
8
+ idx = np.arange(obj.shape[1])
9
+ i = 0
10
+ while i < len(idx) - 1:
11
+ oi = obj[:, idx[i]][:, None]
12
+ reste = obj[:, idx[i + 1:]]
13
+ le = (oi <= reste).all(axis=0) # i domine (faiblement) j -> j supprimé
14
+ gt = (oi > reste).all(axis=0) # j domine strictement i -> i supprimé
15
+ if gt.any():
16
+ jg = int(gt.argmax()) # premier j qui domine i
17
+ a_supprimer = np.append(np.flatnonzero(le[:jg]) + i + 1, i)
18
+ idx = np.delete(idx, a_supprimer) # i reste à la même position
19
+ else:
20
+ idx = np.delete(idx, np.flatnonzero(le) + i + 1)
21
+ i += 1
22
+ return idx
23
+
24
+
25
+ def non_dominance(c, pop, tab_ind3):
26
+ obj_val = np.dot(c, pop)
27
+ idx = _indices_non_domines(obj_val)
28
+ return pop[:, idx], [tab_ind3[k] for k in idx], obj_val[:, idx]
29
+
30
+
31
+ def _filtrer_contre(obj_p, idx_p, obj_ref, idx_ref, limite_fixe=None):
32
+ """Compare chaque individu de la population (idx_p) à l'ensemble de référence
33
+ (idx_ref) : un individu de référence dominé est supprimé, et l'individu de la
34
+ population est supprimé dès qu'un élément de référence le domine strictement.
35
+ `limite_fixe` reproduit la borne de balayage de la 2e boucle d'origine."""
36
+ i = 0
37
+ while i < len(idx_p):
38
+ oi = obj_p[:, idx_p[i]][:, None]
39
+ L = len(idx_ref) if limite_fixe is None else min(limite_fixe, len(idx_ref))
40
+ ref = obj_ref[:, idx_ref[:L]]
41
+ le = (oi <= ref).all(axis=0)
42
+ gt = (oi > ref).all(axis=0)
43
+ if gt.any():
44
+ jg = int(gt.argmax())
45
+ idx_ref = np.delete(idx_ref, np.flatnonzero(le[:jg]))
46
+ idx_p = np.delete(idx_p, i) # i reste à la même position
47
+ else:
48
+ idx_ref = np.delete(idx_ref, np.flatnonzero(le))
49
+ i += 1
50
+ return idx_p, idx_ref
51
+
52
+
53
+ def nd_update(c, population, pop1, pop1_phi, tab_ind11, tab_ind11_phi):
54
+
55
+ # non-dominance interne de pop1_phi puis de pop1
56
+ pop1_phi, tab_ind11_phi, obj_val_phi = non_dominance(c, pop1_phi, tab_ind11_phi)
57
+ pop1, tab_ind11, obj_val1 = non_dominance(c, pop1, tab_ind11)
58
+
59
+ obj_val_p = np.dot(c, population)
60
+ idx_p = np.arange(population.shape[1])
61
+
62
+ # population contre pop1
63
+ idx_p, idx1 = _filtrer_contre(obj_val_p, idx_p, obj_val1,
64
+ np.arange(pop1.shape[1]))
65
+
66
+ # population contre pop1_phi
67
+ # NB : comportement d'origine conservé. Le balayage de pop1_phi est borné par la
68
+ # taille de la population (size_popkD), pas par celle de pop1_phi : si pop1_phi
69
+ # est plus grande, ses derniers éléments ne sont pas comparés.
70
+ D = len(idx_p)
71
+ idx_p, idx_phi = _filtrer_contre(obj_val_p, idx_p, obj_val_phi,
72
+ np.arange(pop1_phi.shape[1]), limite_fixe=D)
73
+
74
+ pop2 = np.concatenate((population[:, idx_p], pop1_phi[:, idx_phi], pop1[:, idx1]),
75
+ axis=1)
76
+ return (pop2,
77
+ [tab_ind11_phi[k] for k in idx_phi],
78
+ [tab_ind11[k] for k in idx1])
dega2/GA4.py ADDED
@@ -0,0 +1,64 @@
1
+ import numpy as np
2
+ from . import BuildpopGA, GenPop, upload_cofGA
3
+ from tqdm import tqdm
4
+
5
+
6
+ def NewPop(population1, n_population, explor, p_cof1, index_p, p_cofphi1, index_phi,
7
+ phi, alpha, a, b, c, T, n, verbose=True):
8
+
9
+ n_pop = len(population1.T)
10
+ n_pop_phi = int(n_pop / alpha)
11
+
12
+ min_phi = []
13
+
14
+ barre = tqdm(
15
+ range(T),
16
+ desc="DEGA-2",
17
+ unit="it",
18
+ colour="green",
19
+ disable=not verbose,
20
+ bar_format="{desc} {percentage:3.0f}%|{bar:35}| {n_fmt}/{total_fmt} "
21
+ "[{elapsed}<{remaining}, {rate_fmt}] {postfix}",
22
+ )
23
+
24
+ for _ in barre:
25
+ [pop2, tab_ind1, tab_ind11, tab_ind1_phi, tab_ind11_phi] = BuildpopGA.Build_PT(
26
+ population1, n_population, explor, p_cof1, index_p, p_cofphi1, index_phi,
27
+ phi, alpha, a, b, c, n_pop, n_pop_phi, n)
28
+
29
+ s = pop2.shape[1]
30
+
31
+ if s > n_population:
32
+ # sélection des n_pop meilleurs individus (tri croissant de phi)
33
+ xphi1 = np.dot(phi, pop2)
34
+ ind_phi1 = np.argsort(xphi1, axis=1)
35
+ pop3 = pop2[:, ind_phi1[0, :n_pop]].astype(int)
36
+ elif s < n_population:
37
+ pop3 = GenPop.Gen(a, b, c, n, n_population - s)
38
+ pop3 = np.concatenate((pop2, pop3), axis=1)
39
+ else:
40
+ pop3 = pop2
41
+
42
+ population1 = pop3
43
+ xphi1 = np.dot(phi, pop3)
44
+
45
+ xphi2 = xphi1.min()
46
+ min_phi.append(xphi2)
47
+
48
+ ##################### Candidats ####################################
49
+ condidat_phi = list(index_phi[0, :explor])
50
+ condidat = list(index_p[0, :explor])
51
+
52
+ ##################### Mise à jour des coefficients #################
53
+ [p_cof1, p_cofphi1, index_p, index_phi] = upload_cofGA.upload(
54
+ p_cof1, index_p, p_cofphi1, index_phi,
55
+ tab_ind1, tab_ind1_phi, tab_ind11, tab_ind11_phi,
56
+ explor, condidat_phi, condidat, n_pop, n_pop_phi)
57
+
58
+ barre.set_postfix_str(f"min_phi={xphi2:.4e}", refresh=False)
59
+
60
+ # Correction : l'indice vient de pop3 (= population1), pas de pop2
61
+ min_index = xphi1.argmin()
62
+ xopt = population1[:, min_index]
63
+
64
+ return pop2, xphi2, min_phi, xopt
dega2/GenPop.py ADDED
@@ -0,0 +1,32 @@
1
+ import numpy as np
2
+ from . import ConsChek, DomChek
3
+
4
+ # Nombre maximal de tirages consécutifs sans progression avant d'abandonner.
5
+ _ESSAIS_MAX = 5000
6
+
7
+
8
+ def Gen(a,b,c,n,n_population):
9
+ population=np.random.randint(0,3,(n,n_population),dtype=int);
10
+ pop2=ConsChek.chek(population, a, b)
11
+ pop3=DomChek.non_dominance(c, pop2)
12
+ np1=n_population-len(pop3.T)
13
+ sans_progres=0
14
+ while np1!=0:
15
+ population=np.random.randint(0,3,(n,np1),dtype=int);
16
+ pop2=ConsChek.chek(population, a, b)
17
+ pop3=np.concatenate((pop3,pop2),axis=1);
18
+ pop3=DomChek.non_dominance(c, pop3)
19
+ np1_nouveau=n_population-len(pop3.T)
20
+ # Garde-fou : sans lui, un problème où il n'existe pas assez de solutions
21
+ # réalisables et deux à deux non dominées (peu d'objectifs, peu de variables,
22
+ # contraintes très serrées...) faisait tourner la boucle indéfiniment.
23
+ sans_progres = 0 if np1_nouveau < np1 else sans_progres + 1
24
+ if sans_progres > _ESSAIS_MAX:
25
+ raise RuntimeError(
26
+ "Impossible de construire une population de %d solutions réalisables "
27
+ "et non dominées entre elles (%d trouvées). Réduis la taille de la "
28
+ "population, ajoute des objectifs (lignes de c) ou relâche les "
29
+ "contraintes." % (n_population, n_population - np1_nouveau))
30
+ np1=np1_nouveau
31
+
32
+ return(pop3)
dega2/__init__.py ADDED
@@ -0,0 +1,9 @@
1
+ """DEGA-2 : algorithme génétique multi-objectifs à variables entières."""
2
+
3
+ __version__ = "0.1.0"
4
+
5
+ from .solver import Result, solve
6
+ from .entree import charger_probleme, ecrire_exemple
7
+ from .example import demo
8
+
9
+ __all__ = ["solve", "charger_probleme", "ecrire_exemple", "demo", "Result", "__version__"]
dega2/__main__.py ADDED
@@ -0,0 +1,4 @@
1
+ from .cli import main
2
+
3
+ if __name__ == "__main__":
4
+ raise SystemExit(main())
dega2/cli.py ADDED
@@ -0,0 +1,139 @@
1
+ """Ligne de commande :
2
+
3
+ dega2 assistant interactif (l'utilisateur entre son problème)
4
+ dega2 -f probleme.json problème et paramètres lus dans un fichier
5
+ dega2 --exemple modele.json écrit un fichier d'exemple à modifier
6
+ dega2 --demo problème aléatoire de démonstration
7
+ """
8
+ import argparse
9
+
10
+ import numpy as np
11
+
12
+ from . import __version__, problems
13
+ from .entree import (PARAMETRES_DEFAUT, charger_probleme, demander,
14
+ demander_oui_non, ecrire_exemple, saisir_parametres,
15
+ saisir_probleme)
16
+ from .example import demo
17
+ from .solver import solve
18
+
19
+
20
+ def _construire_parseur():
21
+ p = argparse.ArgumentParser(
22
+ prog="dega2",
23
+ description="DEGA-2. Sans option, lance un assistant qui demande le problème "
24
+ "et les paramètres.")
25
+ p.add_argument("-f", "--probleme", metavar="FICHIER",
26
+ help="fichier .json ou .npz contenant a, b, c, phi "
27
+ "(et éventuellement \"parametres\")")
28
+ p.add_argument("--exemple", metavar="FICHIER",
29
+ help="écrit un fichier .json d'exemple, puis quitte")
30
+ p.add_argument("--demo", action="store_true",
31
+ help="problème aléatoire de démonstration (voir -n, -p, -m)")
32
+ p.add_argument("-n", type=int, default=None, help="[--demo] nombre de variables (défaut 30)")
33
+ p.add_argument("-p", "--objectifs", type=int, default=None,
34
+ help="[--demo] nombre d'objectifs (défaut 10)")
35
+ p.add_argument("-m", "--contraintes", type=int, default=None,
36
+ help="[--demo] nombre de contraintes (défaut 15)")
37
+ p.add_argument("-T", "--iterations", type=int, default=None,
38
+ help="nombre d'itérations (défaut 2n)")
39
+ p.add_argument("--population", type=int, default=None, help="taille de la population (défaut 80)")
40
+ p.add_argument("--alpha", type=int, default=None, help="paramètre alpha (défaut 4)")
41
+ p.add_argument("--explor", type=int, default=None,
42
+ help="variables explorées par itération (défaut 3)")
43
+ p.add_argument("--sans-positivite", action="store_true",
44
+ help="ne pas ajouter les contraintes x >= 0")
45
+ p.add_argument("--seed", type=int, default=None, help="graine aléatoire")
46
+ p.add_argument("--no-plot", action="store_true", help="ne pas afficher la courbe")
47
+ p.add_argument("--version", action="version", version=f"dega2 {__version__}")
48
+ return p
49
+
50
+
51
+ def _lancer(a, b, c, phi, parametres, seed=None, tracer=True):
52
+ a, c = np.atleast_2d(a), np.atleast_2d(c)
53
+ print(f"\n🧬 DEGA-2 — démarrage (variables={a.shape[1]}, objectifs={c.shape[0]}, "
54
+ f"contraintes={a.shape[0]})\n")
55
+ res = solve(a, b, c, phi, seed=seed, **parametres)
56
+ print("\n" + res.summary() + "\n")
57
+ if tracer:
58
+ try:
59
+ res.plot()
60
+ except ImportError as exc:
61
+ print(exc)
62
+ return res
63
+
64
+
65
+ def _assistant():
66
+ print("\n🧬 DEGA-2 — assistant\n")
67
+ print("Comment fournir le problème ?")
68
+ print(" 1) Charger un fichier (.json ou .npz)")
69
+ print(" 2) Saisir au clavier")
70
+ print(" 3) Problème aléatoire (démonstration)")
71
+ choix = demander("Choix", 1, minimum=1, maximum=3)
72
+
73
+ defauts = {}
74
+ if choix == 1:
75
+ while True:
76
+ chemin = input("Chemin du fichier : ").strip().strip('"').strip("'")
77
+ try:
78
+ a, b, c, phi, defauts = charger_probleme(chemin)
79
+ break
80
+ except (OSError, ValueError) as exc:
81
+ print(f" Lecture impossible : {exc}")
82
+ elif choix == 2:
83
+ a, b, c, phi = saisir_probleme()
84
+ else:
85
+ n = demander("Nombre de variables n", 30, minimum=1)
86
+ m1 = demander("Nombre de contraintes", 15, minimum=1)
87
+ p = demander("Nombre d'objectifs", 10, minimum=1)
88
+ a, b, c, phi = problems.Genr(n, m1, p)
89
+
90
+ n = np.atleast_2d(a).shape[1]
91
+ parametres = saisir_parametres(n, defauts)
92
+ tracer = demander_oui_non("Afficher la courbe de convergence à la fin ?", True)
93
+ _lancer(a, b, c, phi, parametres, tracer=tracer)
94
+
95
+
96
+ def main(argv=None):
97
+ args = _construire_parseur().parse_args(argv)
98
+
99
+ try:
100
+ if args.exemple:
101
+ ecrire_exemple(args.exemple)
102
+ print(f"Fichier d'exemple écrit : {args.exemple}\n"
103
+ f"Modifie-le puis lance : dega2 -f {args.exemple}")
104
+ return 0
105
+
106
+ if args.demo:
107
+ demo(n=30 if args.n is None else args.n,
108
+ p=10 if args.objectifs is None else args.objectifs,
109
+ m1=15 if args.contraintes is None else args.contraintes,
110
+ n_population=80 if args.population is None else args.population,
111
+ alpha=4 if args.alpha is None else args.alpha,
112
+ explor=3 if args.explor is None else args.explor,
113
+ iterations=args.iterations, seed=args.seed, plot=not args.no_plot)
114
+ return 0
115
+
116
+ if args.probleme:
117
+ a, b, c, phi, du_fichier = charger_probleme(args.probleme)
118
+ params = dict(PARAMETRES_DEFAUT)
119
+ params.update(du_fichier) # valeurs du fichier
120
+ for cle, valeur in (("n_population", args.population), ("alpha", args.alpha),
121
+ ("explor", args.explor), ("iterations", args.iterations)):
122
+ if valeur is not None: # options de la ligne de commande
123
+ params[cle] = valeur
124
+ if args.explor is None and "explor" not in du_fichier:
125
+ params["explor"] = min(params["explor"], np.atleast_2d(a).shape[1])
126
+ if args.sans_positivite:
127
+ params["positivity"] = False
128
+ _lancer(a, b, c, phi, params, seed=args.seed, tracer=not args.no_plot)
129
+ return 0
130
+
131
+ _assistant()
132
+ return 0
133
+
134
+ except (OSError, ValueError, RuntimeError) as exc:
135
+ print(f"Erreur : {exc}")
136
+ return 1
137
+ except (EOFError, KeyboardInterrupt):
138
+ print("\nInterrompu.")
139
+ return 1
dega2/entree.py ADDED
@@ -0,0 +1,180 @@
1
+ """Saisie du problème et des paramètres par l'utilisateur.
2
+
3
+ Trois façons de fournir un problème :
4
+ - un fichier .json ou .npz -> charger_probleme(chemin)
5
+ - la saisie au clavier -> saisir_probleme()
6
+ - des tableaux numpy dans son code -> dega2.solve(a, b, c, phi)
7
+ """
8
+ import json
9
+
10
+ import numpy as np
11
+
12
+ CLES_PROBLEME = ("a", "b", "c", "phi")
13
+ CLES_PARAMETRES = ("n_population", "alpha", "explor", "iterations", "positivity")
14
+
15
+ PARAMETRES_DEFAUT = {
16
+ "n_population": 80,
17
+ "alpha": 4,
18
+ "explor": 3,
19
+ "iterations": None, # None -> 2 * n
20
+ "positivity": True,
21
+ }
22
+
23
+
24
+ # ----------------------------------------------------------------------------
25
+ # Fichiers
26
+ # ----------------------------------------------------------------------------
27
+ def charger_probleme(chemin):
28
+ """Lit un problème dans un fichier .json ou .npz.
29
+
30
+ Le fichier contient les clés a, b, c, phi, et éventuellement une clé
31
+ "parametres" (n_population, alpha, explor, iterations, positivity).
32
+ Renvoie (a, b, c, phi, parametres) ; `parametres` est un dict, éventuellement vide.
33
+ """
34
+ chemin = str(chemin)
35
+ bas = chemin.lower()
36
+ if bas.endswith(".json"):
37
+ with open(chemin, encoding="utf-8") as f:
38
+ donnees = json.load(f)
39
+ elif bas.endswith(".npz"):
40
+ with np.load(chemin, allow_pickle=False) as f:
41
+ donnees = {k: f[k] for k in f.files}
42
+ else:
43
+ raise ValueError("Format non pris en charge : utilise un fichier .json ou .npz")
44
+
45
+ manquantes = [k for k in CLES_PROBLEME if k not in donnees]
46
+ if manquantes:
47
+ raise ValueError("Clés manquantes dans le fichier : " + ", ".join(manquantes))
48
+
49
+ parametres = donnees.get("parametres", {})
50
+ if not isinstance(parametres, dict):
51
+ raise ValueError('"parametres" doit être un dictionnaire.')
52
+ inconnus = [k for k in parametres if k not in CLES_PARAMETRES]
53
+ if inconnus:
54
+ raise ValueError("Paramètres inconnus : " + ", ".join(inconnus)
55
+ + " (attendus : " + ", ".join(CLES_PARAMETRES) + ")")
56
+
57
+ a, b, c, phi = (np.asarray(donnees[k]) for k in CLES_PROBLEME)
58
+ return a, b, c, phi, dict(parametres)
59
+
60
+
61
+ def ecrire_exemple(chemin):
62
+ """Écrit un fichier .json d'exemple que l'utilisateur peut modifier."""
63
+ exemple = {
64
+ "a": [[2, 3, 1, 4, 2, 1, 3, 2],
65
+ [1, 1, 2, 3, 1, 4, 2, 1],
66
+ [3, 1, 1, 2, 4, 1, 1, 3]],
67
+ "b": [40, 36, 42],
68
+ "c": [[3, -1, 2, 0, 4, -2, 1, 1],
69
+ [-2, 4, 1, -1, 0, 3, -3, 2],
70
+ [1, 2, -4, 3, -1, 1, 2, -2],
71
+ [0, -3, 2, 2, 1, -1, 4, -1],
72
+ [2, 1, 1, -3, 2, 2, -2, 3]],
73
+ "phi": [-3, -2, -4, -1, -2, -3, -1, -2],
74
+ "parametres": {
75
+ "n_population": 20,
76
+ "alpha": 4,
77
+ "explor": 3,
78
+ "iterations": 16,
79
+ "positivity": True,
80
+ },
81
+ }
82
+ with open(chemin, "w", encoding="utf-8") as f:
83
+ json.dump(exemple, f, indent=2, ensure_ascii=False)
84
+ return exemple
85
+
86
+
87
+ # ----------------------------------------------------------------------------
88
+ # Saisie interactive
89
+ # ----------------------------------------------------------------------------
90
+ def _nombre(brut):
91
+ """Convertit un texte en int si possible, sinon en float."""
92
+ try:
93
+ return int(brut)
94
+ except ValueError:
95
+ return float(brut)
96
+
97
+
98
+ def demander(invite, defaut=None, type_=int, minimum=None, maximum=None):
99
+ """Pose une question, répète tant que la réponse est invalide.
100
+ Entrée vide = valeur par défaut."""
101
+ while True:
102
+ suffixe = "" if defaut is None else f" [{defaut}]"
103
+ brut = input(f"{invite}{suffixe} : ").strip()
104
+ if brut == "":
105
+ if defaut is not None:
106
+ return defaut
107
+ print(" Une valeur est requise.")
108
+ continue
109
+ try:
110
+ valeur = type_(brut)
111
+ except ValueError:
112
+ print(" Valeur invalide.")
113
+ continue
114
+ if (minimum is not None and valeur < minimum) or \
115
+ (maximum is not None and valeur > maximum):
116
+ borne = f"entre {minimum} et {maximum}" if None not in (minimum, maximum) \
117
+ else (f">= {minimum}" if minimum is not None else f"<= {maximum}")
118
+ print(f" La valeur doit être {borne}.")
119
+ continue
120
+ return valeur
121
+
122
+
123
+ def demander_oui_non(invite, defaut=True):
124
+ indice = "O/n" if defaut else "o/N"
125
+ while True:
126
+ brut = input(f"{invite} [{indice}] : ").strip().lower()
127
+ if brut == "":
128
+ return defaut
129
+ if brut in ("o", "oui", "y", "yes"):
130
+ return True
131
+ if brut in ("n", "non", "no"):
132
+ return False
133
+ print(" Réponds par o ou n.")
134
+
135
+
136
+ def demander_vecteur(invite, longueur):
137
+ """Lit `longueur` nombres séparés par des espaces ou des virgules."""
138
+ while True:
139
+ brut = input(f"{invite} : ").replace(",", " ").split()
140
+ try:
141
+ valeurs = [_nombre(t) for t in brut]
142
+ except ValueError:
143
+ print(" Il faut uniquement des nombres.")
144
+ continue
145
+ if len(valeurs) != longueur:
146
+ print(f" {longueur} nombres attendus, {len(valeurs)} reçus.")
147
+ continue
148
+ return valeurs
149
+
150
+
151
+ def saisir_probleme():
152
+ """Saisie au clavier de a, b, c, phi. Renvoie (a, b, c, phi)."""
153
+ n = demander("Nombre de variables n", minimum=1)
154
+ m = demander("Nombre de contraintes m", minimum=1)
155
+ p = demander("Nombre d'objectifs p (lignes de c)", minimum=1)
156
+
157
+ print(f"\nMatrice a : {m} lignes de {n} nombres (contraintes a·x <= b)")
158
+ a = [demander_vecteur(f" a, ligne {i + 1}/{m}", n) for i in range(m)]
159
+ b = demander_vecteur(f"Second membre b : {m} nombres", m)
160
+ print(f"\nMatrice c : {p} lignes de {n} nombres (objectifs)")
161
+ c = [demander_vecteur(f" c, ligne {i + 1}/{p}", n) for i in range(p)]
162
+ phi = demander_vecteur(f"Fonction à minimiser phi : {n} nombres", n)
163
+ return np.array(a), np.array(b), np.array(c), np.array(phi)
164
+
165
+
166
+ def saisir_parametres(n, defauts=None):
167
+ """Demande les paramètres de l'algorithme (n = nombre de variables, pour proposer
168
+ 2·n itérations). Renvoie un dict utilisable par `solve`."""
169
+ d = dict(PARAMETRES_DEFAUT)
170
+ d.update(defauts or {})
171
+ print("\nParamètres de l'algorithme (Entrée = valeur proposée)")
172
+ n_population = demander(" Taille de la population", d["n_population"], minimum=1)
173
+ alpha = demander(" alpha", d["alpha"], minimum=1)
174
+ explor = demander(" Variables explorées par itération", min(d["explor"], n),
175
+ minimum=1, maximum=n)
176
+ iterations = demander(" Nombre d'itérations",
177
+ 2 * n if d["iterations"] is None else d["iterations"], minimum=1)
178
+ positivity = demander_oui_non(" Ajouter les contraintes x >= 0 ?", d["positivity"])
179
+ return {"n_population": n_population, "alpha": alpha, "explor": explor,
180
+ "iterations": iterations, "positivity": positivity}
dega2/example.py ADDED
@@ -0,0 +1,29 @@
1
+ """Démonstration : reproduit le script DEGA2.py d'origine sur un problème aléatoire."""
2
+ import numpy as np
3
+
4
+ from . import problems
5
+ from .solver import solve
6
+
7
+
8
+ def demo(n=30, p=10, m1=15, n_population=80, alpha=4, explor=3,
9
+ iterations=None, seed=None, plot=True, verbose=True):
10
+ """Génère un problème aléatoire (n variables, p objectifs, m1 contraintes),
11
+ le résout avec DEGA-2 et renvoie le `Result`."""
12
+ if seed is not None:
13
+ np.random.seed(seed)
14
+
15
+ a, b, c, phi = problems.Genr(n, m1, p)
16
+ T = 2 * n if iterations is None else iterations
17
+
18
+ if verbose:
19
+ print("\n🧬 DEGA-2 — démarrage de l'optimisation "
20
+ f"(n={n}, objectifs={p}, contraintes={m1}, itérations={T})\n")
21
+
22
+ res = solve(a, b, c, phi, n_population=n_population, alpha=alpha,
23
+ explor=explor, iterations=T, verbose=verbose)
24
+
25
+ if verbose:
26
+ print("\n" + res.summary(max_vars=n) + "\n")
27
+ if plot:
28
+ res.plot()
29
+ return res
dega2/influ_cof.py ADDED
@@ -0,0 +1,29 @@
1
+ import numpy as np
2
+
3
+
4
+ def selct(c, n, p, phi):
5
+ # coefficients normalisés (version vectorisée des doubles boucles d'origine)
6
+ sum_c = np.sum(np.abs(c), axis=1)[:, np.newaxis]
7
+ sum_phi = np.sum(np.abs(phi))
8
+ cof_c = np.sum(c / sum_c, axis=0) # influence cumulée de chaque variable
9
+ cof_phi = phi[0, :] / sum_phi
10
+
11
+ p_cof1 = np.empty((3, n))
12
+ p_cofphi1 = np.empty((3, n))
13
+
14
+ p_cof1[0, :] = np.abs(cof_c)
15
+ p_cofphi1[0, :] = np.abs(cof_phi)
16
+ p_cof1[1, :] = np.arange(n)
17
+ p_cofphi1[1, :] = np.arange(n)
18
+ p_cof1[2, :] = np.where(cof_c < 0, -1, 1)
19
+ # Comportement d'origine conservé : le signe de p_cofphi vaut toujours -1
20
+ # (les deux branches du `if` d'origine donnaient -1). Voir remarque.
21
+ p_cofphi1[2, :] = -1
22
+
23
+ # tri par influence décroissante (même expression que l'original)
24
+ p_cof1 = p_cof1[::, p_cof1[0, ].argsort()[::-1]]
25
+ p_cofphi1 = p_cofphi1[::, p_cofphi1[0, ].argsort()[::-1]]
26
+ index_p = (p_cof1[1, :])[np.newaxis, :].astype(int)
27
+ index_phi = (p_cofphi1[1, :])[np.newaxis, :].astype(int)
28
+
29
+ return [p_cof1, index_p, p_cofphi1, index_phi]
dega2/plotting.py ADDED
@@ -0,0 +1,32 @@
1
+ """Courbe de convergence (matplotlib est une dépendance optionnelle)."""
2
+ import numpy as np
3
+
4
+
5
+ def plot_convergence(result, show=True):
6
+ try:
7
+ import matplotlib.pyplot as plt
8
+ except ImportError as exc: # pragma: no cover
9
+ raise ImportError(
10
+ "matplotlib est requis pour tracer la courbe : "
11
+ "pip install \"dega2[plot]\""
12
+ ) from exc
13
+
14
+ y = np.ravel(result.history)
15
+ t = np.arange(len(y))
16
+
17
+ fig, ax = plt.subplots(figsize=(9, 5))
18
+ ax.plot(t, y, color="#d62728", linewidth=2, label="min φ")
19
+ ax.fill_between(t, y, y.max(), color="#d62728", alpha=0.08)
20
+ ax.scatter([t[-1]], [y[-1]], color="#d62728", zorder=3)
21
+ ax.annotate(f"φ* = {y[-1]:.4g}", xy=(t[-1], y[-1]),
22
+ xytext=(-90, 25), textcoords="offset points",
23
+ arrowprops=dict(arrowstyle="->", color="gray"))
24
+ ax.set_xlabel("Iterations")
25
+ ax.set_ylabel("min of phi")
26
+ ax.set_title("Convergence of DEGA-2")
27
+ ax.grid(True, linestyle="--", alpha=0.4)
28
+ ax.legend()
29
+ fig.tight_layout()
30
+ if show:
31
+ plt.show()
32
+ return fig
dega2/problems.py ADDED
@@ -0,0 +1,15 @@
1
+ import numpy as np
2
+
3
+ def Genr(n,m1,p):
4
+ a=np.random.randint(1,10,(m1,n),dtype=int)
5
+
6
+
7
+
8
+ b=np.random.randint(8*n,10*n,m1,dtype=int)[:,np.newaxis]
9
+
10
+
11
+ c=np.random.randint(-10,10,(p,n),dtype=int)
12
+ phi=np.random.randint(-10,10,n,dtype=int)[np.newaxis,:]
13
+ return a,b,c,phi
14
+
15
+
dega2/solver.py ADDED
@@ -0,0 +1,120 @@
1
+ """Interface publique de DEGA-2.
2
+
3
+ >>> import dega2
4
+ >>> res = dega2.solve(a, b, c, phi)
5
+ >>> res.x, res.phi
6
+ """
7
+ import time
8
+ from dataclasses import dataclass
9
+
10
+ import numpy as np
11
+
12
+ from . import GA4, GenPop, influ_cof
13
+
14
+
15
+ @dataclass
16
+ class Result:
17
+ """Résultat d'une optimisation DEGA-2."""
18
+
19
+ x: np.ndarray # meilleure solution trouvée (vecteur de longueur n)
20
+ phi: float # valeur de phi pour cette solution
21
+ history: np.ndarray # minimum de phi à chaque itération
22
+ population: np.ndarray # population de la dernière itération, avant sélection (une solution par colonne)
23
+ time: float # temps de calcul en secondes
24
+ iterations: int # nombre d'itérations effectuées
25
+
26
+ def summary(self, max_vars=None):
27
+ """Encadré texte récapitulatif (comme dans le script d'origine)."""
28
+ x = np.ravel(self.x)
29
+ shown = x if max_vars is None else x[:max_vars]
30
+ apercu = ", ".join(f"{v:.4g}" for v in shown)
31
+ lignes = [
32
+ "RÉSULTATS DEGA-2",
33
+ f"Phi optimum : {self.phi:.6g}",
34
+ f"Temps CPU : {self.time:.2f} s",
35
+ f"Itérations : {self.iterations}",
36
+ f"x* : {apercu}",
37
+ ]
38
+ largeur = max(len(ligne) for ligne in lignes) + 2
39
+ out = ["┏" + "━" * largeur + "┓"]
40
+ for i, ligne in enumerate(lignes):
41
+ out.append("┃ " + ligne.ljust(largeur - 1) + "┃")
42
+ if i == 0:
43
+ out.append("┣" + "━" * largeur + "┫")
44
+ out.append("┗" + "━" * largeur + "┛")
45
+ return "\n".join(out)
46
+
47
+ def plot(self, show=True):
48
+ """Trace la courbe de convergence (nécessite matplotlib)."""
49
+ from .plotting import plot_convergence
50
+ return plot_convergence(self, show=show)
51
+
52
+
53
+ def solve(a, b, c, phi, *, n_population=80, alpha=4, explor=3,
54
+ iterations=None, positivity=True, seed=None, verbose=True):
55
+ """Lance DEGA-2 sur le problème : min phi·x sous a·x <= b, x entier.
56
+
57
+ Paramètres
58
+ ----------
59
+ a : (m, n) matrice des contraintes.
60
+ b : (m,) ou (m, 1) second membre.
61
+ c : (p, n) matrice des p objectifs (sert au test de non-dominance).
62
+ phi : (n,) ou (1, n) fonction objectif scalaire à minimiser.
63
+ n_population : taille de la population.
64
+ alpha : la population d'exploration « phi » est de taille n_population / alpha.
65
+ explor : nombre de variables explorées à chaque itération.
66
+ iterations : nombre d'itérations (par défaut 2 * n).
67
+ positivity : si True, ajoute les contraintes x >= 0 (comme le script d'origine).
68
+ seed : graine du générateur aléatoire (résultats reproductibles).
69
+ verbose : affiche la barre de progression.
70
+
71
+ Renvoie un objet `Result`.
72
+ """
73
+ a = np.atleast_2d(np.asarray(a))
74
+ b = np.asarray(b).reshape(-1, 1)
75
+ c = np.atleast_2d(np.asarray(c))
76
+ phi = np.asarray(phi).reshape(1, -1)
77
+
78
+ n = a.shape[1]
79
+ p = c.shape[0]
80
+ if b.shape[0] != a.shape[0]:
81
+ raise ValueError("b doit avoir autant de lignes que a.")
82
+ if c.shape[1] != n or phi.shape[1] != n:
83
+ raise ValueError("a, c et phi doivent avoir le même nombre de variables n.")
84
+ if not 1 <= explor <= n:
85
+ raise ValueError("explor doit être compris entre 1 et n.")
86
+ if n_population < 1 or alpha < 1:
87
+ raise ValueError("n_population et alpha doivent être >= 1.")
88
+
89
+ T = 2 * n if iterations is None else int(iterations)
90
+
91
+ if seed is not None:
92
+ np.random.seed(seed)
93
+
94
+ if positivity:
95
+ a = np.concatenate((a, -np.eye(n)), axis=0)
96
+ b = np.concatenate((b, np.zeros((n, 1))), axis=0)
97
+
98
+ # Population initiale
99
+ population = GenPop.Gen(a, b, c, n, n_population)
100
+
101
+ # Influence des coefficients
102
+ p_cof1, index_p, p_cofphi1, index_phi = influ_cof.selct(c, n, p, phi)
103
+
104
+ # Algorithme
105
+ t0 = time.perf_counter()
106
+ pop_final, _, min_phi, x_opt = GA4.NewPop(
107
+ population, n_population, explor,
108
+ p_cof1, index_p, p_cofphi1, index_phi,
109
+ phi, alpha, a, b, c, T, n, verbose=verbose)
110
+ elapsed = time.perf_counter() - t0
111
+
112
+ history = np.asarray(min_phi, dtype=float)
113
+ return Result(
114
+ x=np.ravel(x_opt),
115
+ phi=float(history[-1]),
116
+ history=history,
117
+ population=pop_final,
118
+ time=elapsed,
119
+ iterations=T,
120
+ )
dega2/upload_cofGA.py ADDED
@@ -0,0 +1,72 @@
1
+ import numpy as np
2
+ from collections import Counter
3
+ def upload(p_cof1,index_p,p_cofphi1,index_phi,tab_ind1,tab_ind1_phi,tab_ind11,tab_ind11_phi, explor,condidat_phi,condidat,n_pop,n_pop_phi):
4
+ x1=Counter(tab_ind11)
5
+ x2=Counter(tab_ind11_phi)
6
+ x3=Counter(tab_ind1)
7
+ x4=Counter(tab_ind1_phi)
8
+ counter_tab11=list(x1.items())
9
+ counter_tab11_phi=list(x2.items())
10
+ counter_tab1=list(x3.items())
11
+ counter_tab1_phi=list(x4.items())
12
+
13
+
14
+ l1=len(counter_tab1)
15
+ l2=len(counter_tab11)
16
+ l3=len(counter_tab1_phi)
17
+ l4=len(counter_tab11_phi)
18
+
19
+ if (l1==explor) and (l2==explor):
20
+ rho=[]
21
+ for i in range (0,explor):
22
+ rho.append(counter_tab11[i][1]/counter_tab1[i][1])
23
+ else:
24
+ rho=[0]*explor
25
+ for ii in range(0,explor):
26
+ jj=0
27
+ while jj<l1:
28
+ if condidat[ii]==counter_tab1[jj][0]:
29
+ tt=0
30
+ while tt<l2:
31
+ if counter_tab1[jj][0]==counter_tab11[tt][0]:
32
+ rho[ii]=counter_tab11[tt][1]/counter_tab1[jj][1]
33
+ tt=tt+1
34
+ jj=jj+1
35
+
36
+
37
+ if (l3==explor) and (l4==explor):
38
+ rho1=[]
39
+ for i in range (0,explor):
40
+ rho1.append(counter_tab11_phi[i][1]/counter_tab1_phi[i][1])
41
+ else:
42
+ rho1=[0]*explor
43
+ for ii in range(0,explor):
44
+ jj=0
45
+ while jj<l3:
46
+ if condidat_phi[ii]==counter_tab1_phi[jj][0]:
47
+ tt=0
48
+ while tt<l4:
49
+ if counter_tab1_phi[jj][0]==counter_tab11_phi[tt][0]:
50
+ rho1[ii]=counter_tab11_phi[tt][1]/counter_tab1_phi[jj][1]
51
+ tt=tt+1
52
+ jj=jj+1
53
+ rho_p=[]
54
+ rho_phi=[]
55
+ for i in range(0,explor):
56
+ rho_p.append((p_cof1[0,i])*(rho[i])**2)
57
+ p_cof1[0,i]=rho_p[i]
58
+ rho_phi.append((p_cofphi1[0,i])*(rho1[i])**2)
59
+ p_cofphi1[0,i]=rho_phi[i]
60
+
61
+ p_cof1= p_cof1[::, p_cof1[0,].argsort()[::-1]]
62
+ p_cofphi1= p_cofphi1[::, p_cofphi1[0,].argsort()[::-1]]
63
+ index_p=(p_cof1[1,:])[np.newaxis,:]
64
+ index_phi=(p_cofphi1[1,:])[np.newaxis,:]
65
+ index_p=index_p.astype(int)
66
+ index_phi=index_phi.astype(int)
67
+ return p_cof1,p_cofphi1, index_p,index_phi
68
+
69
+
70
+
71
+
72
+
@@ -0,0 +1,122 @@
1
+ Metadata-Version: 2.4
2
+ Name: dega2
3
+ Version: 0.1.0
4
+ Summary: DEGA-2: A optimization a function over the efficient set of multi-objective integer variables using the genetics algorithms
5
+ Author-email: Ali Zaidi <a.zaidi@crlca.dz>
6
+ License-Expression: MIT
7
+ Keywords: optimization,genetic algorithm,multi-objective,integer programming
8
+ Classifier: Programming Language :: Python :: 3
9
+ Classifier: Intended Audience :: Science/Research
10
+ Classifier: Topic :: Scientific/Engineering :: Mathematics
11
+ Requires-Python: >=3.9
12
+ Description-Content-Type: text/markdown
13
+ License-File: LICENSE
14
+ Requires-Dist: numpy
15
+ Requires-Dist: tqdm
16
+ Provides-Extra: plot
17
+ Requires-Dist: matplotlib; extra == "plot"
18
+ Provides-Extra: test
19
+ Requires-Dist: pytest; extra == "test"
20
+ Dynamic: license-file
21
+
22
+ # DEGA-2
23
+
24
+ A optimisation of function over the efficient set of multi-objective integer variables using a genetics algorithms, by Ali Zaidi.
25
+
26
+ It minimizes a function `phi·x` subject to linear constraints `a·x <= b`
27
+ (`x` integer, and `x >= 0` by default), using `p` objectives `c·x` for the
28
+ non-dominance test.
29
+
30
+ ## Installation
31
+
32
+ ```bash
33
+ pip install dega2
34
+ # with the convergence plot:
35
+ pip install "dega2[plot]"
36
+ ```
37
+
38
+ ## Entering your problem and parameters
39
+
40
+ ### 1. Interactive assistant
41
+
42
+ ```bash
43
+ dega2
44
+ ```
45
+
46
+ The assistant asks for the problem (file, keyboard entry, or a random example),
47
+ then for the parameters (population size, alpha, number of explored variables,
48
+ iterations, `x >= 0` constraints). Press Enter to accept the suggested value.
49
+
50
+ ### 2. `.json` file
51
+
52
+ ```bash
53
+ dega2 --exemple my_problem.json # writes a template to edit
54
+ dega2 -f my_problem.json # runs the computation
55
+ ```
56
+
57
+ File format:
58
+
59
+ ```json
60
+ {
61
+ "a": [[2, 3, 1], [1, 1, 2]],
62
+ "b": [20, 15],
63
+ "c": [[3, -1, 2], [-2, 4, 1]],
64
+ "phi": [-3, -2, -4],
65
+ "parametres": {
66
+ "n_population": 20, "alpha": 4, "explor": 3,
67
+ "iterations": 10, "positivity": true
68
+ }
69
+ }
70
+ ```
71
+
72
+ - `a`: constraint matrix (m rows, n columns); `b`: right-hand side (m values)
73
+ - `c`: objectives matrix (p rows, n columns); `phi`: function to minimize (n values)
74
+ - `parametres` is optional. Command-line options (`--population`, `--alpha`,
75
+ `--explor`, `-T`, `--sans-positivite`, `--seed`, `--no-plot`) take precedence over
76
+ the file. A `.npz` file (keys `a`, `b`, `c`, `phi`) is also accepted.
77
+
78
+ ### 3. In Python code
79
+
80
+ ```python
81
+ import numpy as np
82
+ import dega2
83
+
84
+ a = np.array([[2, 3, 1], [1, 1, 2]])
85
+ b = np.array([20, 15])
86
+ c = np.array([[3, -1, 2], [-2, 4, 1]])
87
+ phi = np.array([-3, -2, -4])
88
+
89
+ res = dega2.solve(a, b, c, phi, n_population=20, explor=3, iterations=10, seed=0)
90
+
91
+ print(res.phi) # best value of phi
92
+ print(res.x) # best solution
93
+ res.plot() # convergence curve (requires matplotlib)
94
+
95
+ # or from a file:
96
+ a, b, c, phi, params = dega2.charger_probleme("my_problem.json")
97
+ res = dega2.solve(a, b, c, phi, **params)
98
+ ```
99
+
100
+ `solve` parameters: `n_population=80`, `alpha=4`, `explor=3`,
101
+ `iterations=None` (2·n by default), `positivity=True`, `seed=None`, `verbose=True`.
102
+ `solve` returns a `Result` object: `x`, `phi`, `history` (minimum of phi at each
103
+ iteration), `population`, `time`, `iterations`.
104
+
105
+ Note: the algorithm builds a population of `n_population` feasible solutions that
106
+ are mutually non-dominated. With very few objectives or variables, such a
107
+ population may not exist; `dega2` then stops with an error message (reduce
108
+ `n_population` or add objectives).
109
+
110
+ ## Random demonstration
111
+
112
+ ```bash
113
+ dega2 --demo --seed 1
114
+ dega2 --demo -n 20 -p 5 --no-plot
115
+ ```
116
+
117
+ ## Tests
118
+
119
+ ```bash
120
+ pip install -e ".[test]"
121
+ pytest
122
+ ```
@@ -0,0 +1,23 @@
1
+ dega2/BuildpopGA.py,sha256=rjdFi_fuzGCqdHqZioOrO6Moap_tN6i7TgkMMKdhDGg,1953
2
+ dega2/ConsChek.py,sha256=YeR8auh1Pp0qDOvqq5ho74qASVnzfxcuROiXz1TwuK8,169
3
+ dega2/ConsChekGA4.py,sha256=TYfZKhtZrnFfJaUHx3EiMk-akEBv1L1iMGN68v9ZuBo,577
4
+ dega2/DomChek.py,sha256=rafMg_9Xbt_cesNXxOYX2pOI2QX8e_xnGu1PkASijDk,692
5
+ dega2/DomChekGA4.py,sha256=FrLNy1q-PEcHr6kXyMOZa6WMCjs_A8qVs0_irqOU6hc,3332
6
+ dega2/GA4.py,sha256=mI4g6O6gDXia4npm7gpeiEIN9-6EMJHFOYaT3cHudhQ,2181
7
+ dega2/GenPop.py,sha256=ZgcXpGYZhIQnjrrHEa5Z8AP-SxQagRd0dIx_LBzLxQ8,1414
8
+ dega2/__init__.py,sha256=4YUmz0fH3yyfi7wPR5kCQU1-38usChBvgNP3IaGvfuc,307
9
+ dega2/__main__.py,sha256=MHKZ_ae3fSLGTLUUMOx15fWdeOnJSHhq-zslRP5F5Lc,79
10
+ dega2/cli.py,sha256=7XmihOue_34Edjov6YykhwFq43lL-GXdoktfMDqzbxY,6112
11
+ dega2/entree.py,sha256=zFqYLJnlpswm3pFKadrCYSLbHmn8rzLbqwZxGQ97kpQ,7009
12
+ dega2/example.py,sha256=iP2zpYYIr2xyGKD9_Besr8yaxsrVyVwgdHTUTMPC36g,987
13
+ dega2/influ_cof.py,sha256=B95jXUxy3JClO8uWKchPDBo3K-aob4xB0y2MXtviLIE,1116
14
+ dega2/plotting.py,sha256=3LgxRzR5SPp1GI80O1sQk1KetEYtTJu-E6qwUJJtlyE,1098
15
+ dega2/problems.py,sha256=xudbft7jXXpXA7actbJVtpqZ7LnPN_s01I8O4s8b5n8,294
16
+ dega2/solver.py,sha256=1F8OO7mIKkd0GIyaoQVwoDfmmnCumjJtcF_0ZafaGt8,4358
17
+ dega2/upload_cofGA.py,sha256=v3QeIWlhK8CQm9CE7Gc0ukIq1hKXkveQ0OxvJfpJYXU,2373
18
+ dega2-0.1.0.dist-info/licenses/LICENSE,sha256=1riZ1sfK9aSG3-OIJCXqWYqNOHIZApqInCP64juYiVU,1066
19
+ dega2-0.1.0.dist-info/METADATA,sha256=oGuueAcuxni3If4K4V8kIbeBARlbqCSTnZvXIAK49NQ,3550
20
+ dega2-0.1.0.dist-info/WHEEL,sha256=YVMoNqKzERt-wjUZwJ33xBGAwnFl-4cqbYkTtWa4itE,91
21
+ dega2-0.1.0.dist-info/entry_points.txt,sha256=8kH-bHcg7HiErUcwWDb1tNFiMWeewohUQfG9v1hpe1g,41
22
+ dega2-0.1.0.dist-info/top_level.txt,sha256=3MN8auQqwfRd1lNGX52TzD434deySaQnxiDtg-AI5So,6
23
+ dega2-0.1.0.dist-info/RECORD,,
@@ -0,0 +1,5 @@
1
+ Wheel-Version: 1.0
2
+ Generator: setuptools (84.0.0)
3
+ Root-Is-Purelib: true
4
+ Tag: py3-none-any
5
+
@@ -0,0 +1,2 @@
1
+ [console_scripts]
2
+ dega2 = dega2.cli:main
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2026 Ali Zaidi
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
@@ -0,0 +1 @@
1
+ dega2