Partagez
Voir le sujet précédentAller en basVoir le sujet suivant
avatar
Flo44
Habitué du forum

[Maths] Où trouver un générateur de pyramides additives ? Empty [Maths] Où trouver un générateur de pyramides additives ?

par Flo44 le Ven 15 Mai 2020 - 9:24
Bonjour,
Je cherche un génénateur ou une méthode rapide et efficace pour générer ce type de pyramide :
http://pegame.ens-lyon.fr/activite.php?rubrique=2&id_theme=28&id_activite=81&
En effet, je veux en faire avec des relatifs, et les toutes faites que je trouve ne correspondent pas du tout à l'approche que j'ai eue avec mes élèves, ou bien sont avec des nombres non entiers (et je sais que c'est trop difficile pour la majorité de mes élèves).
Merci.
Pourquoi 3,14159
Pourquoi 3,14159
Fidèle du forum

[Maths] Où trouver un générateur de pyramides additives ? Empty Re: [Maths] Où trouver un générateur de pyramides additives ?

par Pourquoi 3,14159 le Ven 15 Mai 2020 - 9:59
Avec un tableur tu peux réaliser cela en fusionnant les cellules deux à deux et en les décalant de ligne en ligne. Puis tu sélectionnes ta pyramide pour la coller dans ton document.

_________________
"Placez votre main sur un poêle une minute et ça vous semble durer une heure. Asseyez vous auprès d'une jolie fille une heure et ça vous semble durer une minute. C'est ça la relativité. " (Albert Einstein).
ben2510
ben2510
Expert

[Maths] Où trouver un générateur de pyramides additives ? Empty Re: [Maths] Où trouver un générateur de pyramides additives ?

par ben2510 le Ven 15 Mai 2020 - 11:50
Si tu aimes le LaTeX et le Python,
voila une solution avec TikZ.

&textReferences=false]générer le TikZ en Python

[Maths] Où trouver un générateur de pyramides additives ? Pyrami10

Code:
\documentclass[10pt,a4paper]{article}
\usepackage[utf8]{inputenc}
\usepackage{amsmath}
\usepackage{amsfonts}
\usepackage{amssymb}
\usepackage{tikz}
\usepackage[left=2cm,right=2cm,top=2cm,bottom=2cm]{geometry}
\begin{document}
\begin{tikzpicture}
\draw (4,5)--(6,5)--(6,4)--(4,4)--cycle;
\draw (5,4.5) node{$14$};
\draw (3,4)--(5,4)--(5,3)--(3,3)--cycle;
\draw (4,3.5) node{$23$};
\draw (5,4)--(7,4)--(7,3)--(5,3)--cycle;
\draw (6,3.5) node{$25$};
\draw (2,3)--(4,3)--(4,2)--(2,2)--cycle;
\draw (3,2.5) node{$32$};
\draw (4,3)--(6,3)--(6,2)--(4,2)--cycle;
\draw (5,2.5) node{$34$};
\draw (6,3)--(8,3)--(8,2)--(6,2)--cycle;
\draw (7,2.5) node{$36$};
\draw (1,2)--(3,2)--(3,1)--(1,1)--cycle;
\draw (2,1.5) node{$41$};
\draw (3,2)--(5,2)--(5,1)--(3,1)--cycle;
\draw (4,1.5) node{$43$};
\draw (5,2)--(7,2)--(7,1)--(5,1)--cycle;
\draw (6,1.5) node{$45$};
\draw (7,2)--(9,2)--(9,1)--(7,1)--cycle;
\draw (8,1.5) node{$47$};
\draw (0,1)--(2,1)--(2,0)--(0,0)--cycle;
\draw (1,0.5) node{$50$};
\draw (2,1)--(4,1)--(4,0)--(2,0)--cycle;
\draw (3,0.5) node{$52$};
\draw (4,1)--(6,1)--(6,0)--(4,0)--cycle;
\draw (5,0.5) node{$54$};
\draw (6,1)--(8,1)--(8,0)--(6,0)--cycle;
\draw (7,0.5) node{$56$};
\draw (8,1)--(10,1)--(10,0)--(8,0)--cycle;
\draw (9,0.5) node{$58$};
\end{tikzpicture}
\end{document}


_________________
On fait la science avec des faits, comme on fait une maison avec des pierres : mais une accumulation de faits n'est pas plus une science qu'un tas de pierres n'est une maison. Henri Poincaré  La notion d'équation différentielle est le pivot de la conception scientifique du monde. Vladimir Arnold
avatar
Flo44
Habitué du forum

[Maths] Où trouver un générateur de pyramides additives ? Empty Re: [Maths] Où trouver un générateur de pyramides additives ?

par Flo44 le Ven 15 Mai 2020 - 14:29
Merci à vous deux!

Vu que je n'ai pas le temps d'investir dans LaTeX, ce sera la solution basique (tableur). Je m'étais dit que quelqu'un aurait peut-être eu l'idée géniale d'en faire un en ligne, vu qu'on trouve déjà pas mal de choses.


ben2510
ben2510
Expert

[Maths] Où trouver un générateur de pyramides additives ? Empty Re: [Maths] Où trouver un générateur de pyramides additives ?

par ben2510 le Ven 15 Mai 2020 - 15:54
La façon de procéder avec un tableur est simple et efficace !
J'ai proposé du TikZ parce qu'avec le confinement et le travail à distance je deviens un pro du LaTeX (quinze heures par semaine à taper des diapos des polys et des corrigés, forcément...).

_________________
On fait la science avec des faits, comme on fait une maison avec des pierres : mais une accumulation de faits n'est pas plus une science qu'un tas de pierres n'est une maison. Henri Poincaré  La notion d'équation différentielle est le pivot de la conception scientifique du monde. Vladimir Arnold
ycombe
ycombe
Monarque

[Maths] Où trouver un générateur de pyramides additives ? Empty Re: [Maths] Où trouver un générateur de pyramides additives ?

par ycombe le Ven 15 Mai 2020 - 16:33
@ben2510 a écrit:Si tu aimes le LaTeX et le Python,
voila une solution avec TikZ.

