Petit challenge info

Discutez d'informatique ici !
Avatar de l’utilisateur
fatal_error
Membre Légendaire
Messages: 6610
Enregistré le: 22 Nov 2007, 12:00

Petit challenge info

par fatal_error » 21 Oct 2013, 19:00

hello,

Suite à la discussion ouverte sur le remplacement de chaine n'ayant pas eu trop de réussite, peut-etre trop simple, j'ouvre celle-ci en détaillant un peu plus la discussion.
J'en profite pour monter un peu le niveau!

1) Je n'attends pas que vous fassiez le travail pour moi, je peux m'en sortir moyennant du temps.
2) Mais si le script est bon et validé (au moins pour les cas classiques): il pourrait bien nous être utile, autant qu'il soit lisible et facilement maintenable.
Donc peut-être que Haskell ou autre langages ne sont pas les plus adaptés...
3) Le challenge est le suivant:

Nous utilisons actuellement TEX.
Principalement, des formules TEX que nous utilisons, nous pouvons disserner l'utilisation de :
Code: Tout sélectionner
 \frac{}{}
 _{}
 \cos,\sin,\ln
 ,=>
 \text{}
 *
 

Ce que je vous propose, c'est d'écrire un script qui converti une formule écrite naturellement vers du TEX valide sur ce forum.

Par formule écrite naturellement j'entends:

Code: Tout sélectionner
formule naturelle         =>Script=> formule TEX
--------------------------------------------------------------------------------
3/(2+5)                   =>Script=> \frac{3}{2+5}
3/(2+(3*5-1)/cos(8))      =>Script=> \frac{3}{2+\frac{3 \times 5-1}{\cos(8)}}
(E)2x+5 "Eq d'un plan" =>Script=> (E)\Leftrightarrow 2x+5 \text{Eq d'un plan}
\n                        =>Script=> \


4) Les idées sont importantes, mais au final, c'est le résultat qui compte! Libre à vous de ne pas être en accord avec la translation de formules écrites habituellement vers TEX auquel cas proposez.
Si ce script vous parait trop d'effort pour si peu, passez votre chemin, le but étant
surtout de coder/scripter!

Bonne chance pour ceux que ca intéresse :D

Bonus1) Pour les plus non rassasiés, détecter et convertir les matrices
Code: Tout sélectionner
(1,2,3 ==> \begin{pmatrix}
3,2,4)      1 & 2 & 3  \\
            3 & 2, 4 \end{pmatrix}


Bonus2) Pour les aventuriers, convertir le TEX généré en formule écrite naturellement

A vos cafés :lol3:
la vie est une fête :)



Valentin03
Membre Relatif
Messages: 429
Enregistré le: 23 Déc 2012, 13:08

par Valentin03 » 21 Oct 2013, 22:53

fatal_error a écrit:hello,
Ce que je vous propose, c'est d'écrire un script qui converti une formule écrite naturellement vers du TEX valide sur ce forum.

Houla ! Y va y avoir de la casse !!

Avatar de l’utilisateur
ampholyte
Membre Transcendant
Messages: 3940
Enregistré le: 21 Juil 2012, 07:03

par ampholyte » 22 Oct 2013, 07:54

Bonjour,

Projet fort intéressant. J'essayerais, si j'ai le temps, de le faire. J'ai déjà ma petite idée.

J'essayerais de faire cela en C =).

PS : Pour corser encore un peu plus le niveau, détecter les erreurs d'expressions =)

Exemple :

\frac{3}{5 => script => Erreur de {} ect...

edit : Peut-être que les codes ne seront pas à fournir ici, car trop lourd suivant le langage.

joel76
Membre Relatif
Messages: 230
Enregistré le: 11 Fév 2013, 15:31

par joel76 » 26 Oct 2013, 13:54

Bonjour

Je suis en train de le faire, mais c'est en Prolog, cela pose-t-il problème ?

Avatar de l’utilisateur
fatal_error
Membre Légendaire
Messages: 6610
Enregistré le: 22 Nov 2007, 12:00

par fatal_error » 26 Oct 2013, 18:54

slt Joel,

le langage est libre, prolog ca va, quand on s'attend à parser un langage, on s'attend à gérer des prédicats ;)
la vie est une fête :)

Avatar de l’utilisateur
fatal_error
Membre Légendaire
Messages: 6610
Enregistré le: 22 Nov 2007, 12:00

par fatal_error » 27 Oct 2013, 15:03

hello,

un ptit update, j'ai pas tout implémenté, ni tout checké.
Code: Tout sélectionner





.notParsed{
  color:red;
}
textarea{
  width:500px;
  height:500px;
}
#result{

};













