Bienvenue sur IndexError.

Ici vous pouvez poser des questions sur Python et le Framework Django.

Mais aussi sur les technos front comme React, Angular, Typescript et Javascript en général.

Consultez la FAQ pour améliorer vos chances d'avoir des réponses à vos questions.

un python dans le jardin

+5 votes

J'ai une question qui ne porte pas sur un module en particulier, mais sur un conseil d' algorithme.

Auparavant, une entrée en matière:
Il s' agit de cultures associées dans le jardinage : certaines plantes se boostent mutuellement par leur action sur le pH, leurs secrétions et leur rôle sur la flore bactériologique et mycologique etc. D'autres se font la guerre.

bref, je dispose d'un tableau à 3 colonnes : la plante considérée, les plantes amies, les plantes ennemies.

ex: Les tomates vont bien avec le basilic et les carottes mais pas avec les betteraves ni le fenouil.
ex2: Les poireaux sont copains avec les fraisiers et les épinards, mais pas avec les haricots ni les pois.

On pourrait faire deux dicos:

  • le dico_AMIS = {"tomate":{'basilic','carotte'},"poireau":{'fraisier','épinard'}}

  • le dico_ENNEMIS = {"tomate":{'betterave','fenouil'},"poireau":{'haricot','pois'}}

J' imagine une petite interface graphique avec une grille, dont chaque case représente un mètre-carré de terrain.
L' utilisateur donne des dimensions ex: 250x75 et on trace la grille équivalente. il dispose de quelques icones-tirroirs : legumes,fruits,fleurs,etc. Dedans il attrape un pied de tomate, il fait un click n'drop et pouf, vla un mètre carré de tomate en terre !
Les cases adjacentes s'illuminent en jaune, une liste de plantes suggérées apparait, il n'y a plus qu'à refaire un click n'drop.

C'est plus compliqué que ça.
On veut planter des lignes qui s' alternent, ou bien des méga carrés de 10x10 en faisant un mix de graines pour avoir une bonne biodiversité. Mais on augmente de façon exponentielle le risque que l'une des plantes du mix "entre en conflit" avec une plante ennemie. En cas d' erreur, les cases conflictuelle s'illuminent en rouge, comme lorsqu'on joue au échec et que le roi est attaqué.

Il doit il y avoir une sorte d'annalyse recursive des dicos j' imagine, mais si vous avez un exemple, une suggestion...

http://mag.plantes-et-jardins.com/conseils-de-jardinage/fiches-conseils/bien-associer-les-legumes-au-potager

http://www.truffaut.com/webtv/jardin/video-bonnes-associations-plantes-jardin/id_video/146.htm

(nb : attention, les plantes à l' interieur d'un set ne sont pas forcément amies entre elles)

demandé 18-Jul-2015 par buffalo974 (2,886 points)
edité 18-Jul-2015 par boblinux

Cool j'ai appris des trucs sur le jardinage ! ;D

Sinon c'est quoi la question? Comment générer aléatoirement un carré de plantes diverses tout en faisant en sorte qu'il y ait le moins d'enemis possible? genre avec taux en % d'enemis maxi à tolérer pour un périmètre donné??

Et c'est une idée ça, les carrés 9x9 pré-calculés.
On pourrait les aligner dans l'icone tirroir "Mix", en mettant la plante reine comme clée et elle serait au centre du big carré (comme la touche 5 du bloc numérique).

on pourrait utiliser les rangs autour pour marcher d'un big carré à un autre .
Comme ça on circule facilement , et on isole des potentielles rivalités avec les autres
big carrés. Un mètre c'est une marge correcte.

Du coup, j'ai l'impression que je pourrais m'inspirer d'un jeu d' échec...
Une idée de one-liner pour pas réinventer la roue ?

Encore plus fun:
On a dit qu'un mètre de distance, c'est bien pour isoler les rivalités, mais du coup ça limite aussi la coopération entre amis.
Du coup, pour revenir à mon carré 9x9,il ne faudrait pas mettre la reine au centre, mais plutôt le "couple royal", qui serait entouré de "couples vassaux".

ça complexifie le code, mais c'est plus proches des besoins réels.
Par exemple, avec un couple royal poireaux-fraise en position 5 (regardez votre bloc numérique) Il faut s'assurer que le couple vassal en position 7 accepte celui en position 8 ainsi que le 4.
Ainsi de suite pour toutes les cases de la couronne.

C'est pu un jeu d' échec, c'est du sudoku là , nan ?