[url="http://www.pythontutor.com/visualize.html#code=print%28%22\\begin%7Btikzpicture%7D%22%29%0Afor%20i%20in%20range%281,6%29%3A%0A%20%20%20%20y%3D6-i%0A%20%20%20%20for%20x%20in%20range%285-i,5%2Bi,2%29%3A%0A%20%20%20%20%20%20%20%20print%28%22\\%22%2Bf%22draw%20%28%7Bx%7D,%7By%7D%29--%28%7Bx%2B2%7D,%7By%7D%29--%28%7Bx%2B2%7D,%7By-1%7D%29--%28%7Bx%7D,%7By-1%7D%29--cycle%3B%22%29%0A%20%20%20%20%20%20%20%20print%28%22\\%22%2Bf%22draw%20%28%7Bx%2B1%7D,%7By-1%7D.5%29%20node%22%2B%22%7B%22%2Bf%22%24%7Bi%7D%7Bx%7D%24%22%2B%22%7D%3B%22%29%0Aprint%28%22\\end%7Btikzpicture%7D%22%29&cumulative=false&curInstr=63&heapPrimitives=nevernest&mode=display&origin=opt-frontend.js&py=3&rawInputLstJSON=[]&textReferences=false"]générer le TikZ en Python[/url]

[Maths] Où trouver un générateur de pyramides additives ? Pyrami10

Code:
\documentclass[10pt,a4paper]{article}
\usepackage[utf8]{inputenc}
\usepackage{amsmath}
\usepackage{amsfonts}
\usepackage{amssymb}
\usepackage{tikz}
\usepackage[left=2cm,right=2cm,top=2cm,bottom=2cm]{geometry}
\begin{document}
\begin{tikzpicture}
\draw (4,5)--(6,5)--(6,4)--(4,4)--cycle;
\draw (5,4.5) node{$14$};
\draw (3,4)--(5,4)--(5,3)--(3,3)--cycle;
\draw (4,3.5) node{$23$};
\draw (5,4)--(7,4)--(7,3)--(5,3)--cycle;
\draw (6,3.5) node{$25$};
\draw (2,3)--(4,3)--(4,2)--(2,2)--cycle;
\draw (3,2.5) node{$32$};
\draw (4,3)--(6,3)--(6,2)--(4,2)--cycle;
\draw (5,2.5) node{$34$};
\draw (6,3)--(8,3)--(8,2)--(6,2)--cycle;
\draw (7,2.5) node{$36$};
\draw (1,2)--(3,2)--(3,1)--(1,1)--cycle;
\draw (2,1.5) node{$41$};
\draw (3,2)--(5,2)--(5,1)--(3,1)--cycle;
\draw (4,1.5) node{$43$};
\draw (5,2)--(7,2)--(7,1)--(5,1)--cycle;
\draw (6,1.5) node{$45$};
\draw (7,2)--(9,2)--(9,1)--(7,1)--cycle;
\draw (8,1.5) node{$47$};
\draw (0,1)--(2,1)--(2,0)--(0,0)--cycle;
\draw (1,0.5) node{$50$};
\draw (2,1)--(4,1)--(4,0)--(2,0)--cycle;
\draw (3,0.5) node{$52$};
\draw (4,1)--(6,1)--(6,0)--(4,0)--cycle;
\draw (5,0.5) node{$54$};
\draw (6,1)--(8,1)--(8,0)--(6,0)--cycle;
\draw (7,0.5) node{$56$};
\draw (8,1)--(10,1)--(10,0)--(8,0)--cycle;
\draw (9,0.5) node{$58$};
\end{tikzpicture}
\end{document}








Ton lien déconne à cause des [ et ].

Avec le "embed code' ça passe:


_________________
Assurbanipal: "Passant, mange, bois, divertis-toi ; tout le reste n’est rien".

Franck Ramus : "Les sciences de l'éducation à la française se font fort de produire un discours savant sur l'éducation, mais ce serait visiblement trop leur demander que de mettre leur discours à l'épreuve des faits".
ben2510
ben2510
Expert

[Maths] Où trouver un générateur de pyramides additives ? Empty Re: [Maths] Où trouver un générateur de pyramides additives ?

par ben2510 le Ven 15 Mai 2020 - 17:15
Merci !

_________________
On fait la science avec des faits, comme on fait une maison avec des pierres : mais une accumulation de faits n'est pas plus une science qu'un tas de pierres n'est une maison. Henri Poincaré  La notion d'équation différentielle est le pivot de la conception scientifique du monde. Vladimir Arnold
ycombe
ycombe
Monarque

[Maths] Où trouver un générateur de pyramides additives ? Empty Re: [Maths] Où trouver un générateur de pyramides additives ?

par ycombe le Ven 15 Mai 2020 - 17:29
Accessoirement, tu peux utiliser des r-string pour éviter le double backslash et le combiner avec une f-string et employer le code utf8  pour les accolades à l'intérieur de la f-string:
Code:

print(r"\begin{tikzpicture}")
for i in range(1,6):
    y = 6-i
    for x in range(5-i,5+i,2):
        print( fr"\draw ({x},{y})--({x+2},{y})--({x+2},{y-1})--({x},{y-1})--cycle;")
        print( f"\\draw ({x+1},{y-1}.5) node \u007b ${i}{x}$ \u007d ;")