function convertToTex(str, grammar, nf){
  var backOptions={left:str, nodeList:[]};
  grammarParser.doPred(grammar, nf, 'expression', backOptions);
  var node = nf.applyFunc('master', backOptions.nodeList);
  return node.toString()+''+backOptions.left+'';
}
window.onload=function(){
  var nf = grammarParser.NodeFactory();
  nf.register('_funcName',function(name,nodeList, matchedStr){
    return {toString:function(){return '\\'+matchedStr}};
  }).register('sub',function(name,nodeList, matchedStr){
    return {toString:function(){
      return nodeList[0].toString()+'{'+nodeList[1].toString()+'}';}
    };
  }).register('exp',function(name,nodeList, matchedStr){
    return {toString:function(){
      var s=nodeList[1].toString();
      if(s[0] == '(' && s.slice(-1)==')'){
        s=s.substring(1, s.length-1);
      }
      return nodeList[0].toString()+'{'+s+'}';}
    };
  }).register('comment',function(name,nodeList, matchedStr){
    return {toString:function(){
      return '\\text{'+nodeList[1].toString()+'}';}
    };
  }).register('anyConsTextNode',function(name,nodeList, matchedStr){
    return {toString:function(){
      if(nodeList.length==3 && nodeList[2].nodeList.length==2){
        var str=nodeList[0].toString();
        str+='\\frac{'+nodeList[1]+'}';
        str+='{'+nodeList[2].nodeList[1].toString()+'}';
        return str;
      }
      return nodeList.map(function(x){
          return x.toString();
        }).join('');
      }
    };
  }).register('_anyNConsGroup',function(name,nodeList,matchedStr){
    return {
      toString:function(){
        matchedStr=matchedStr.replace(//g,'\\Leftrightarrow ');
        matchedStr=matchedStr.replace(//g,'\\gt ');
        matchedStr=matchedStr.replace(/>=/g,'\\ge ');
        matchedStr=matchedStr.replace(/'+error+'';
      e.preventDefault();
      return false;
    }
  }
}




  expression         +:globalNode                                   ;
  globalNode          :textNode                                     ;
  globalNode          :PContext                                     ;
  textNode           +:anyConsTextNode                              ;
  anyConsTextNode     :_anyNConsGroup,consGroup,anyFrac             ;
  anyConsTextNode     :null                                         ;
  PContext            :_openParenthesis,expression,_closeParenthesis;
  anyFrac             :fracOperator,consGroup                       ;
  anyFrac             :null                                         ;
  consGroup           :consecutive,anySubExp                        ;
  anySubExp           :sub                                          ;
  anySubExp           :exp                                          ;
  anySubExp           :null                                         ;
  sub                 :_subChar,consGroup                           ;
  exp                 :_expChar,consGroup                           ;
  fracOperator        :_anyWs,_fracSign,_anyWs                      ;
  consecutive         :funcNode                                     ;
  consecutive         :_word                                        ;
  consecutive         :PContext                                     ;
  consecutive         :comment                                      ;
  comment             :_doubleQuote,_anyNotDouble,_doubleQuote      ;
  comment             :_simpleQuote,_anyNotSimple,_simpleQuote      ;
  funcNode            :_funcName,PContext                           ;
  funcNode            :_word,PContext                               ;
  _fracSign           :^/                                           ;
  _anyNConsGroup      :^(\s|[^\w()"\'])*                          ;
  _anyWs              :^\s*                                        ;
  _openParenthesis    :^\(                                         ;
  _closeParenthesis   :^\)                                         ;
  _charSequence       :^[^_()]+                                     ;
  _subChar            :^_                                           ;
  _expChar            :^\^                                         ;
  _word               :^[0-9a-zA-Z]+                                ;
  _doubleQuote        :^"                                           ;
  _simpleQuote        :^\'                                          ;
  _anyNotDouble       :^[^"]*                                       ;
  _anyNotSimple       :^[^\']*                                      ;
  _funcName           :^(cos|sin|ln|exp|sqrt)                       ;


 
  cos(3+ln(5*exp(2)/voiture_test))/a_22_21
 
 









./grammarParser.js
var grammarParser=(function(){

function TerminalNode(name,s){
  this.name=name;
  this.s=s;
  this.toString=function(){return this.s;}
}
function Node(name,nodeList){
  this.name=name;
  this.nodeList=nodeList;
  this.toString=function(){
    return this.nodeList.map(function(x){
     return x.toString();
   }).join('');
  }
}
function NodeFactory(name, nodeList){
  var registeredNames={};
  var _that= {
    /*
      func: node applyFunc(nodeList, string)
    */
    register:function(name,func){
      registeredNames[name]=func;
      return _that;
    },
    applyFunc:function(name,nodeList,string){
      if(name in registeredNames){
        return registeredNames[name](name,nodeList,string);
      }
      if(name[0]=='_'){
        return new TerminalNode(name, string);
      }
      return new Node(name,nodeList);
    }
  };
  return _that;
}
var _DBG_offset='';
var _DBG_enabled=false;
function DBG(s){if(_DBG_enabled){console.log(_DBG_offset+s);}}
function DBG_OPEN(s){DBG(s);_DBG_offset+='  ';}
function DBG_CLOSE(s){_DBG_offset=_DBG_offset.slice(0,-2);DBG(s);}
/*
backOptions:{
  left:'string to parse': will contain in output the string which is left
  nodeList:[] the nodes which made it
}
*/
/*
  grammar:
{
'Frac':[
    {oneOrPlus:['whiteSpace','pContext']},
    ['_terminal'],
    null
  ]
,
'_terminal':regex
}
*/
function doPred(grammar, nodeFactory, predName, backOptions){
  var rules=grammar[predName];
DBG('called '+predName+'->'+backOptions.left);
  if(predName[0]=='_'){                                               //terminal
    var res = backOptions.left.match(rules);
DBG('trying '+predName+'|'+rules+'|'+backOptions.left);
    if(res){
      var node=nodeFactory.applyFunc(predName,nodeList,res[0]);
      backOptions.left = backOptions.left.substr(res[0].length);
      backOptions.nodeList.push(node);
DBG('success->'+backOptions.left);
      return true;
    }
    return false;
  }else{
    var nodeList=[];
    for(var i=0;i1;}).forEach(function(line){
    line=line.trim();
    var rule=line.split(':');
    var pred=rule[0].trim();
    var deps=rule[1].replace(/\s*$/,'');
    if(pred.indexOf('+')!=-1){
      pred=pred.replace('+','').trim();
      if(!(pred in grammar)){
        grammar[pred]=[];
      }
      grammar[pred].push({oneOrPlus:deps.split(',')});
    }else{
      if(pred[0]=='_'){
        grammar[pred]=new RegExp(deps);
      }else{
        if(!(pred in grammar)){
          grammar[pred]=[];
        }
        var res=deps.split(',');
        if(res[0]=='null'){
          res=null;
        }
        grammar[pred].push(res);
      }
    }
  });
  var res=checkGrammar(grammar);
  if(res.length){
    console.log('failed to determine');
    console.log(res);
  }
  return grammar;
}
function checkGrammar(grammar){
  var keys=Object.keys(grammar);
  var notFound=[];
  for(var i in grammar){
    var alternatives=grammar[i];
    if(alternatives instanceof Array){
      alternatives.forEach(function(deps){
        if(deps===null){return;}
        if(deps.oneOrPlus){
          deps=deps.oneOrPlus;
        }
        notFound = notFound.concat(deps.filter(function(dep){
          return keys.indexOf(dep)==-1;
        }));
      });
    }
  }
  return notFound;
}

  return {
    doPred:doPred,
    NodeFactory:NodeFactory,
    grammarFromString:grammarFromString
  };
})();
if(typeof(module)!='undefined' && module.parent){
  module.exports=grammarParser;
}


example de résultat:
3/a_22_12_((( --> \frac{3}{a_{22_{12}}}_(((

L'idée, c'est que je me base sur la grammaire suivante:
Code: Tout sélectionner
  expression         +:globalNode                                   ;
  globalNode          :textNode                                     ;
  globalNode          :PContext                                     ;
  textNode           +:anyConsTextNode                              ;
  anyConsTextNode     :_anyNConsGroup,consGroup,anyFrac             ;
  anyConsTextNode     :null                                         ;
  PContext            :_openParenthesis,expression,_closeParenthesis;
  anyFrac             :fracOperator,consGroup                       ;
  anyFrac             :null                                         ;
  consGroup           :consecutive,anySubExp                        ;
  anySubExp           :sub                                          ;
  anySubExp           :exp                                          ;
  anySubExp           :null                                         ;
  sub                 :_subChar,consGroup                           ;
  exp                 :_expChar,consGroup                           ;
  fracOperator        :_anyWs,_fracSign,_anyWs                      ;
  consecutive         :funcNode                                     ;
  consecutive         :_word                                        ;
  consecutive         :PContext                                     ;
  consecutive         :comment                                      ;
  comment             :_doubleQuote,_anyNotDouble,_doubleQuote      ;
  comment             :_simpleQuote,_anyNotSimple,_simpleQuote      ;
  funcNode            :_funcName,PContext                           ;
  funcNode            :_word,PContext                               ;
  _fracSign           :^/                                           ;
  _anyNConsGroup      :^(\s|[^\w()"\'])*                          ;
  _anyWs              :^\s*                                        ;
  _openParenthesis    :^\(                                         ;
  _closeParenthesis   :^\)                                         ;
  _charSequence       :^[^_()]+                                     ;
  _subChar            :^_                                           ;
  _expChar            :^\^                                         ;
  _word               :^[0-9a-zA-Z]+                                ;
  _doubleQuote        :^"                                           ;
  _simpleQuote        :^\'                                          ;
  _anyNotDouble       :^[^"]*                                       ;
  _anyNotSimple       :^[^\']*                                      ;
  _funcName           :^(cos|sin|ln|exp|sqrt)                       ;


qui bien sûr n'est pas complète, certainement pas optimisée, mais qui fait son job (à peu près :D)

edit:maj:
Gerer les fonctions P(blabla) comme une entité: P(3)/5 => \frac{P(3)}{5}
Supporter , , >=
Gerer les exposants (comme les subs): 3^a_22 => 3^{a_{22}}
Gerer les commentaires: P("test") => P(\text{test})
la vie est une fête :)

joel76
Membre Relatif
Messages: 230
Enregistré le: 11 Fév 2013, 15:31

par joel76 » 31 Oct 2013, 22:59

Je ne comprend pas ce que veux dire exactement cette écriture :
expression +:globalNode

Comment la traduirais-tu en BNF ?

Avatar de l’utilisateur
fatal_error
Membre Légendaire
Messages: 6610
Enregistré le: 22 Nov 2007, 12:00

par fatal_error » 01 Nov 2013, 02:23

Code: Tout sélectionner
expression +:globalNode

+ signifie en regex au moins 1.
en bnf qqch du genre
Code: Tout sélectionner
expression:globalNode, subExpression.
subExpression:expression|null.


voici un plugin pour le tester. (testé que sous ff24.0). Si ca marche pas pour vous, tant pis :[
X33 = (N1/Y1 + N1/Y2)/(1 - (1/Y1 + 1/Y2 + 1/Y3))
==>
X_33 = \frac{\frac{N_1}{Y_1} + \frac{N_1}{Y_2}}{1 - (\frac{1}{Y_1} + \frac{1}{Y_2} + \frac{1}{Y_3})}
==>
la vie est une fête :)

joel76
Membre Relatif
Messages: 230
Enregistré le: 11 Fév 2013, 15:31

par joel76 » 01 Nov 2013, 14:11

Pour moi X_33 signifiait X indice 33 et non X indice exposant 3 !

Avatar de l’utilisateur
fatal_error
Membre Légendaire
Messages: 6610
Enregistré le: 22 Nov 2007, 12:00

par fatal_error » 01 Nov 2013, 14:33

oui, et c'est bien le résultat attendu, je me suis rendu compte de l'erreur quand j'ai posté, le temps que j'écrive un script de déploiement...et on se rend déjà compte de mes boulettes :marteau:

la vie est une fête :)

Iroh
Membre Relatif
Messages: 374
Enregistré le: 14 Oct 2008, 19:24

par Iroh » 01 Nov 2013, 14:52

Bonjour, il existe aussi le projet asciimath avec la description de la grammaire utilisée ici (ascii to mathml).

Le projet a également été intégré à MathJax (demo)

Permet de faire des graphes sample

Avatar de l’utilisateur
fatal_error
Membre Légendaire
Messages: 6610
Enregistré le: 22 Nov 2007, 12:00

par fatal_error » 01 Nov 2013, 15:39

slt,

je suis assez déçu par la tournure qu'a pris mathjax...
Ya qq temps, la lib avait l'air prometteuse, mais je cacherais pas que ca m'a semblé bien compliqué pour télécharger une lib qu'on veut pas spécialement grosse. Quand je vois qu'elle contient des appels ajax et tout... ca fait un peu usine à gaz (même si elle converti potentiellement très bien)

En revanche, je découvre ASCIIMathml et je suis assez bluffé par sa capacité à détecter les sections correspondant à des formules de maths.

Je pensais que ca serait super hardu, et ca a pas l'air le cas, il faut que je regarde!
la vie est une fête :)

joel76
Membre Relatif
Messages: 230
Enregistré le: 11 Fév 2013, 15:31

par joel76 » 03 Nov 2013, 18:51

Une petite question X indice 33 est traduit X_33 ou X_{33} ? Il y a les deux versions sur tes posts.

Avatar de l’utilisateur
fatal_error
Membre Légendaire
Messages: 6610
Enregistré le: 22 Nov 2007, 12:00

par fatal_error » 03 Nov 2013, 19:08

le résultat naturellement attendu est bien sur X_{33}.
J'update assez fréquemment lextension à chaque fois que je vois une erreur (et j'en vois beaucoup...)
la vie est une fête :)

joel76
Membre Relatif
Messages: 230
Enregistré le: 11 Fév 2013, 15:31

par joel76 » 04 Nov 2013, 11:08

Bonjour
J' ai une première mouture du code en Prolog. Il n'y a pas de gestion d'erreur comme suggéré par ampholyte.
Le code fonctionne en SWI-Prolog 6.4.1. Il utilise à fond les DCG
Il comporte deux modules, l'un pour l'analyse lexicale de l'expression fournie, l'autre pour l'analyse syntaxique qui produit la version latex de l'expression.
Il n'est testé que pour les expressions fournies par fatal_error.
Code de l'analyse lexicale.
Code: Tout sélectionner
:- module('totex_lexical.pl', [lexical_analysis/2]).

tex_fonction(cos).
tex_fonction(sin).
tex_fonction(ln).
tex_fonction(sqrt).
tex_fonction(exp).
tex_fonction(sub).


lexical_analysis(In, Out) :-
   atom_chars(In, Chars)  ,
   tex_lexical(Chars, Out, []),!.


tex_lexical([]) --> [].
tex_lexical(['\n']) --> [].

tex_lexical([X|T]) -->
   {member(X, ['(', ')', ',', '+', '-', '*', '/', '^', '_', '{', '}']), !},
   [X],
   tex_lexical(T).

tex_lexical(['\\', 'n'|T]) -->
   {!},
   ['\\'],
   tex_lexical(T).

tex_lexical(['\\'|T]) -->
   tex_lexical_litteral(T, ['\\'|U]-U).

tex_lexical([X|T]) -->
   {(char_type(X, alpha); X = '\\'), !},
   tex_lexical_litteral(T, [X|U]-U).

tex_lexical([X|T]) -->
   {char_type(X, digit), !},
   tex_lexical_num(T, [X|U]-U).

tex_lexical(['"' | T]) -->
   tex_lexical_double_quote(T, U-U).

tex_lexical(['\'' | T]) -->
   tex_lexical_single_quote(T, U-U).

tex_lexical([X|T]) -->
   {member(X, ['=','']), !},
   tex_lexical_symbol(T, [X|U]-U).

tex_lexical(['\n'|T]) -->
   ['\\'],
   tex_lexical(T).

tex_lexical([X|T]) -->
   {char_type(X, white), !} ,
   tex_lexical(T).



tex_lexical_symbol([X|T], Symbol) -->
   {member(X, ['=','']), !,
   append_dl(Symbol, [X|U]-U, Symbol1)},
   tex_lexical_symbol(T, Symbol1).

tex_lexical_symbol(X, Symbol) -->
   {Symbol = V-[],
   atom_chars(Atom, V) },
   [Atom],
   tex_lexical(X)   .


tex_lexical_num([X | T], Digit) -->
   {char_type(X, digit), !,
   append_dl(Digit, [X|U]-U, Digit1)},
   tex_lexical_num(T, Digit1).

tex_lexical_num(X, Digit) -->
   {Digit = V-[],
   atom_chars(Atom, V) },
   [number(Atom)],
   tex_lexical(X)   .


tex_lexical_litteral([X | T], Litteral) -->
   {char_type(X, alpha), !,
   append_dl(Litteral, [X|U]-U, Litteral1)},
   tex_lexical_litteral(T, Litteral1).


tex_lexical_litteral([X | T], Litteral) -->
   {char_type(X, digit), !,
    Litteral = V - [],
    atom_chars(Atom, V),
    check_litteral(Atom, Out)},
   [Out, '_'],
   tex_lexical_num(T, [X|U]-U).

tex_lexical_litteral(['\'' | T], Litteral) -->
   { !,
     append_dl(Litteral, [''''|U]-U, V1),
    V1 = V - [],
    atom_chars(Out, V)},
   [litteral(Out)],
   tex_lexical(T).


tex_lexical_litteral(X, Litteral ) -->
   {Litteral = V - [],
   atom_chars(Atom, V),
   check_litteral(Atom, Out)},
   [Out],
   tex_lexical(X).

tex_lexical_double_quote(['"' |T], Text) -->
   { !,
     Text = V - [],
     atom_chars(Atom, V)},
   [texte(Atom)],
   tex_lexical(T).

tex_lexical_double_quote([X | T], Text) -->
   {append_dl(Text, [X|U]-U, Text1)},
   tex_lexical_double_quote(T, Text1).

tex_lexical_single_quote(['\'' |T], Text) -->
   { !,
     Text = V - [],
     atom_chars(Atom, V)},
   [texte(Atom)],
   tex_lexical(T).

tex_lexical_single_quote([X | T], Text) -->
   {append_dl(Text, [X|U]-U, Text1)},
   tex_lexical_single_quote(T, Text1).

check_litteral(Atom, Atom) :-
   tex_fonction(Atom), !.

check_litteral(Atom, litteral(Atom)).

% concaténation de chaines (sous forme de difference de listes)  en O(1)
append_dl(X-Y, Y-Z, X-Z).

L'analyse syntaxique
Code: Tout sélectionner
:- module('totex_syntaxique.pl', [to_tex/3]).

to_tex(Out)--> global(O), {flatten(O, Out), !}.

% une sequence peux etre consituée d'expressions
% liées par des opérateurs logiques
global(Out) --> expr(O1), reste_global(O2),
   {append(O1, O2, O),
    flatten(O, Out)}.

reste_global(Out) --> oplogique(Op), global(O),
   {flatten([Op, O], Out)}.

reste_global([]) --> [].

% une expression est constituée de termes
% liées par des opérateurs additifs
expr(Out) --> terme(O1), reste_expr(O2),
   {append(O1, O2, O),
   flatten(O, Out)}.

reste_expr(Out) --> opadd(Op) , expr(O2),
   {flatten([Op, O2], Out)}.

reste_expr([]) --> [].


% un terme est constitué de facteurs
% liés par des opérateurs multiplicatifs
terme(Out) -->
   facteur(O1), reste_terme(O2),
   {create_facteur(O1, O2, Out)}.

reste_terme([Op , O]) -->
   opmult(Op), facteur(O1), reste_terme(O2),
   {create_facteur(O1, O2, O)}.


reste_terme([]) --> [].


% un facteur peut être formés de "termes simples"
% liés par les opérateurs d'exponentiation ou d'indices
facteur(Out) -->
   simple(O1), reste_facteur(O2),
   {append(O1, O2, O3),
    flatten(O3, Out)}.

% un facteur peut être une matrice
facteur(Out) --> matrice(Out).

reste_facteur(Out) --> opexp_sub(Op), facteur(O),
   {clean_expr(O, O1),
   append([Op, '{' | O1], ['}'],O2),
   flatten(O2, Out)}   .

reste_facteur([]) --> [].


% un terme simple est une "unité" suivi d'un commentaire
simple(Out) --> unite(O1), commentaire(O2),
   {append(O1, O2, O),
    flatten(O, Out)}.

% une unite peut être une expression
unite(Out) --> ['('], expr(O), [')'],
   {clean_expr(O, O1),
    flatten(['(', O1, ')'], Out)}.

unite(Out) --> ['{'], global(O), ['}'],
   {clean_expr(O, O1),
    flatten(['{', O1, '}'], Out)}.


% une unite peut être une fonction
unite(Out) --> fonction(Fonc), [X], expr(O1), [Y],
   {member([X, Y], [['(', ')'], ['{', '}']]),
    clean_expr(O1, O11),
     append([Fonc, X | O11], [Y], O),
    flatten(O, Out)}.

unite(Out) --> litteral_indice(Fonc), ['('], expr(O1), [')'],
   {clean_expr(O1, O11),
    append([Fonc, '(' | O11], [')'], O),
    flatten(O, Out)}.


unite(Out) --> litteral_indice(Fonc), ['{'], global(O1), ['}'],
   {clean_expr(O1, O11),
    append([Fonc, '{' | O11], ['}'], O),
    flatten(O, Out)}.


% une unite peut être un nombre
unite(Out) -->   number(Out).

% une unite peut être une sequence de lettres
unite(Out) -->   litteral(Out).

% une unite peut être un texte
unite(Out) -->   texte(Out).


litteral_indice(Out) --> litteral(O1), reste_litteral_indice(O2),
   {append(O1, O2, O),
    flatten(O, Out)}.

reste_litteral_indice(Out) --> opsub(Op), facteur(O2),
   {clean_expr(O2, O22),
    append([Op, '{', O22], ['}'], O),
    flatten(O, Out)}.

reste_litteral_indice([]) --> [].



% un commentaire peut être une sequence de lettre
commentaire([Out]) --> litteral(Out).
commentaire([Out]) --> texte(Out).
commentaire([]) --> [].


% gestion des matrices
matrice(Out) -->
   ['('], expr(O1), [','], expr(O2), reste_matrice(O3), [')'],
   {append([' \\begin{pmatrix}', O1, ' & ', O2], O3, O),
    flatten(O, Out)}.

reste_matrice(Out) -->
   [','],
   expr(O1),
   reste_matrice(O2),
   {append([' & ', O1], O2, O),
   flatten(O, Out)}.

reste_matrice(Out) -->
   ['\\'],
   expr(O1),
   reste_matrice(O2),
   {append(['\\\\\n', O1], O2, O),
   flatten(O, Out)}.

reste_matrice([' \\end{pmatrix} ']) --> [].



% definition des différents types d'opérateurs
%
% % les opeateur logiques de connexion d'expressions
oplogique(' = ') --> ['='].
oplogique(' \\Rightarrow ') --> ['=>'].
oplogique(' \\Leftrightarrow ') --> [''].
oplogique(' \\le ') --> [' ['>='].
oplogique(' \\lt ') --> [' ['>'].
oplogique('\\\\') --> ['\\'].

% les opérateurs "additifs" de connexion de termes
opadd(' + ') --> ['+'].
opadd(' - ') --> ['-'].

% les opérateurs "multiplicatifs" de connexion de facteurs
opmult('\\times') --> ['*'].
opmult('\\frac') --> ['/'].

% les opérateurs "exposant/indices" de connexion de composants
% de facteurs
opexp_sub('^') --> [exp].
opexp_sub('^') --> ['^'].
opexp_sub(Op)  --> opsub(Op).


opsub('_') --> ['sub'].
opsub('_') --> ['_'].

% les noms des fonctions
fonction('\\cos') --> [cos].
fonction('\\sin') --> [sin].
fonction('\\ln') --> [ln].
fonction('\\sqrt') --> [sqrt].

number([V]) --> [number(V)].
litteral([L]) --> [litteral(L)].
texte([Out]) --> [texte(T)],
   {format(atom(Out), ' \\text{~w} ', [T])}.

% creation des facteurs
% la multiplication a * b ==> a \times b
create_facteur(O1, ['\\times', O2], Out) :-
   append( O1, [' \\times ' | O2], O),
   flatten(O, Out).

% la division  a / b ==> \frac {a] {b]
create_facteur(O1, ['\\frac', O2], Out) :-
   clean_expr(O1, O11),
   clean_expr(O2, O22),

   append(['\\frac{' | O11], ['}'], O3),
   append(['{' | O22], ['}'], O4),
   append(O3, O4, O),
   flatten(O, Out).

% cas paticulier
create_facteur(O, [], Out) :-
   flatten(O, Out).


clean_expr(In, Out) :-
   (   append(['(' | Out], [')'], In);   append(['{' | Out], ['}'], In)), !.

clean_expr(In, In).

Pour l'exécution effective du programme, j'ai un fichier d'entrée contenant les expressions à convertir et j'écris les résultats dans un fichier de sortie.
Code: Tout sélectionner
:- use_module('totex_lexical.pl').
:- use_module('totex_syntaxique.pl').

to_tex :-
   % lecture du fichier d'entrée
   open('C:\\Users\\Utilisateur\\Documents\\Prolog\\totex\\totex.txt', read, In),

   % les sorties console sont rédirigées vers le fichier des resultat
   tell('C:\\Users\\Utilisateur\\Documents\\Prolog\\totex\\totex-resultat.txt'),
   repeat,
       read_line_to_codes(In, Codes_EBNF),
       (   (Codes_EBNF \= end_of_file, Codes_EBNF \= [])
       ->   atom_codes(EBNF, Codes_EBNF),
      lexical_analysis(EBNF, Out),
      phrase(to_tex(A1),Out, Rest),
      (   % la conversion a-t-elle été correcte
          Rest \= []
      ->  format('Erreur : ~w~n', [EBNF]),nl,nl
      ;   atomic_list_concat(A1, A),
          format('~w ~32t ~40+==> ~w~n~n~n', [EBNF, A]))
       ;   true),
   (   Codes_EBNF = end_of_file; Codes_EBNF = []),

   % fermeture du fichier d'entrée
   close(In),
   % fermeture du fichier de sortie
   % la sortie standard est redirigées vers la console
   told.


/*
% pout tester les matrices sur plusieurs lignes
to_tex :-
   open('C:\\Users\\Utilisateur\\Documents\\Prolog\\totex\\totex-1.txt', read, In),
   tell('C:\\Users\\Utilisateur\\Documents\\Prolog\\totex\\totex-resultat.txt'),
   read_stream_to_codes(In, Codes_EBNF),
   close(In),
   atom_codes(EBNF, Codes_EBNF),
   lexical_analysis(EBNF, Out),
   phrase(to_tex(A1),Out, []),
   atomic_list_concat(A1, A),
   writeln(A),
   told.
*/

Fichier d'entrée
(E) 2x + y "ceci est une expression"
3 ^ a sub 4
3 / N exp 12 exp 13
(N sub 1/Y sub 1 + N sub 1/Y sub 2)/(1 - (1/Y sub 1 + 1/Y sub 2 + 1/Y sub 3))
X sub 33 = (N sub 1/Y sub 1 + N sub 1/Y sub 2)/(1 - (1/Y sub 1 + 1/Y sub 2 + 1/Y sub 3))
3/(2+5)
P(3)/5
P("test")
(1,2,3,4,5)
3/(2+(3*5-4)/cos(8))

Fichier de sortie
(E) 2x + y "ceci est une expression" ==> E \Leftrightarrow 2x + y \text{ceci est une expression}

3 ^ a sub 4 ==> 3^{a_{4}}

3 / N exp 12 exp 13 ==> \frac{3}{N^{12^{13}}}

(N sub 1/Y sub 1 + N sub 1/Y sub 2)/(1 - (1/Y sub 1 + 1/Y sub 2 + 1/Y sub 3)) ==> \frac{\frac{N_{1}}{Y_{1}} + \frac{N_{1}}{Y_{2}}}{1 - (\frac{1}{Y_{1}} + \frac{1}{Y_{2}} + \frac{1}{Y_{3}})}


X sub 33 = (N sub 1/Y sub 1 + N sub 1/Y sub 2)/(1 - (1/Y sub 1 + 1/Y sub 2 + 1/Y sub 3)) ==> X_{33} = \frac{\frac{N_{1}}{Y_{1}} + \frac{N_{1}}{Y_{2}}}{1 - (\frac{1}{Y_{1}} + \frac{1}{Y_{2}} + \frac{1}{Y_{3}})}

3/(2+5) ==> \frac{3}{2 + 5}

P(3)/5 ==> \frac{P(3)}{5}

P("test") ==> P( \text{test} )

(1,2,3,4,5) ==> \begin{pmatrix}1 & 2 & 3 & 4 & 5 \end{pmatrix}

3/(2+(3*5-4)/cos(8)) ==> \frac{3}{2 + \frac{3 \times 5 - 4}{\cos(8)}}

La grande formule

Avatar de l’utilisateur
fatal_error
Membre Légendaire
Messages: 6610
Enregistré le: 22 Nov 2007, 12:00

par fatal_error » 04 Nov 2013, 22:40

c'est complètement épique, il m'aurait fallu un mois au moins pour pondre un truc comme ca en prolog. Ca à l'air pas mal ces DCG (même si j'ai encore du mal à ingérer le concept).

+1 pour les matrices.

pour les tests que j'ai utilisés, les voici:
Code: Tout sélectionner
a_b---->a_{b}
cos(5)---->\cos(5)
a_(cos(5))---->a_{\cos(5)}
a_(cos(5_2))---->a_{\cos(5_{2})}
3/4---->\frac{3}{4}
d(d)_s---->d(d)  //celui la est un peu particulier. Je ne le parse pas et laisse le _s trainer. Genant.
---->\Leftrightarrow
(E)(F)---->(E)\Leftrightarrow (F)
"test"r---->\text{test}r
(1-2^(n+1))/(1-2)---->\frac{1-2^{n+1}}{1-2}
X33 = (N1/Y1 + N1/Y2)/(1 - (1/Y1 + 1/Y2 + 1/Y3))---->X_{33} = \frac{\frac{N_1}{Y_1} + \frac{N_1}{Y_2}}{1 - (\frac{1}{Y_1} + \frac{1}{Y_2} + \frac{1}{Y_3})}
f'(a)---->f'(a)
f'(a)\ntest---->f'(a)\\\ntest
B1(f_O1(x_0))---->B_1(f_{O_1}(x_{0}))
B1(a)---->B_1(a)
2y0---->2y_0
\lim_{x=8}---->\lim_{x=8}
3=>5---->3\Rightarrow 5
la vie est une fête :)

joel76
Membre Relatif
Messages: 230
Enregistré le: 11 Fév 2013, 15:31

par joel76 » 05 Nov 2013, 01:13

Les DCG (abréviation de Definite Clause Grammar ou Grammaire à Clause définie) permettent de décrire les grammaires telles pratiquement qu'on les pense, ce petit lien pour comprendre.

J'ai du mal avec f'(a)\ntest. Quel doit être l'affichage tex ?

ou ou ou ou

joel76
Membre Relatif
Messages: 230
Enregistré le: 11 Fév 2013, 15:31

par joel76 » 08 Nov 2013, 15:41

J'ai mis à jour mon code en supposant que la bonne version de f'(a)\ntest soit

Avatar de l’utilisateur
fatal_error
Membre Légendaire
Messages: 6610
Enregistré le: 22 Nov 2007, 12:00

par fatal_error » 09 Nov 2013, 09:50

hello concernant f'(a)\ntest
ca voulait dire

[normal ]f'(a)
test
[/normal]
-->
[TEX ] f'(a) \\
test
[/TEX]
la vie est une fête :)

joel76
Membre Relatif
Messages: 230
Enregistré le: 11 Fév 2013, 15:31

par joel76 » 09 Nov 2013, 18:50

OK c'est comme ça que je l'avais finalement interprété !

 

Retourner vers ϟ Informatique

Qui est en ligne

Utilisateurs parcourant ce forum : Aucun utilisateur enregistré et 2 invités

Tu pars déja ?



Fais toi aider gratuitement sur Maths-forum !

Créé un compte en 1 minute et pose ta question dans le forum ;-)
Inscription gratuite

Identification

Pas encore inscrit ?

Ou identifiez-vous :

Inscription gratuite