Comment évoluerait mon one-liner si on passait à des "couples" à 3, comme dans le
cas des Trois Soeurs ? ==> http://www.dailymotion.com/video/xepqiw_tentez-l-association-des-3-soeurs_lifestyle

J'arrive pas à te suivre, tu t'éparpilles un peu trop =D

J'aime beaucoup le projet mais je n'ai pas compris la question. Ta structure basée sur des dico est très bien, mais à mon avis il faut mieux foutre tout ça dans une base de données types sqlite, quitte à tout charger en mémoire après. Quel est ton problème ? Ton algo actuel n'est pas assez rapide ?

A terme, une base de donnée serait intéressant si le projet faisait un carton.
Il y a en effet beaucoup de variétés pour une même plante et certaines ont des propriétés uniques.

Mais pour l'instant c'est modeste et un bon algo sur dico me permettrait de me concentrer et de le recycler ailleurs plus rapidement.

J'ai pas de pb de rapidité vu que y'a encore rien de codé la-dessus, je suis encore dans la phase de réflexion.

Le lien de DoubleNain se rapprocherait de mon idée de grille. Je remplacerais les
cases cultivées par un petit PNG.

pourriez vous tester vite fait mon code svp ?

6 Réponses

+2 votes
 
Meilleure réponse

Crash Test Version 0.1 prête

Edit de boblinux :

Pour ceux qui voudraient jeter un coup d’œil au code / le tester / forker (et même y contribuer si ça vous chante ;p), ça se passe par ici :

https://github.com/IndexErrorCoders/pygarden

répondu 4-Aou-2015 par buffalo974 (2,886 points)
edité 8-Aou-2015 par boblinux
+2 votes

Et si tu modélisait les affinités de tes plantes par une matrice?
Genre:

Plante    | Carotte  | Betterave | Haricots
--------  | -------- |  -------- | --------
Carotte   | X        | Amis      | Ennemis
Betterave | Amis     | X         | Amis
Haricots  | Ennemis  | Amis      | X

Le lecteur attentif aura remarqué qu'il s'agit d'un matrice symétrique.

Pour la gestion des conflits entre tes cases, j'avais d'abord pensé à modéliser le truc par un graphe. Mais en fin de compte ça sera surement aussi simple de parcourir ton jardin case par case et de vérifier les compatibilités (cf la matrice).

répondu 19-Jul-2015 par greizgh (128 points)

Je pense que la modélisation proposée à la base, à savoir l'utilisation des dicos est plus propre/pythonesque/rapide

Pour le programme, je mise sur le dico, et pour l' utilisateur, on pourrait lui fournir
un joli tableau comme le propose greizgh

Une solution de facilité serait de faire une croix avec le couple royal :

  7X9
  XXX
  1X3

7,9,1,3 sont des couples vassaux (en exemplaire unique) dans les angles de mon big carré 9x9, le X représente mon couple royal muiltiplanté au sites 8,4,5,6,2.
Du coup chaque couple vassal est isolé de toute plante ennemie et forcément amie
avec les cases adjacentes cultivée. L’extrême périphérie représente les planches au sol pour circuler et étouffer l'herbe.

C'est la solution anti-sèche, mais "un vrai pythonista se sort les doigts" ;-)

+1 vote

Ton problème est un problème d'optimisation. A moins de rester sur des surfaces très faible ou de vouloir créer un casse tête, ton utilisateur va avoir du fil à retorde.

Pourquoi ne pas lui proposé directement une solution?
1) Demandé à l'utilisateur les plantes qu'il souhaite et la surface.
2) Utilisé un algorithme d'optimisation, je verrais bien un algo génétique dans ce cas pour trouvé une solution convenable.
3) Lui présenter la solution graphiquement.

répondu 20-Jul-2015 par Andarus (172 points)