print(r"\end{tikzpicture}")
(Pas r-string dans l'avant-dernière à cause du code utf8).

_________________
Assurbanipal: "Passant, mange, bois, divertis-toi ; tout le reste n’est rien".

Franck Ramus : "Les sciences de l'éducation à la française se font fort de produire un discours savant sur l'éducation, mais ce serait visiblement trop leur demander que de mettre leur discours à l'épreuve des faits".
ycombe
ycombe
Monarque

[Maths] Où trouver un générateur de pyramides additives ? Empty Re: [Maths] Où trouver un générateur de pyramides additives ?

par ycombe le Ven 15 Mai 2020 - 22:55
Bon, j'ai un peu modifié le code histoire de gagner en souplesse
Code:

def encadre(s):
    s.insert(0, r"\begin{tikzpicture}")
    s.append(r"\end{tikzpicture}")
    return '\n'.join(s)

def generate_box(x, y):
    return [ fr"\draw ({x},{y})--({x+2},{y})--({x+2},{y-1})--({x},{y-1})--cycle;" ]

def generate_node(x,y, no):
    return [ f"\\draw ({x+1},{y-1}.5) node \u007b ${no}{x}$ \u007d ;" ]

def generate_ligne(y, nombre_lignes, no):
    s = []
    for x in range(nombre_lignes-no,nombre_lignes+no,2):
        s += generate_box(x,y) + generate_node(x,y,no)
    return s

def generate_pyramide(nombre_lignes):
    s = []
    for i in range(nombre_lignes):
        y = nombre_lignes - i
        s += generate_ligne(y, nombre_lignes, i+1)
    return encadre(s)

print(generate_pyramide(8))

[Maths] Où trouver un générateur de pyramides additives ? Pyr-se10

_________________
Assurbanipal: "Passant, mange, bois, divertis-toi ; tout le reste n’est rien".

Franck Ramus : "Les sciences de l'éducation à la française se font fort de produire un discours savant sur l'éducation, mais ce serait visiblement trop leur demander que de mettre leur discours à l'épreuve des faits".
ycombe
ycombe
Monarque

[Maths] Où trouver un générateur de pyramides additives ? Empty Re: [Maths] Où trouver un générateur de pyramides additives ?

par ycombe le Sam 16 Mai 2020 - 16:58
Évidemment, le problème suivant est de choisir les n cases (hauteur de la pyramide) qui donnent une solution complète.

Problème résolu sur papier, il faut que je passe au codage. Laissez-moi quelques jours.




_________________
Assurbanipal: "Passant, mange, bois, divertis-toi ; tout le reste n’est rien".

Franck Ramus : "Les sciences de l'éducation à la française se font fort de produire un discours savant sur l'éducation, mais ce serait visiblement trop leur demander que de mettre leur discours à l'épreuve des faits".
ycombe
ycombe
Monarque

[Maths] Où trouver un générateur de pyramides additives ? Empty Re: [Maths] Où trouver un générateur de pyramides additives ?

par ycombe le Jeu 28 Mai 2020 - 15:57
Voilà, plus qu'à intégrer ça avec le générateur de cases en tikz qui est dessus.

La dernière ligne renvoie un dict comme:
{0: 5, 5: 5, 8: 7, 9: 5, 10: 7, 20: 105}
à lire comme numéro de case : valeur

[Maths] Où trouver un générateur de pyramides additives ? Pyrami10

(Cases numérotées en partant de 0 en bas à gauche et en allant toujours de gauche à droite sur les lignes, en remontant.)

Spoiler:

Code:

#!/usr/bin/env python3
# -*- coding: utf-8 -*-
"""
Created on Wed May 27 17:21:12 2020

@author: yves
"""

import numpy as np
import itertools
import random

class Pyramide():
    # stolen in the net (choose)
    #
    
    def nCr(self, n, k):
        """
        A fast way to calculate binomial coefficients by Andrew Dalke (contrib).
        """
        if 0 <= k <= n:
            ntok = 1
            ktok = 1
            for t in range(1, min(k, n - k) + 1):
                ntok *= n
                ktok *= t
                n -= 1
            return ntok // ktok
        else:
            return 0

    def __init__(self, size):
        if size < 4:
            raise ValueError("Pyramide sans intérêt si taille < 5")
        # size
        self.n = size
        # n lines of the matrix
        self.n_lines = self.n*(self.n+1)//2
        # calculation matrix from base line to all values
        self.mat = np.empty((self.n_lines,self.n), dtype='int')
        
        # used only to statistical fonctions
        self.determinants = None

        m_line = 0
        for part in range(self.n,0,-1):
            n_comb = self.n - part
            for line in range(part):
                for case in range(self.n):
                    self.mat[m_line, case] = self.nCr( n_comb, case - line)
                m_line += 1

    def get_random_pyramid(self, difficulty = 2, min=1, max = 9, *, seed = None):
        """
        return a dict { number_of_case : value }
        you can use as puzzle
        """
        if difficulty < 1 or difficulty > 8:
            raise ValueError("difficulty between 1 and 8")
        elif difficulty >  3 and self.n == 4:
            raise ValueError("size too low for difficulty")

        # self.random_cases are cases to fill for the puzzle
        self.random_cases = np.array(self.__choose_random__(difficulty, seed = seed))
        self.random_cases.transpose()

        # choose values for base line
        self.base_solution = np.random.randint(min, max, size=(self.n,1))
        
        # get values for all cases
        self.solution = np.matmul(self.mat, self.base_solution)

        # get index and values for selected cases
        # the visible part of the puzzle
        self.puzzle = { c: self.solution[c,0] for c in self.random_cases }
        
        return self.puzzle

        
    def __choose_random__(self, difficulty = 2, *, seed = None):
        """
        choose at random cases to fill for given difficulty
        """
        lines = list(range(self.n_lines))
        random.seed(seed)
        random.shuffle(lines)
        iter_mat = itertools.combinations(lines, self.n)
        
        det = 0
        for l in iter_mat:
            det =  abs(round(np.linalg.det(self.mat[l,])))
            if det == difficulty:
                return tuple(sorted(l))
        else:
            raise ValueError("This difficulty was not found with that size")
    
    #####
    # statistical only calculations: all determinants
    # for all choices of cases
    # only det !=0 give a possible puzzle
    # abs(determinant) is used as a difficulty level
    #####    
    def __get_determinants__(self):
        """
        list all determinants in self.determinants
        can be long, 9min on my old core i7 for n=8
        """
        lines = list(range(self.n_lines))
        # random.shuffle(lines)
        sel_mat = itertools.combinations(lines, self.n)
        self.determinants =  {}

        for l in sel_mat:
            #l = sorted(l)
            det =  abs(round(np.linalg.det(self.mat[l,])))
            if det in self.determinants:
                self.determinants[det].append(l)
            else:
               self.determinants[det] = [l]
              
    def __nbr_cas__(self):
        return self.nCr(self.n_lines, self.n_lines - self.n)

    def __bilans__(self):
        # can be long
        if not self.determinants:
            self.__get_determinants__()
            
        if 0 in self.determinants:
            n_zeros = len(self.determinants[0])
        else:
            n_zeros = 0
        print(f"{self.__nbr_cas__()} choix possibles dont {n_zeros} impossibles.")
        max_det = max(self.determinants.keys())
        print(f"Déterminant maximal : {max_det}")


p = Pyramide(6)
# bon courage
print(p.get_random_pyramid(5))

_________________
Assurbanipal: "Passant, mange, bois, divertis-toi ; tout le reste n’est rien".

Franck Ramus : "Les sciences de l'éducation à la française se font fort de produire un discours savant sur l'éducation, mais ce serait visiblement trop leur demander que de mettre leur discours à l'épreuve des faits".
ycombe
ycombe
Monarque

[Maths] Où trouver un générateur de pyramides additives ? Empty Re: [Maths] Où trouver un générateur de pyramides additives ?

par ycombe le Jeu 28 Mai 2020 - 19:18
Quelques stats avant que je termine le code (j'ai sorti R): que se passe-t-il si on veut vérifier toutes les possibilités pour choisir les n cases ?

On remarque bien l'explosion du nombre de cas à partir de n=7 et surtout 8, avec presque 1,2 millions de choix possibles pour n=7 et plus de trente millions pour n=8. Le temps de calcul va avec, long pour n=7 (22 secondes), insupportable pour n=8 (9 min).

Notez que c'est juste lorsque je fais calculer tous les cas. Pour générer juste une pyramide de la difficulté demandé, on va générer les matrices une par une jusqu'à ce qu'on obtienne le bon déterminant. C'est beaucoup plus rapide, même avec n=10 c'est quasi instantané.




[Maths] Où trouver un générateur de pyramides additives ? Rplot010

[Maths] Où trouver un générateur de pyramides additives ? Rplot011

[Maths] Où trouver un générateur de pyramides additives ? Rplot012

[Maths] Où trouver un générateur de pyramides additives ? Rplot013

[Maths] Où trouver un générateur de pyramides additives ? Rplot014

_________________
Assurbanipal: "Passant, mange, bois, divertis-toi ; tout le reste n’est rien".

Franck Ramus : "Les sciences de l'éducation à la française se font fort de produire un discours savant sur l'éducation, mais ce serait visiblement trop leur demander que de mettre leur discours à l'épreuve des faits".
ben2510
ben2510
Expert

[Maths] Où trouver un générateur de pyramides additives ? Empty Re: [Maths] Où trouver un générateur de pyramides additives ?

par ben2510 le Jeu 28 Mai 2020 - 23:23
Beau boulot ! Il n'y a plus qu'à tout réécrire en javascript pour mettre ça dans une page ouèbe. professeur

_________________
On fait la science avec des faits, comme on fait une maison avec des pierres : mais une accumulation de faits n'est pas plus une science qu'un tas de pierres n'est une maison. Henri Poincaré  La notion d'équation différentielle est le pivot de la conception scientifique du monde. Vladimir Arnold
ycombe
ycombe
Monarque

[Maths] Où trouver un générateur de pyramides additives ? Empty Re: [Maths] Où trouver un générateur de pyramides additives ?

par ycombe le Ven 29 Mai 2020 - 0:58
Attends, j'avais pas fini:

[Maths] Où trouver un générateur de pyramides additives ? Pyr-se12

Plus qu'à ajouter la gestion des arguments en ligne de commande pour la taille, la difficulté, la sortie des solutions ou pas et on sera pas mal.

Spoiler:

Code:

#!/usr/bin/env python3
# -*- coding: utf-8 -*-
"""
Created on Wed May 27 17:21:12 2020

@author: yves
"""

import numpy as np
import itertools
import random

class PyramidePrinterTikz():
    def __init__(self, pyramide):
        self.size = pyramide.n
        self.n_values = pyramide.n_lines
        self.puzzle = pyramide.puzzle
        self.solution  = pyramide.solution
        self.out = { 'puzzle' : "", 'solution' : "" }
        self.print_solution = False
        
    def print(self, puzzle=True, solution=True, *,filename = None):
        if solution and self.solution is None:
            solution = False
        self.values = []
        

        # on imprime le puzzle même si vide.        
        self.streams = ['puzzle']
        self.streams += [ 'solution' ] if solution else []

        file_mode = "w"
        while self.streams:
            if self.streams[0] == 'puzzle':
                for k in range(self.n_values):
                    self.values.append(self.puzzle[k] if k in self.puzzle else '_')
            elif self.streams[0] == 'solution':  
                self.values = [ int(n) for n in self.solution ]
                # str will be type of puzzle values
                for k in self.puzzle:
                    self.values[k] = str(self.values[k])
            else:
                self.values = None

            self.initialize()
            self.print_pyramide()
            self.finalize()
            
            if filename:
                with open(filename, file_mode) as f:
                    f.write(self.out[self.streams[0]])
                    f.write("\n")
                    file_mode="a"
            else:
                print(self.out[self.streams[0]],"\n")
                
            self.streams.pop(0)
            
    def print_pyramide(self):
        for i in range(self.size):
            y = self.size - i
            self.print_line(y, i+1)

    def print_line(self, y, no):
        for x in range(self.size-no,self.size+no,2):
            self.print_box(x,y)
            self.print_node(x,y)
            
    def print_box(self, x, y):
        self.__add_line_out__(fr"\draw ({x},{y})--({x+2},{y})--({x+2},{y-1})--({x},{y-1})--cycle;")

    def print_node(self, x, y):
        if not self.values:
            return
        value = self.values.pop()
        if value == "_":
            return
        
        # puzzle
        if type(value) is str:
            color="[text=red]"
        else:
            color=""
        self.__add_line_out__(f"\\draw ({x+1},{y-1}.5) node{color} \u007b ${value}$ \u007d ;")
                
        
    def initialize(self):
        self.__add_line_out__(f"%% {self.streams[0]}")
        self.__add_line_out__(r"\begin{tikzpicture}")

    def finalize(self):
        self.__add_line_out__(r"\end{tikzpicture}")
    
    def __add_line_out__(self, line):
        self.out[self.streams[0]] += line + '\n'
        
class Pyramide():
    # stolen in the net (choose)
    #
    
    def nCr(self, n, k):
        """
        A fast way to calculate binomial coefficients by Andrew Dalke (contrib).
        """
        if 0 <= k <= n:
            ntok = 1
            ktok = 1
            for t in range(1, min(k, n - k) + 1):
                ntok *= n
                ktok *= t
                n -= 1
            return ntok // ktok     # // casse la reconnaissance de code du site
        else:
            return 0

    def __init__(self, size):
        if size < 4:
            raise ValueError("Pyramide sans intérêt si taille < 5")
        # size
        self.n = size
        # n lines of the matrix
        self.n_lines = self.n*(self.n+1)//2
        # calculation matrix from base line to all values
        self.mat = np.empty((self.n_lines,self.n), dtype='int')
        
        # used only to statistical fonctions
        self.determinants = None

        m_line = 0
        for part in range(self.n,0,-1):
            n_comb = self.n - part
            for line in range(part):
                for case in range(self.n):
                    self.mat[m_line, case] = self.nCr( n_comb, case - line)
                m_line += 1
                
        self.solution = None
        self.puzzle = {}
        
    def get_size(self):
        return self.n
    
    def get_nbr_cases(self):
        return self.n_lines
    
    

    def get_random_pyramid(self, difficulty = 2, min=1, max = 9, *, seed = None):
        """
        return a dict { number_of_case : value }
        you can use as puzzle
        """
        if difficulty < 1 or difficulty > 8:
            raise ValueError("difficulty between 1 and 8")
        elif difficulty >  3 and self.n == 4:
            raise ValueError("size too low for difficulty")

        # self.random_cases are cases to fill for the puzzle
        self.random_cases = np.array(self.__choose_random__(difficulty, seed = seed))
        self.random_cases.transpose()

        # choose values for base line
        self.base_solution = np.random.randint(min, max, size=(self.n,1))
        
        # get values for all cases
        self.solution = np.matmul(self.mat, self.base_solution)

        # get index and values for selected cases
        # the visible part of the puzzle
        self.puzzle = { c: int(self.solution[c,0]) for c in self.random_cases }
        
        return self.puzzle

        
    def __choose_random__(self, difficulty = 2, *, seed = None):
        """
        choose at random cases to fill for given difficulty
        """
        lines = list(range(self.n_lines))
        random.seed(seed)
        random.shuffle(lines)
        iter_mat = itertools.combinations(lines, self.n)
        
        det = 0
        for l in iter_mat:
            det =  abs(round(np.linalg.det(self.mat[l,])))
            if det == difficulty:
                return tuple(sorted(l))
        else:
            raise ValueError("This difficulty was not found with that size")
    
    #####
    # statistical only calculations: all determinants
    # for all choices of cases
    # only det !=0 give a possible puzzle
    # abs(determinant) is used as a difficulty level
    #####    
    def __get_determinants__(self):
        """
        list all determinants in self.determinants
        can be long, 9min on my old core i7 for n=8
        """
        lines = list(range(self.n_lines))
        # random.shuffle(lines)
        sel_mat = itertools.combinations(lines, self.n)
        self.determinants =  {}

        for l in sel_mat:
            #l = sorted(l)
            det =  abs(round(np.linalg.det(self.mat[l,])))
            if det in self.determinants:
                self.determinants[det].append(l)
            else:
               self.determinants[det] = [l]
              
    def __nbr_cas__(self):
        return self.nCr(self.n_lines, self.n_lines - self.n)

    def __bilans__(self):
        # can be long
        if not self.determinants:
            self.__get_determinants__()
            
        if 0 in self.determinants:
            n_zeros = len(self.determinants[0])
        else:
            n_zeros = 0
        print(f"{self.__nbr_cas__()} choix possibles dont {n_zeros} impossibles.")
        max_det = max(self.determinants.keys())
        print(f"Déterminant maximal : {max_det}")


p = Pyramide(6)
p.get_random_pyramid(5)
# bon courage
pr = PyramidePrinterTikz(p)
pr.print(filename='out6')


_________________
Assurbanipal: "Passant, mange, bois, divertis-toi ; tout le reste n’est rien".

Franck Ramus : "Les sciences de l'éducation à la française se font fort de produire un discours savant sur l'éducation, mais ce serait visiblement trop leur demander que de mettre leur discours à l'épreuve des faits".
ycombe
ycombe
Monarque

[Maths] Où trouver un générateur de pyramides additives ? Empty Re: [Maths] Où trouver un générateur de pyramides additives ?

par ycombe le Ven 29 Mai 2020 - 1:15
Celle-ci devrait être un peu plus facile (difficulté 2):
[Maths] Où trouver un générateur de pyramides additives ? Pyr-se14

Spoiler:

[Maths] Où trouver un générateur de pyramides additives ? Pyr-se13

_________________
Assurbanipal: "Passant, mange, bois, divertis-toi ; tout le reste n’est rien".

Franck Ramus : "Les sciences de l'éducation à la française se font fort de produire un discours savant sur l'éducation, mais ce serait visiblement trop leur demander que de mettre leur discours à l'épreuve des faits".
ycombe
ycombe
Monarque

[Maths] Où trouver un générateur de pyramides additives ? Empty Re: [Maths] Où trouver un générateur de pyramides additives ?

par ycombe le Ven 29 Mai 2020 - 1:27
@ben2510 a écrit:Beau boulot ! Il n'y a plus qu'à tout réécrire en javascript pour mettre ça dans une page ouèbe. professeur
Facile: il n'y a qu'à écrire une classe PyramidePrinterXHTMLStrict qui fait ça.

D'ailleurs, il faut reprendre ce code: une classe PyramidePrinter qui fait tous les calculs et reprend printer, et les sous classes TIKZ/HTML/etc... qui gèrent les parties dessin.

(Ça va faire un bel exercice pour des MPI, non? algèbre linéaire, numpy, programmation objet...):

_________________
Assurbanipal: "Passant, mange, bois, divertis-toi ; tout le reste n’est rien".

Franck Ramus : "Les sciences de l'éducation à la française se font fort de produire un discours savant sur l'éducation, mais ce serait visiblement trop leur demander que de mettre leur discours à l'épreuve des faits".
ycombe
ycombe
Monarque

[Maths] Où trouver un générateur de pyramides additives ? Empty Re: [Maths] Où trouver un générateur de pyramides additives ?

par ycombe le Ven 29 Mai 2020 - 14:36
[Maths] Où trouver un générateur de pyramides additives ? Pyr-se16

Spoiler:
[Maths] Où trouver un générateur de pyramides additives ? Pyr-se15

Ça avance tranquille. J'ai inclus argparse pour lancer en ligne de commande. Les images ci-dessus viennent d'un pdf découpé par gimp, pdf créé à partir du fichier généré par:
Code:

./pyramide.py -s 8 -d 1 -f out8 -l "\\bigskip\n" -m -5 -M 5

Les options étant:
Code:

usage: pyramide.py [-h] [-s SIZE] [-d {1,2,3,4,5}] [-m MIN] [-M MAX] [-S SEED]
                   [-f FILENAME] [-t LATEX_SEPARATOR]

optional arguments:
  -h, --help            show this help message and exit
  -s SIZE, --size SIZE  Piramid size (4 or more)
  -d {1,2,3,4,5}, --difficulty {1,2,3,4,5}
                        difficlty level (max 3 if size is 4)
  -m MIN, --min MIN     minimum number in base
  -M MAX, --max MAX     maximum number in base
  -S SEED, --seed SEED  Seed number for random generator
  -f FILENAME, --filename FILENAME
                        output file
  -t LATEX_SEPARATOR, --latex-separator LATEX_SEPARATOR
                        separator latex code betwwen puzzle and solution



Vous voulez vraiment voir les 308 lignes de code ?:

Ça va finir coupé en petits morceaux comme module pour pip, je sens. Pas encore fait ça, ça me fera une expérience.
Code:

#!/usr/bin/env python3
# -*- coding: utf-8 -*-
"""
Created on Wed May 27 17:21:12 2020

@author: yves
"""

import numpy as np
import itertools
import random
import argparse
import sys

class PyramidePrinter():
    def __init__(self, pyramide):
        self.size = pyramide.n
        self.n_values = pyramide.n_lines
        self.puzzle = pyramide.puzzle
        self.solution  = pyramide.solution

    def print(self, puzzle=True, solution=True, **kwargs):
        if solution and self.solution is None:
            solution = False
        self.values = []
        
        # on imprime le puzzle même si vide.        
        self.streams = ['puzzle']
        self.streams += [ 'solution' ] if solution else []

        self.initialize_printer(**kwargs)
        
        for stream in self.streams:
            if stream == 'puzzle':
                for k in range(self.n_values):
                    self.values.append(self.puzzle[k] if k in self.puzzle else '_')
            elif stream == 'solution':  
                self.values = [ int(n) for n in self.solution ]
                # str will be type of puzzle values
                for k in self.puzzle:
                    self.values[k] = str(self.values[k])
            else:
                self.values = None

            #print("Values: ", self.values)
            self.initialize_pyramide(stream)
            self.print_pyramide()
            self.finalize_pyramide()
                
        self.finalize_printer()

        def initialize_printer(self, **kwargs):
            """
            Initialisation code for the printer object
            **kwargs are passer from self.printer
            Implement in subclass
            """
            raise NotImplementedError("Don't use directly this class !")
            
        def finalize_printer(self):
            """
            finalization code for the printer object
            **kwargs are passer from self.printer
            Implement in subclass
            """
            raise NotImplementedError("Don't use directly this class !")
            
        def initialize_pyrammide(self, stream):
            """
            initialisation code for each pyramide to print
            stream is 'puzzle' or 'solution'
            """
            raise NotImplementedError("Don't use directly this class !")

        def print_pyramide(self):
            """
            Implement in the subclass
            self.values as values to print, or '_'
            self.size as size of the pyramide
            self.current_stream is 'puzzle' or 'solution'
            """
            raise NotImplementedError("Don't use directly this class !")
          
        def finalize_pyramide(self):
            """
            finalisation code for each pyramide to print
            """
            raise NotImplementedError("Don't use directly this class !")
        
class PyramidePrinterTikz(PyramidePrinter):
    def __init__(self, pyramide):
        super().__init__(pyramide)

    def  initialize_printer(self, **kwargs):
        self.current_stream = None
        self.filename = kwargs.get('filename', None)
        self.sep = kwargs.get('separator', "")
        self.out = {}
        for stream in self.streams:
            self.out[stream] = ""
            
    def finalize_printer(self):
        with self.filename as f:
            for stream in self.streams:
                f.write(self.out[stream])
                f.write("\n")

    def initialize_pyramide(self,stream):
        #add a seperator before each pyramide but first
        if self.current_stream:
            self.__add_line_out__(self.sep)
        self.current_stream = stream
        self.__add_line_out__(f"%% {stream}")
        self.__add_line_out__(r"\begin{tikzpicture}")

    def finalize_pyramide(self):
        self.__add_line_out__(r"\end{tikzpicture}")
    
    def print_pyramide(self):
        for i in range(self.size):
            y = self.size - i
            self.__print_line__(y, i+1)

    def __add_line_out__(self, line):
        if line:
            self.out[self.current_stream] += line + '\n'

    def __print_line__(self, y, no):
        for x in range(self.size-no,self.size+no,2):
            self.__print_box__(x,y)
            self.__print_node__(x,y)
            
    def __print_box__(self, x, y):
        self.__add_line_out__(fr"\draw ({x},{y})--({x+2},{y})--({x+2},{y-1})--({x},{y-1})--cycle;")

    def __print_node__(self, x, y):
        if not self.values:
            return
        value = self.values.pop()
        if value == "_":
            return
        
        # puzzle
        if type(value) is str:
            color="[text=red]"
        else:
            color=""
        self.__add_line_out__(f"\\draw ({x+1},{y-1}.5) node{color} \u007b ${value}$ \u007d ;")
        
class Pyramide():
    # stolen in the net (choose)
    #
    
    def nCr(self, n, k):
        """
        A fast way to calculate binomial coefficients by Andrew Dalke (contrib).
        """
        if 0 <= k <= n:
            ntok = 1
            ktok = 1
            for t in range(1, min(k, n - k) + 1):
                ntok *= n
                ktok *= t
                n -= 1
            return ntok // ktok
        else:
            return 0

    def __init__(self, size):
        if size < 4:
            raise ValueError("Pyramid Size at least 4")
        # size
        self.n = size
        # n lines of the matrix
        self.n_lines = self.n*(self.n+1)//2
        # calculation matrix from base line to all values
        self.mat = np.empty((self.n_lines,self.n), dtype='int')
        
        # used only to statistical fonctions
        self.determinants = None

        m_line = 0
        for part in range(self.n,0,-1):
            n_comb = self.n - part
            for line in range(part):
                for case in range(self.n):
                    self.mat[m_line, case] = self.nCr( n_comb, case - line)
                m_line += 1
                
        self.solution = None
        self.puzzle = {}
        
    def get_size(self):
        return self.n
    
    def get_nbr_cases(self):
        return self.n_lines
    
    

    def get_random_pyramid(self, difficulty = 2, min=1, max = 9, *, seed = None):
        """
        return a dict { number_of_case : value }
        you can use as puzzle
        """
        if difficulty < 1 or difficulty > 8:
            raise ValueError("difficulty between 1 and 8")
        elif difficulty >  3 and self.n == 4:
            raise ValueError("size too low for difficulty")

        # self.random_cases are cases to fill for the puzzle
        self.random_cases = np.array(self.__choose_random__(difficulty, seed = seed))
        self.random_cases.transpose()

        # choose values for base line
        self.base_solution = np.random.randint(min, max+1, size=(self.n,1))
        
        # get values for all cases
        self.solution = np.matmul(self.mat, self.base_solution)

        # get index and values for selected cases
        # the visible part of the puzzle
        self.puzzle = { c: int(self.solution[c,0]) for c in self.random_cases }
        
        return self.puzzle

        
    def __choose_random__(self, difficulty = 2, *, seed = None):
        """
        choose at random cases to fill for given difficulty
        """
        lines = list(range(self.n_lines))
        random.seed(seed)
        random.shuffle(lines)
        iter_mat = itertools.combinations(lines, self.n)
        
        det = 0
        for l in iter_mat:
            det =  abs(round(np.linalg.det(self.mat[l,])))
            if det == difficulty:
                return tuple(sorted(l))
        else:
            raise ValueError("This difficulty was not found with that size")
    
    #####
    # statistical only calculations: all determinants
    # for all choices of cases
    # only det !=0 give a possible puzzle
    # abs(determinant) is used as a difficulty level
    #####    
    def __get_determinants__(self):
        """
        list all determinants in self.determinants
        can be long, 9min on my old core i7 for n=8
        """
        lines = list(range(self.n_lines))
        # random.shuffle(lines)
        sel_mat = itertools.combinations(lines, self.n)
        self.determinants =  {}

        for l in sel_mat:
            #l = sorted(l)
            det =  abs(round(np.linalg.det(self.mat[l,])))
            if det in self.determinants:
                self.determinants[det].append(l)
            else:
               self.determinants[det] = [l]
              
    def __nbr_cas__(self):
        return self.nCr(self.n_lines, self.n_lines - self.n)

    def __bilans__(self):
        # can be long
        if not self.determinants:
            self.__get_determinants__()
            
        if 0 in self.determinants:
            n_zeros = len(self.determinants[0])
        else:
            n_zeros = 0
        print(f"{self.__nbr_cas__()} choix possibles dont {n_zeros} impossibles.")
        max_det = max(self.determinants.keys())
        print(f"Déterminant maximal : {max_det}")

if __name__ == '__main__':
    parser = argparse.ArgumentParser()
    parser.add_argument("-s", "--size", type=int, default=5,
                    help="Piramid size (4 or more)")
    parser.add_argument("-d", "--difficulty", type=int, choices=range(1,6), default=2,
                    help="difficlty level (max 3 if size is 4)")
    parser.add_argument("-m", "--min", type=int, default=0,
                    help="minimum number in base")    
    parser.add_argument("-M", "--max", type=int, default=9,
                    help="maximum number in base")    
    parser.add_argument("-S", "--seed", type=int,
                    help="Seed number for random generator")
    parser.add_argument("-f", "--filename", type=argparse.FileType('w'), default=sys.stdout,
                    help="output file")
    parser.add_argument("-l", "--latex-separator", type=str, default="",
                    help="separator latex code betwwen puzzle and solution")
    
    args = parser.parse_args()
    
    p = Pyramide(args.size)
    p.get_random_pyramid(args.difficulty,args.min, args.max, seed=args.seed)
    # bon courage
    pr = PyramidePrinterTikz(p)
    pr.print(filename=args.filename, separator=args.latex_separator)

_________________
Assurbanipal: "Passant, mange, bois, divertis-toi ; tout le reste n’est rien".

Franck Ramus : "Les sciences de l'éducation à la française se font fort de produire un discours savant sur l'éducation, mais ce serait visiblement trop leur demander que de mettre leur discours à l'épreuve des faits".
ycombe
ycombe
Monarque

[Maths] Où trouver un générateur de pyramides additives ? Empty Re: [Maths] Où trouver un générateur de pyramides additives ?

par ycombe le Ven 29 Mai 2020 - 15:15
Taille 10 min -5 max 5 difficulté 2. Résolu à la main pour vérifier le niveau de difficulté. Ça va, c'est faisable sans trop de problème.
Code:

./pyramide.py -f out9 -s 10 -d 2 -l '\pagebreak' -m -5 -M 5
(J'ai mis la page en paysage, ça ne rentrait pas sinon).

[Maths] Où trouver un générateur de pyramides additives ? Pyr-0-10

Spoiler:

[Maths] Où trouver un générateur de pyramides additives ? Pyr-2-10

_________________
Assurbanipal: "Passant, mange, bois, divertis-toi ; tout le reste n’est rien".

Franck Ramus : "Les sciences de l'éducation à la française se font fort de produire un discours savant sur l'éducation, mais ce serait visiblement trop leur demander que de mettre leur discours à l'épreuve des faits".
ycombe
ycombe
Monarque

[Maths] Où trouver un générateur de pyramides additives ? Empty Re: [Maths] Où trouver un générateur de pyramides additives ?

par ycombe le Sam 30 Mai 2020 - 10:43
Bon, j'ai commencé le nettoyage et la mise en propre pour inclusion dans PyPI.

Il manque encore un peu de doc.
https://framagit.org/ycombe/saqqarah

Il faut encore que je:
- remplace les initialize/finalize par des context managers.
- fasse une page de documentation

Une fois que ça sera fait, je le mets sur PyPI. Après je fais un printer qui crée directement une image avec PIL.

Je voulais l'appeler Imhotep, normal pour un générateur de pyramides. Mais c'était déjà pris. Alors j'ai mis Saqqarah comme nom.


_________________
Assurbanipal: "Passant, mange, bois, divertis-toi ; tout le reste n’est rien".

Franck Ramus : "Les sciences de l'éducation à la française se font fort de produire un discours savant sur l'éducation, mais ce serait visiblement trop leur demander que de mettre leur discours à l'épreuve des faits".
ben2510
ben2510
Expert

[Maths] Où trouver un générateur de pyramides additives ? Empty Re: [Maths] Où trouver un générateur de pyramides additives ?

par ben2510 le Sam 30 Mai 2020 - 13:23
veneration veneration veneration
Balèze, Ô Grand Scribe

_________________
On fait la science avec des faits, comme on fait une maison avec des pierres : mais une accumulation de faits n'est pas plus une science qu'un tas de pierres n'est une maison. Henri Poincaré  La notion d'équation différentielle est le pivot de la conception scientifique du monde. Vladimir Arnold
ycombe
ycombe
Monarque

[Maths] Où trouver un générateur de pyramides additives ? Empty Re: [Maths] Où trouver un générateur de pyramides additives ?

par ycombe le Lun 1 Juin 2020 - 3:03
Ça y est. J'ai ajouté une sortie sous forme d'image, sans passer par LaTeX.
[Maths] Où trouver un générateur de pyramides additives ? Pyrami11

Spoiler:

[Maths] Où trouver un générateur de pyramides additives ? Pyrami12

Demain, j'ajoute de la doc et j'essaie de la mettre dans PyPI pour le rendre facile à utiliser.

_________________
Assurbanipal: "Passant, mange, bois, divertis-toi ; tout le reste n’est rien".

Franck Ramus : "Les sciences de l'éducation à la française se font fort de produire un discours savant sur l'éducation, mais ce serait visiblement trop leur demander que de mettre leur discours à l'épreuve des faits".
ycombe
ycombe
Monarque

[Maths] Où trouver un générateur de pyramides additives ? Empty Re: [Maths] Où trouver un générateur de pyramides additives ?

par ycombe le Lun 1 Juin 2020 - 23:40
C'est fait: https://pypi.org/project/saqqarah/

Un simple
Code:
pip install saqqarah
devrait vous permettre de l'essayer. Si vous avez python3.6.

J'ai mis python >= 3.6 mais je ne suis pas sûr de tout que ça marche avec autre chose que python3.7. Il faut que je vérifie.

Edit: si ça trouve, ça marche avec python3.4... Non, il y a des f-strings donc python >= 3.6


Edit: : le mode image ne marche pas: il manque un ttf. Corrigé.

_________________
Assurbanipal: "Passant, mange, bois, divertis-toi ; tout le reste n’est rien".

Franck Ramus : "Les sciences de l'éducation à la française se font fort de produire un discours savant sur l'éducation, mais ce serait visiblement trop leur demander que de mettre leur discours à l'épreuve des faits".
ycombe
ycombe
Monarque

[Maths] Où trouver un générateur de pyramides additives ? Empty Re: [Maths] Où trouver un générateur de pyramides additives ?

par ycombe le Jeu 4 Juin 2020 - 8:33
Allez, je suis lancé, j'ajoute un clickodrome pour les allergiques à la ligne de commande.

[Maths] Où trouver un générateur de pyramides additives ? Screen10

(Il n'est pas encore fini)


_________________
Assurbanipal: "Passant, mange, bois, divertis-toi ; tout le reste n’est rien".

Franck Ramus : "Les sciences de l'éducation à la française se font fort de produire un discours savant sur l'éducation, mais ce serait visiblement trop leur demander que de mettre leur discours à l'épreuve des faits".
ben2510
ben2510
Expert

[Maths] Où trouver un générateur de pyramides additives ? Empty Re: [Maths] Où trouver un générateur de pyramides additives ?

par ben2510 le Jeu 4 Juin 2020 - 13:19
Voila un exemple nettement plus simple que le précédent. Pas besoin d'écrire un algorithme de descente de gradient cette fois-ci.

_________________
On fait la science avec des faits, comme on fait une maison avec des pierres : mais une accumulation de faits n'est pas plus une science qu'un tas de pierres n'est une maison. Henri Poincaré  La notion d'équation différentielle est le pivot de la conception scientifique du monde. Vladimir Arnold
ycombe
ycombe
Monarque

[Maths] Où trouver un générateur de pyramides additives ? Empty Re: [Maths] Où trouver un générateur de pyramides additives ?

par ycombe le Jeu 4 Juin 2020 - 18:58
@ben2510 a écrit:Voila un exemple nettement plus simple que le précédent. Pas besoin d'écrire un algorithme de descente de gradient cette fois-ci.
Il faut nous montrer ça en détail.

Le logiciel utilise un bête calcul matriciel, lui.

_________________
Assurbanipal: "Passant, mange, bois, divertis-toi ; tout le reste n’est rien".

Franck Ramus : "Les sciences de l'éducation à la française se font fort de produire un discours savant sur l'éducation, mais ce serait visiblement trop leur demander que de mettre leur discours à l'épreuve des faits".
Voir le sujet précédentRevenir en hautVoir le sujet suivant
Permission de ce forum:
Vous ne pouvez pas répondre aux sujets dans ce forum