On pourrait faire les deux dans un monde parfait.
-Avoir des carrés 9x9 pré-calculés (besoin d' algo ou se faire chier à la main).

-avoir un carré fun où notre jardinier commence à planter ce qui lui chante (envie de fraise ou melon en été, paquet de graine offert par le voisin, etc.) et au fur et à mesure qu'il remplit son big carré, c'est de plus en plus complexe à choisir. Le programme joue le rôle d' assistant en calculant les possibilités.

L'optimisation ce serait d'avoir dans notre carré de 9 : un couple royal central et huit couples vassaux uniques soit un total de 18 espèces végétales par big carré.
et ceci :
- sans aucun cas de cases en conflit
- et si possibles des amitiés inter-vassales adjacentes. (hyper optimisation)

L'optimisation accroît la productivité du jardin en augmentant les récoltes et en diminuant la sensibilités aux maladies (pucerons,champignon,déficit azote phosphore potassium, etc.).

+3 votes

Concernant la création incrémentale de l'espace

Étant donné que l'espace est découpé en cases et que seules les cases adjacentes interagissent entre elles, une modification locale du graphe n'agit que sur une portion minime du graphe, c'est à dire des cases adjacentes à la case modifiée. Donc, pas besoin de tout recalculer à chaque fois.

La structure supportant ce changement atomique pourrait s'appuyer sur un dictionnaire de plante simulant un espace à deux dimensions ({(int, int):plante}), et sur un second dictionnaire donnant les couleurs associées ({(int, int):couleur}).

NEUTRE  = 0
AMIE        = 1
ENNEMIE = 2
COULEUR_NEUTRE = 'black'
COULEUR_AMIE = 'green'
COULEUR_ENNEMIE = 'red'

def liaison(p1, p2):
    """Retourne NEUTRE, AMIE ou ENNEMIE selon si la plante1 est neutre, amie ou ennemie avec la plante2"""
    pass  # TODO: appel aux dico AMIE et ENNEMIE


def voisines(x, y, espace):
    """Retourne un générateur de plante, représentant les voisins de (x;y) dans un ordre quelconque"""
    return (espace[x+i, y+j]
        for i, j in itertools.product(range(-1, 2), 2)
        if j != 0  and i != 0  # on ne considère pas la case de la plante elle-même (elle n'est pas sa propre voisine)
    )


def maj_couleur_carre(x, y, espace, couleurs):
    """Modifie la couleur du carré (x;y) selon ses liaisons avec ses voisins"""
    plante = espace[x, y]
    couleurs[x, y] = max(liaison(plante, voisine) for voisine in voisines(x, y, espace))) 


def change_plante(x, y, espace, couleur, plante):
    """Modifie l'espace au coordonnées (x;y) pour que la plante donnée y soit placée

    Si la plante est None, aucune plante ne sera placée et toute plante préexistante sera supprimée"""
    espace[x, y] = plante
    [maj_couleur_carre(i, j, espace, couleur) for i, j in voisines(x, y, espace)]

Concernant une recherche des meilleures solutions

Il existe des moyens, via des algorithmes indépendants du langage, pour résoudre ce problème combinatoire.

Pourtant, je ne ferais pas appel à une telle technique si le temps n'est pas une composante essentielle du programme. (si tout doit être calculé sur un microcontrôleur, avec des terrains et contraintes gigantesques)

Pour ce genre de problème, une méthode beaucoup plus simple est de plus en plus abordée : les langages logiques reposant sur la contrainte et la recherche de modèles stables.
La raison est la suivante : le problème est trop complexe pour avoir une solution optimale rapidement (combinatoire), et quand bien même un algorithme résoudrai le problème, sa complexité est telle que la maintenance n'est pas triviale. Autant sacrifier un peu de temps (et encore) pour travailler avec un outils plus adapté à la recherche de solution, suivant des heuristiques déjà prêtes, optimisées et optimisables.

Prolog, un langage français (cocorico), en est un bon exemple, très utilisé dans le domaine de la représentation de données, la query evaluation. (Watson d'IBM et le robonaute de la NASA utilisent Prolog comme base de donnée)

Answer Set Programming, un autre langage logique particulièrement optimisé pour les problèmes combinatoires, ne fonctionne pas comme Prolog, mais serais peut-être plus adapté dans ce cas. L'implémentation de Potassco, notamment Clingo dans ton cas (à essayer sur le web), permet d'interfacer l'outil avec python assez facilement, à l'aide du packaging pip.

Personnellement, j'utilise Answer Set Programming pour la manipulation et le traitement de concepts formels, et entre autre la recherche de cliques et de bicliques au sein d'un graphe. C'est impressionnant de simplicité et d'efficacité.

répondu 23-Jul-2015 par lucas (2,332 points)
edité 23-Jul-2015 par lucas
+4 votes

(EDIT du 27 juillet 2015 en bas de page)
(EDIT du 28 juillet :
- Pour un code plus commenté, demande-le moi, car ici le snippet est tronqué
- Seules les lignes "dico_affinités =..." sont à modifier.
- Les valeurs des dicos d'affinité doivent être des tuples et non des sets
- Il faudrait une fonction qui écrive la liste des plantes à placer à partir des dicos, ou le contraire...Bref, je te laisse le modèle de données)

Oui, je suis d'accord pour la programmation logique. Clairement,on a un graphe à traiter, une "sociologie des plantes".
Maintenant je suis bien étonné qu'aucun Pythonista n'ait pensé à pyDatalog ; C'est fait par un belge, Pierre Carbonnelle :
https://sites.google.com/site/pydatalog/

Soit on passe des chaînes "str" de clauses à traiter (c'est lourd !), soit on utilise un décorateur qui dit que le prochain "scope" de fonction sera fait de clauses écrites directement en Datalog. Attention, même dans une fonction décorée, les clauses bossent sur le scope global ; franchement c'est traître.

Deux manières de l'utiliser :
- En procédural, au fil du script, donc sur les variables globales
- En orienté objet, dans une classe qui sert de frontal à un ORM, SQLAlchemy typiquement. Dans ce dernier cas, on écrit une fonction anonyme "def _(self):" qui sert de réservoir à clauses pour la classe / table mappée.

Le module interagit bien avec Python, ya moyen d'utiliser des fonctions Python et des modules dans les clauses Datalog, imaginez un peu ce que ça ouvre de perspectives...
En revanche, impossible de transformer un dictionnaire Python en fonction logique, même si les deux notations sont identiques et ont en fait le même sens. Il vaut beaucoup mieux également effectuer les "tours de boucle" dans Datalog

Concernant la vitesse de pédalage du moteur d'inférence, ya une configuration particulière qui utilise PyPy, là aussi très adapté puisque c'est le CPU et la RAM qui travaillent plus que les entrées-sorties. Normalement, à l'installation du module, il va tirer PyPy justement...

Enfin, sur le site pyDatalog, ya l'exemple des "8 reines", avec placements et contraintes réciproques, très pertinent ici.


# -*- coding: utf-8 -*-
#
from pyDatalog import pyDatalog as pdl
#
DEFAUT_GRILLE = 10
taille = DEFAUT_GRILLE
#
dico_affinités = {'fraisier':('tussilage', 'laitue'), 'bergamote':('valériane', 'choux')}
dico_inimitiés = {'bergamote': ('tussilage', 'laitue'),'fraisier':('valériane', 'choux')}
liste_plantes = ['bergamote', 'fraisier','tussilage', 'laitue', 'valériane', 'choux']

@pdl.program()
def _():
    """
    """
    pdl.clear()
    #
    (grille(X,Y)) 
répondu 24-Jul-2015 par jeancd (124 points)
edité 27-Jul-2015 par jeancd

Pourrais tu donnez quelques brèves lignes de code, juste pour illustrer comment je pourrais m'en servir dans mon prog ?

+3 votes

Personnellement j'utiliserais les sets pour ça:

Tu représente tes cases par des sets de plantes qui sont acceptables/interdites (ou les deux avec dico par dessus si tu veux) autour :

plantes =   [
    [{'A', 'B'}, {'E'}, {B'}],
    [{'C', 'B'}, {'A'}, {'B', 'D'}],
    [{'B', 'D'}, {B'}, {'B', 'D'}],
]

Ensuite, pour savoir ce que tu peux mettre dans une case, tu prends toutes les case autours, et tu fais l'union des sets pour connaitres toutes les plantes qui sont acceptées/interdites dans cette case.

Par exemple, si je veux savoir quoi mettre là:

plantes =   [
    [{'A', 'B'}, {'E'}, {B'}],
    [{'C', 'B'}, {'A'}, {'B', 'D'}],
    [????, {B'}, {'B', 'D'}],
]

En partant du principe que mes sets représentent uniquement les plantes interdites (pour toi se sera plus complet) :

# toutes les plantes
toutes_plantes = {'A', 'B', 'C', 'D', 'E'}

# coordonnées de la plante
x, y = 2, 0

plantes_interdites = set()

# parcours de toutes les cases autour
for X in (x, x-1, x+1):
    for Y in (y, y-1, y+1):
        if X > 0 and Y > 0:
            try:
                plantes_interdites |= plantes[X][Y]
            except IndexError:
                pass

plante_autorisees = toutes_plantes - plantes_interdites
print(plante_autorisees)
set(['E', 'D'])
répondu 2-Aou-2015 par Sam (4,984 points)

grosso-modo c'est ce que j'ai fait, je pense pouvoir publier d'ici une semaine. Des bugs et du dégueulis dans le code à karchériser auparavant.


Je voulais aussi publier ceci sur le subreddit mais jme suis méfié du downvote.

Ici, la thématique jardinage est déjà entamée alors la tentation est trop forte :
https://soundcloud.com/podcastscience/169-ogm-avec-marc-robinson-rechavi
MP3 super intéressant.

...