173
Títol: Generació Ordenada d’Estructures Combinatòries en “MuPAD-Combinat” Volum: I Alumne: Jordi Vives Pons Director/Ponent: Xavier Molinero Albareda Departament: LSI Data: 4 de gener de 2008

Títol: Generació Ordenada d’Estructures Combinatòries en

  • Upload
    others

  • View
    3

  • Download
    0

Embed Size (px)

Citation preview

Page 1: Títol: Generació Ordenada d’Estructures Combinatòries en

Títol: Generació Ordenada d’Estructures Combinatòries en “MuPAD-Combinat”

Volum: I

Alumne: Jordi Vives Pons

Director/Ponent: Xavier Molinero Albareda

Departament: LSI

Data: 4 de gener de 2008

Page 2: Títol: Generació Ordenada d’Estructures Combinatòries en
Page 3: Títol: Generació Ordenada d’Estructures Combinatòries en

DADES DEL PROJECTE

Títol del Projecte: Generació Ordenada d’Estructures Combinatòries en “MuPAD-Combinat”

Nom de l'estudiant: Jordi Vives Pons

Titulació: Enginyeria Superior en Informàtica

Crèdits: 37.5

Director/Ponent: Xavier Molinero Albareda

Departament: LSI

MEMBRES DEL TRIBUNAL (nom i signatura)

President: Salvador Roura Ferret

Vocal: Juan Trias Pairo

Secretari: Jordi Petit Silvestre

QUALIFICACIÓ

Qualificació numèrica:

Qualificació descriptiva:

Data:

Page 4: Títol: Generació Ordenada d’Estructures Combinatòries en
Page 5: Títol: Generació Ordenada d’Estructures Combinatòries en
Page 6: Títol: Generació Ordenada d’Estructures Combinatòries en
Page 7: Títol: Generació Ordenada d’Estructures Combinatòries en

Agraïments M’agradaria expressar, amb aquestes línies, el meu agraïment a totes aquelles persones que

d’alguna manera m’han ajudat a realitzar aquest projecte.

En primer lloc, moltes gràcies a en Xavier Molinero Albareda, per confiar en mi i donar- me

l’oportunitat de realitzar el projecte final de carrera amb ell. Gràcies per guiar-me i

resoldre els meus dubtes sempre que ho he necessitat. Ha resultat una experiència

francament interessant.

Moltes gràcies a la meva família. Sobretot als meus pares, Julià i Alba, per recolzar-me en tot

el que he fet sempre.

A tots els amics/companys de la FIB, sense els quals, aquests anys no m’haurien resultat tan

gratificants.

Moltes, moltíssimes gràcies a la Jesica, pel seu suport incondicional, sobretot en els

moments més durs d’aquest projecte, i per la seva comprensió durant aquests mesos en què

no he pogut estar tant per ella com hauria volgut. Gràcies pel teu interès i per ajudar-me

amb tot el que has pogut. Per fi ha arribat el moment! ;)

I, per acabar, gràcies també a totes aquelles persones que d’alguna manera m’han donat

suport moral durant aquests darrers mesos, que han estat durs però enriquidors.

i

Page 8: Títol: Generació Ordenada d’Estructures Combinatòries en

ii

Page 9: Títol: Generació Ordenada d’Estructures Combinatòries en

Índex general de continguts

Presentació...............................................................................................................................................1 Capítol I: Visió general del projecte.

1 RAÓ I OPORTUNITAT DEL PROJECTE .......................................................... 15

2 SITUACIÓ ACTUAL .............................................................................................. 15

3 OBJECTIUS ............................................................................................................. 18

4 ALTRES ASPECTES A CONSIDERAR .............................................................. 19

5 ALTRES OPCIONS ESTUDIADES ...................................................................... 21

6 EXECUCIÓ DEL PROJECTE I PLANIFICACIÓ ............................................. 21 Capítol II: Preliminars Matemàtics.

1 INTRODUCCIÓ....................................................................................................... 26

2 PRELIMINARS MATEMÀTICS .......................................................................... 26 2.1 Definicions .................................................................................................................................. 26 2.2 Objectes combinatoris descomposables ...................................................................................... 33

Capítol III: Generació d’Especificacions Estàndard.

1 INTRODUCCIÓ....................................................................................................... 41

2 ESPECIFICACIONS ESTÀNDARD ..................................................................... 41

3 ALGORISME PER A LA GENERACIÓ D’ESPECIFICACIONS ESTÀNDARD................................................................................................................... 47

4 RESULTATS OBTINGUTS ................................................................................... 73 4.1 Tractament d’errors ..................................................................................................................... 74 4.2 Sortides generades....................................................................................................................... 77

Page 10: Títol: Generació Ordenada d’Estructures Combinatòries en

Capítol IV: Unranking.

1 INTRODUCCIÓ....................................................................................................... 85

2 ESTUDI DE LA FUNCIÓ D’ UNRANKING ......................................................... 85 2.1 Unranking de classes no etiquetades ........................................................................................... 88 2.2 Unranking de classes etiquetades ................................................................................................ 99

3 IMPLEMENTACIÓ DE L’UNRANKING........................................................... 103

4 ANÀLISI DEL COST ............................................................................................ 133 4.1 Sortides generades..................................................................................................................... 138

Capítol V: Ranking.

1 INTRODUCCIÓ..................................................................................................... 144

2 ESTUDI DE LA FUNCIÓ DE RANKING ........................................................... 144 2.1 Ranking de classes etiquetades.................................................................................................. 147 2.2 Ranking de classes no etiquetades............................................................................................. 151

3 IMPLEMENTACIÓ DEL RANKING .................................................................. 152

4 ANÀLISI DEL COST ............................................................................................ 164 4.1 Sortides generades..................................................................................................................... 165

Capítol VI: Balanç i conclusions.

1 OBJECTIUS COBERTS ....................................................................................... 169

2 CONCLUSIONS..................................................................................................... 169

3 FEINA FUTURA.................................................................................................... 170 Referències.

vi

Page 11: Títol: Generació Ordenada d’Estructures Combinatòries en

Presentació Aquest document correspon a la memòria del projecte de final de carrera anomenat Generació

Ordenada d’Estructures Combinatòries en “MuPAD-Combinat”.

Les tasques que s’han dut a terme durant la realització d’aquest projecte es poden agrupar en

tres grans apartats:

▪ Estudi previ del sistema MuPAD.

▪ Estudi d’algorismes teòrics existents per a la resolució de problemes de generació ordenada

d’estructures combinatòries.

▪ Implementació dels algorismes anteriors en MuPAD.

Organització de la memòria Aquesta memòria està dividida en sis capítols:

Capítol I: Visió general del projecte. Motivacions del projecte, descripció dels objectius i

visió general de la solució proposada.

Capítol II: Preliminars Matemàtics. Introducció a les estructures combinatòries des d’un

punt de vista formal i matemàtic.

Capítol III: Generació d’Especificacions Estàndard. Estudi per a la generació

d’especificacions en format estàndard i anàlisi del codi implementat.

Capítol IV: Unranking. Estudi dels algorismes d’unranking i anàlisi de la seva

implementació en MuPAD-Combinat.

Capítol V: Ranking. Estudi dels algorismes de ranking i anàlisi de la seva implementació en

MuPAD-Combinat.

Capítol VI: Balanç i conclusions. Valoració sobre l’elaboració del projecte.

Referències. Referències bibliogràfiques, webs, llibres i articles consultats en diverses

etapes del projecte.

1

Page 12: Títol: Generació Ordenada d’Estructures Combinatòries en
Page 13: Títol: Generació Ordenada d’Estructures Combinatòries en

Capítol I

Visió general del projecte

Page 14: Títol: Generació Ordenada d’Estructures Combinatòries en

Capítol I – Visió General del Projecte

Índex del capítol

1 RAÓ I OPORTUNITAT DEL PROJECTE ...................................................... 15

2 SITUACIÓ ACTUAL .......................................................................................... 15

3 OBJECTIUS ......................................................................................................... 18

4 ALTRES ASPECTES A CONSIDERAR........................................................... 19

5 ALTRES OPCIONS ESTUDIADES .................................................................. 21

6 EXECUCIÓ DEL PROJECTE I PLANIFICACIÓ.......................................... 21

Page 15: Títol: Generació Ordenada d’Estructures Combinatòries en

PFC – Generació Ordenada d’Estructures Combinatòries en “MuPAD-Combinat”

15

1 Raó i oportunitat del projecte

MuPAD és un sistema algebraic que es troba en constant evolució per tal de cobrir el màxim

de les necessitats de la indústria (problemes matemàtics i tècnics), de l’àmbit universitari i

de la recerca (eines matemàtiques, etc.), i de l’entorn de l’ensenyament i dels estudiants

(càlculs algebraics i numèrics, etc.) [http://www.mupad.com]. Emperò, existeixen un seguit

de funcionalitats sobre classes combinatòries que encara no es troben completament

desenvolupades ([15]).

MuPAD ofereix també un potent entorn de programació per tal que els seus usuaris puguin

implementar aquelles funcionalitats necessàries però encara no existents en les llibreries.

Unint aquestes dues idees, es desenvoluparà un seguit d’algorismes sobre classes

combinatòries, fent ús del propi entorn de programació de MuPAD.

2 Situació actual

Actualment, la investigació i el desenvolupament així com molts dels productes que usem

quotidianament (directa o indirectament), depenen de complicats models matemàtics i la

resolució de complexos problemes, i són inimaginables sense aquests. La companyia SciFace

i el seu producte de software MuPAD, proporcionen aquesta capacitat.

MuPAD és un programa comercial d’àlgebra computacional, desenvolupat pel Grup

d’Investigació MuPAD, des de l’any 1990, a la Universitat de Paderborn, Alemania, sota la

direcció del professor Benno Fuchssteiner (http://www.mupad.com).

SciFace Software GmbH & Co. KG va ser fundada pel professor Benno Fuchssteiner l’any

1997 com a un derivat del Grup d’investigació MuPAD. Actualment, el seu director executiu

és el Dr. Oliver Kluge. La major part dels treballadors de SciFace són els antics membres del

Grup d’Investigació.

L’objectiu de SciFace, és “fer la ciència accessible” proporcionant eines obertes i

professionals, que ajudin a l’usuari a entendre i resoldre problemes científics (especialment

matemàtics). SciFace actualment treballa en els camps dels Sistemes d’Algebra

Computacionals Oberts (Open Computer Algebra Systems) i dels Medis Científics Interactius

(Interactive Scientific Media).

MuPAD és un sistema d’àlgebra computacional d’altes prestacions desenvolupat en un etorn

de treball integrat i obert, per a la resolució i tractament de problemes científics i

matemàtics, tant numèrics com algebraics. MuPAD pot ser una bona solució per a la

Page 16: Títol: Generació Ordenada d’Estructures Combinatòries en

Capítol I – Visió general del projecte

16

resolució de problemes matemàtics en una àmplia varietat de sectors, des de l’educació

matemàtica bàsica en les escoles, fins als projectes de desenvolupament i investigació a les

universitats.

La sintaxis és modelada en Pascal, i és similar a la utilitzada en el llenguatge simbòlic Maple

d’àlgebra computacional (http://www.maplesoft.com). La major diferència entre els dos rau

en què MuPAD proporciona suport per a la programació orientada a objectes. Això significa

que cada objecte carrega amb ell els mètodes/operacions permesos per a ser usats. MuPAD

proporciona les construccions essencials d’un llenguatge de programació. L’usuari pot

implementar algorismes complexes còmodament en MuPAD.

Actualment, MuPAD disposa de les següents funcionalitats ([1], [15]):

• Concepte de Notebook: el Notebook és la part bàsica de MuPAD. Els Notebooks

combinen càlculs, textos i gràfics en un únic document. Això permet reeditar i tornar

a avaluar expressions MuPAD ja existents. Es poden obrir diverses Notebooks

independents al mateix temps, passar d’un Notebook a un altre mitjançant la barra

de tabulació i exportar-los a diferents formats (RTF, text, Word i HTML). • Editor de codi font: MuPAD inclou un editor de codi font per a l’escriptura de

procediments definibles per el propi usuari, així com a una eina de colorejat de

sintaxi i de gestió de bookmarks.

• Depurador de codi font: Per a una correcta execució dels procediments escrits en

MuPAD, el programa inclou també un potent editor per a la depuració i optimització

de les línies de codi. Mostra, a més, les variables definides per l’usuari i permet

l’execució d’expressions de manera arbitrària durant el procés de depurat.

• Eines gràfiques interactives: MuPAD proporciona un potent visualitzador de

resultats 2D i 3D, denominat Virtual Camera (VCam) que permet observar, des de

qualsevol angle, funcions, corbes, superfícies i objectes matemàtics en general.

• Ajuda en línia en format hipertext: Els sistemes d’ajuda de MuPAD i la seva

àmplia documentació, permeten disposar de tota l’ajuda en línia necessària relativa a

les instruccions MuPAD, així com de tots els procediments d’edició del programa.

• Suport OLE2: Els Notebooks de MuPAD i els gràfics VCam poden ser incrustats en

altres aplicacions OLE (com per exemple Word ó Excel). Al mateix temps, les fulles

de càlcul Excel poden ser incrustades en les Notebooks de MuPAD.

• Característiques i funcions generals:

o Aritmètica multiprecisió; Manipulació d’expressions i càlcul simbòlic;

Estructures de dades definibles per l’usuari; Programació funcional,

procedural i orientada a objectes; Enllaços dinàmics a codi binari extern;

Extensa documentació en línia (hipertext); Eina gràfica 2D i 3D interactiva.

• Àmplies funcions matemàtiques:

o Solució d’equacions:

Equacions i sistemes d’equacions; Inequacions; Equacions

diferencials parcials i ordinàries; Relacions de recurrència lineals;

Page 17: Títol: Generació Ordenada d’Estructures Combinatòries en

PFC – Generació Ordenada d’Estructures Combinatòries en “MuPAD-Combinat”

17

Congruències lineals; Equacions diofàntiques polinomials; Equacions

sobre dominis estàndard (enteres, reals, complexes); Equacions

sobre estructures algebraiques abstractes.

o Càlcul:

Límits; Integració; Diferenciació; Expansió de sèries; Transformació

integrals; Operadors diferencials; Polinomis ortogonals.

o Àlgebra lineal:

Matrius sobre anells de coeficients arbitraris; Determinants; Valors

propis; Vectors propis; Formes canòniques; Divergències; Gradients;

Curl.

o Anàlisis numèric:

Resolució d’equacions i sistemes d’equacions; Arrels de polinomis;

Integració; Equacions diferencials ordinàries; Càlcul funcional per a

matrius; Valors propis; Vectors propis; Descomposició de valors

singulars; Transformades ràpides de Fourier; Interpolació

polinòmica; Mètodes Splines; Optimització.

o Teoria de conjunts:

Unió; Intersecció; Producte Cartesià.

o Polinomis:

Anells arbitraris; Representació “Sparse”; GCD; Factorització; Bases

de Groebner.

o Optimització lineal:

Resolució; Minimització, maximització; Representació de programes

enters mixtes i lineals.

o Teoria de nombres:

Fraccions contínues; Factorització mitjançant corbes elíptiques;

Símbols de Jacobi i Legendre; Phi de Euler; Funcions de Mangdolt,

Moebius i Charmichael; Arrels modulars i primitives.

o Combinatòria:

Nombres de Stirling, Catalan i Bell; Composicions; Partició de

nombres; Permutacions de llistes; Subconjunts; Generadors.

o Estadística:

Correlació de Bravais-Pearson i Fechner; Distribucions contínues i

discretes; Distribucions Chi-quadrat, T i normal; Aritmètica i

geomètrica; Harmòniques i quadràtiques; Regressió lineal i no-lineal;

Desviació estàndard; Variància, covariància, Kurtosis, etc; Generació

de nombres aleatoris; Densitats de probabilitat i acumulativa;

Quartils.

o Xarxes i gràfiques:

Definició, edició i dibuix; Cerca de camins curts i optimització per a

fluxos màxims.

o Sistemes de Lindenmayer:

Page 18: Títol: Generació Ordenada d’Estructures Combinatòries en

Capítol I – Visió general del projecte

18

Definició i gràfiques de fractals per significats lliures de continguts.

o Estructures algebraiques:

Grups simètrics; Anells polinòmics; Anells matricials i grups;

Producte d’anells; Extensions de camp algebraiques; Camps finits i

camps quocient; Creació de dominis definibles per l’usuari amb

extensió a aquestes estructures.

Entre tot el que s’ha exposat, el que ens interessarà realment serà el conjunt de

funcionalitats combinatòries proporcionades pel paquet “MuPAD-Combinat”. Aquesta llibreria

aporta no només funcions combinatòries, sinó també eines per al comptatge, la generació i

la manipulació d’objectes combinatoris. Dintre d’aquesta llibreria, ens centrarem en la

categoria dels “decomposableObjects”, el qual ens proporciona funcions per al comptatge, la

generació i la representació a l’atzar d’objectes combinatoris descomposables definits

recursivament per una especificació.

Donat que MuPAD és un sistema en contínua evolució, no tots els paquets d’aquest software

es troben totalment implementats i complerts. Ara, la problemàtica a la que volem fer front,

consistirà en cobrir algunes de les mancances de la llibreria “MuPAD-Combinat”,

concretament en l’apartat de la generació d’estructures combinatòries.

3 Objectius A continuació, definirem l’objectiu final d’aquest projecte:

Realitzar un estudi de la implementació i la complexitat dels algorismes existents de

generació d’estructures combinatòries: la generació determinista –unranking i

ranking – i, si es disposa de prou temps, dels problemes de generació exhaustiva

(generating). El llenguatge en què s’implementaran aquests algorismes serà MuPAD.

Si definim el projecte mitjançant la metodologia PAM:

Purpose (P): estudiar i implementar un conjunt d’algorismes de generació

d’estructures combinatòries fent servir les eines proporcionades pel sistema MuPAD.

Advantages (A): el conjunt d’algorismes que estudiarem, analitzarem i

implementarem proporcionarà les eines necessàries per a dur a terme un conjunt de

funcionalitats no cobert completament per MuPAD fins al moment.

Measurement (M): pretenem que el conjunt de funcionalitats a desenvolupar

cobreixi aquelles ja tractades per MuPAD i que, a més, també inclogui aquelles no

cobertes fins al moment (unranking de Sets i Powersets no etiquetats, ranking, etc.).

Page 19: Títol: Generació Ordenada d’Estructures Combinatòries en

PFC – Generació Ordenada d’Estructures Combinatòries en “MuPAD-Combinat”

19

Per tal d’entendre perfectament el problema al que ens enfrontem i l’objectiu que busquem,

cal que definim en què consisteix cada un dels tipus de generació determinista que

tractarem:

• Unranking: donada una classe A i una mida/talla n, generar l’objecte tal que tingui el

rank que ens hagin donat dins dels objectes d’An (d’acord a un ordre específic).

• Ranking: donada una classe combinatòria i un objecte d’aquesta classe, calcular el

rank d’aquest objecte, és a dir, el nombre d’objectes de la classe de la mateixa mida

que l’objecte donat, però que són més petits (d’acord amb un ordre prèviament

fixat).

• Generació exhaustiva: Es pretén obtenir tots els objectes d’una determinada mida n

existents per a la classe combinatòria especificada.

4 Altres aspectes a considerar Per poder començar a treballar en els algorismes a desenvolupar, caldrà que abans

coneguem alguns aspectes més de l’entorn del projecte.

Donat que la solució proposada es basa en un conjunt d’algorismes implementats en el propi

entorn de programació MuPAD i que, al mateix temps, es procurarà que el format dels

algorismes s’adapti el màxim possible al format de les llibreries preexistents del sistema, es

requerirà que l’arquitectura tècnica (hardware i software) sigui com a mínim capaç de

suportar el sistema MuPAD.

En el nostre cas, les característiques del hardware i el software que usarem són les

següents:

• Hardware:

o CPU Intel T2400 (1,83 GHz)

o 1 GB RAM

• Software:

o Debian GNU/Linux 3.1

o MuPAD Pro 4.0.0

Un cop estigui a punt l’entorn sota el qual treballarem i donat que en un principi no disposem

d’un coneixement gaire ampli en MuPAD, la primera necessitat d’informació radicarà en

adquirir coneixements sobre aquest i les eines que proporciona per al desenvolupament

d’algorismes.

A més, també caldrà que obtinguem informació sobre els algorismes en pseudocodi

prèviament existents de generació d’estructures combinatòries, i que els estudiem i

analitzem per tal d’entendre completament el seu funcionament.

Page 20: Títol: Generació Ordenada d’Estructures Combinatòries en

Capítol I – Visió general del projecte

20

Podem suposar que el resultat obtingut en aquest projecte es reflectirà en un conjunt de

beneficis per als usuaris del sistema MuPAD. Així, a grans trets, podem suposar els següents

possibles beneficis:

• Tangibles:

o Obtenció d’una llibreria de generació d’estructures combinatòries, la qual cosa,

al mateix temps proporcionarà:

Simplificació del procés de generació d’estructures combinatòries.

Reducció del temps de generació d’estructures combinatòries.

Increment en l’eficiència en la generació d’estructures combinatòries.

• Intangibles:

o Millora de la imatge tecnològica del sistema.

o Millora en l’aspecte de les solucions obtingudes pels usuaris.

o Millora del servei de MuPAD enfront dels usuaris del sistema.

o Major nombre de funcions/algorismes a disposició dels usuaris.

o Major ventall d’aplicacions implementables pels usuaris.

Ara bé, també podem suposar que el nostre projecte produirà una sèrie d’impactes i canvis

en el sistema ja existent. Així, per tal de minimitzar-los, caldrà que proveïm als usuaris d’una

documentació clara i rigurosa sobre el funcionament dels algorismes desenvolupats. En

aquesta documentació, haurà de constar una breu descripció de la funcionalitat, la signatura

de l’operació, el resultat esperat i els possibles malfuncionaments que s’hagin pogut detectar

(fins al moment). A més, treballarem de tal manera que no caldrà que l’usuari realitzi cap

canvi sobre el hardware o software que tingui instal·lats. Tan sols caldrà que, quan vulgui

usar les noves funcionalitats implementades, carregui el conjunt d’algorismes en la Notebook

que estigui usant.

Així, per garantir al màxim que el codi a implementar sigui compatible amb el sistema

existent s’ha optat per, sempre que sigui possible, mantenir l’estructura de les llibreries de

MuPAD.

A més, s’intentarà reutilitzar el màxim de codi ja implementat per tal de què el nombre de

codi replicat sigui mínim i la compatibilitat màxima.

Emperò, una de les situacions de risc més clara de tot el projecte apareix a l’hora de

reutilitzar el propi codi del sistema. És segur que, en alguna situació, el codi ja existent no

cobrirà per complet les necessitats, i per tant, la detecció d’aquesta situació i la

“reprogramació” del codi necessari poden comportar alguns problemes.

Page 21: Títol: Generació Ordenada d’Estructures Combinatòries en

PFC – Generació Ordenada d’Estructures Combinatòries en “MuPAD-Combinat”

21

Al mateix temps, la complexitat conceptual d’alguns d’aquests algorismes, pot provocar que

la solució presentada no cobreixi en la seva totalitat la funcionalitat desitjada.

5 Altres opcions estudiades En un principi, es va estudiar la possibilitat d’implementar els algorismes en codi C++, però

es va abandonar la idea ja que s’haurien hagut de reimplementar un ampli conjunt

d’algorismes no pertanyents a la generació d’estructures combinatòries pròpiament dita

(però necessaris per a dur-la a terme), la qual cosa deixava el projecte fora de l’abast de

qualsevol PFC.

Per tant, es va optar per enfocar la implementació de la llibreria per a un dels sistemes

d’àlgebra computacional existents, per tal de què així, algunes de les funcions necessàries ja

es trobessin prèviament implementades. Així, entre l’ampli ventall de tots els sistemes

algebraics existents, la decisió final oscil·lava entre Maple i MuPAD. Però donat l’origen obert

i lliure de MuPAD, i el més fàcil accés a la codificació de les llibreries d’aquest últim, es va

acabar optant per aquesta opció.

6 Execució del projecte i planificació Per a dur a terme el present projecte s’ha considerat que es disposava d’unes 375 hores

totals, és a dir, d’uns 37,5 crèdits (on cada crèdit equival a 10 hores).

S’ha considerat que les següents etapes conformen la planificació global que s’haurà de dur a

terme per completar satisfactòriament el projecte:

• Etapa 1: Familiarització amb l’entorn del sistema algebraic MuPAD i la llibreria

MuPAD-Combinat.

• Etapa 2: Estudi dels algorismes existents en pseudocodi de generació d’estructures

combinatòries:

o Fase 1: Cerca d’informació i estudi.

o Fase 2: Presa de decisions sobre la futura implementació.

• Etapa 3: Implementació d’algorismes:

o Fase 0: Implementació de l’especificació adient. És a dir, donada

l’especificació d’una classe, obtenir l’especificació en el format estàndard CNF

(Chomsky Normal Form) .

o Fase 1: Unrank (etiquetat i no etiquetat) per als constructors Unió, Producte,

Seqüències, Sets, Powersets (només pel cas no etiquetat) i Cicles.

o Fase 2: Rank (etiquetat i no etiquetat) per als constructors Unió, Producte i

Seqüències.

Page 22: Títol: Generació Ordenada d’Estructures Combinatòries en

Capítol I – Visió general del projecte

22

o Fase 3: Exhaustiva (etiquetat i no etiquetat) per als constructors Unió,

Producte, Seqüències, Sets, Powersets i Cicles Unió, Producte, Conjunts,

Cicles, Seqüències i Powersets. [Fase pendent de la disponibilitat de temps]

o Fase 4: Random. [Fase pendent de la disponibilitat de temps]

Paral·lelament al desenvolupament de les esmentades fases, es va realitzant un

estudi i anàlisi de la complexitat dels diversos algorismes implementats.

• Etapa 4: Redacció de la memòria del projecte.

Page 23: Títol: Generació Ordenada d’Estructures Combinatòries en
Page 24: Títol: Generació Ordenada d’Estructures Combinatòries en

Capítol II

Preliminars Matemàtics

Page 25: Títol: Generació Ordenada d’Estructures Combinatòries en

Índex del capítol

1 INTRODUCCIÓ................................................................................................... 26

2 PRELIMINARS MATEMÀTICS....................................................................... 26 2.1 Definicions ..............................................................................................................................26 2.2 Objectes combinatoris descomposables ..................................................................................33

Page 26: Títol: Generació Ordenada d’Estructures Combinatòries en

Capítol II – Preliminars Matemàtics

26

1 Introducció

L’objectiu d’aquest projecte, tal i com ja s’ha explicat, consisteix en realitzar un estudi i

implementació dels algorismes existents de generació d’estructures combinatòries

(unranking, ranking i generating). El llenguatge en què s’han implementat aquests

algorismes ha estat MuPAD, i per tant, una primera tasca important a realitzar ha estat

familiaritzar-se amb aquest llenguatge algebraic. És més, per tal de poder treballar amb

estructures combinatòries en MuPAD, ens ha calgut conèixer a fons la llibreria MuPAD-

Combinat (http://mupad-combinat.sourceforge.net/).

La llibreria MuPAD-Combinat proporciona funcions combinatòries, així com eines per al

comptatge, la generació i la manipulació d’objectes combinatoris. Dintre d’aquesta llibreria,

hem volgut centrar-nos en la categoria dels “decomposableObjects”. MuPAD-Combinat ens

proporciona funcions per al comptatge, la generació (determinista i atzarosa) d’objectes

combinatoris descomposables definits recursivament per una determinada especificació.

Així doncs, per tal d’introduir/entendre aquests tipus d’objectes, ens caldrà posseir uns

mínims coneixements matemàtics bàsics, que són els que s’exposaran a continuació en el

present capítol. S’introduiran doncs, un seguit de definicions que es considera que poden

ajudar al lector a comprendre amb més facilitat alguns dels aspectes del material que es

presentarà posteriorment.

La major part d’aquest contingut és estàndard i pot ser trobat en moltes fonts (entre

d’altres, la principal font pel desenvolupament d’aquest PFC ha estat la Tesi Doctoral del meu

Director, Xavier Molinero Albareda, anomenada Ordered Generation of Classes of

Combinatorial Structures). Emperò, per tal de què el present document sigui més

autocontingut, s’ha considerat necessari reproduir en aquest capítol algunes d’aquelles

nocions que poden ser-nos més útils.

2 Preliminars matemàtics

2.1 Definicions Definició 1. Una classe combinatòria és un parell ( )

AA ·, tal que A és un conjunt finit o

infint no numerable i →AA

:· és una funció de mida tal que, per tot n no negatiu,

{ }nAAAn =∈= αα | és finit.

Usarem lletres majúscules (A, B, C, etc.) per tal de referir-nos a classes combinatòries, i

usarem subíndexs enters n a sota del nom d’una classe A per referir-nos al subconjunt

Page 27: Títol: Generació Ordenada d’Estructures Combinatòries en

PFC – Generació Ordenada d’Estructures Combinatòries en “MuPAD-Combinat”

27

d’objectes d’aquesta classe A de mida n ( nA , nB , nC , etc.). De forma similar, nA> , nA< ,

nA≥ i nA≤ denoten el subconjut d’objectes de la classe A de mida major, menor, major o

igual i menor o igual que n.

Típicament, els objectes en una classe estan composats d’unitats més petites, anomenades

àtoms i denotades genèricament per Z. Els àtoms són objectes de mida 1 i, per tant, la mida

d’un objecte correspon al nombre d’àtoms que aquest conté. Els objectes de mida 0

normalment es representen mitjançant el símbol ε 1.

Per exemple, una cadena (o String), està formada per una concatenació de símbols (àtoms).

De forma similar, un arbre està compost de nodes interiors i nodes exteriors (fulles).

Depenent de com sigui l’especificació donada per a l’arbre, la manera en què s’obté la mida

pot canviar. Així, suposant que especifiquéssim el nostre arbre com B = Z + B x B, aleshores

la mida s’obtindria sumant el nombre de fulles. Ara bé, si el nostre arbre s’especifiqués com

B = ε + Z x B x B, la mida consistiria en la suma tan dels nodes interns com dels externs.

B = ε + Z x B x B B = Z + B x B

ε

ε 9 Àtoms 5 Àtoms

Es poden definir dos tipus principals de classes combinatòries, depenent de si els àtoms que

composen un objecte donat de la classe poden ser distingits entre ells o no. En el primer cas,

direm que la classe és (o està) etiquetada, mentre que en el segon cas direm que és (o està)

no etiquetada. Un etiquetatge estàndard vàlid d’un objecte de mida n seria una bijecció dels

àtoms de l’objecte cap a la llista [1..n], o de manera equivalent, una permutació de mida n.

Com a exemple, a continuació es mostren els objectes de mida 2 per a la classe dels arbres

binaris no etiquetada (B = Z + B x B)2 i etiquetada (B = Z + B * B):

1 Alguns autors usen el símbol λ per denotar els objectes de mida 0, anomenat l’objecte buit. El mateix símbol ( )λε , s’usa sovint per a referir-se a la classe tal que només conté l’objecte buit. De forma similar, la Z denota una classe atòmica. 2 A partir d’ara ‘x’ denotarà el producte NO etiquetat, mentre que ‘*’ denotarà el producte etiquetat.

1 2 3

5 4 ε

4

2

1 3 5

6

8

9 7ε ε ε ε ε

ε ε ε ε

Page 28: Títol: Generació Ordenada d’Estructures Combinatòries en

Capítol II – Preliminars Matemàtics

28

Arbres binaris no etiquetats de mida 2:

o [Prod(Z,Z)]

Arbres binaris etiquetats de mida 2:

o [Prod(Z(1),Z(2)), Prod(Z(2),Z(1)) ]

Com es pot observar doncs, l’etiquetatge d’un objecte consisteix en repartir un nombre

d’etiquetes igual a la mida de l’objecte desitjat entre els àtoms que el composen. Per tant en

la generació dels objectes d’una classe etiquetada hi haurà com a mínim dos factors

rellevants: l’ordre de col·locació dels àtoms i l’ordre de col·locació de les etiquetes.

Per tal de poder solucionar els problemes plantejats de unranking i ranking és necessari

trobar una solució eficient al problema del comptatge. És a dir, donada l’especificació d’una

classe i una mida, el comptatge consisteix en calcular (comptar) el nombre d’objectes

d’aquesta mida en la classe donada. Per tant, dirigim la nostra atenció cap a les classes

combinatòries admissibles. Aquestes estan construïdes a partir dels operadors admissibles

aplicats sobre les classes, produint noves classes. En aquest cas, el nombre d’objectes d’una

classe donada es pot calcular a partir del nombre d’objectes de la mida o de mides inferiors

de les classes que la formen.

Podem formalitzar la noció d’admissibilitat a partir de la noció de les funcions generadores de

comptatge.

Definició 2. La funció generadora (de comptatge) d’una classe combinatòria no etiquetada

A és la funció generadora ordinària per a la seqüència { } 0≥nna , on nn Aa #= és el nombre

d’objectes d’A de mida n. El coeficient n-èsim d’A(z) és [ ] )(zAza nn = . Això és,

∑ ∑≥ ∈

==0

)(n A

nn zzazA

α

α

Definició 3. La funció generadora (de comptatge) d’una classe combinatòria etiquetada A és

la funció generadora exponencial per la seqüència { } 0≥nna , on nn Aa #= és el nombre

d’objectes d’A de mida n. El coeficient n-èsim d’A(z) és [ ] )(zAz n ; per tant,

[ ] )(! zAzna nn ⋅= . Això és,

z z

1 2 2 1

Page 29: Títol: Generació Ordenada d’Estructures Combinatòries en

PFC – Generació Ordenada d’Estructures Combinatòries en “MuPAD-Combinat”

29

∑ ∑≥ ∈

==0 !!

)(n A

n

nz

nzazA

α

α

α.

Ara hem de definir quins són els operadors admissibles.

Definició 4. Un operador (també conegut com a constructor) Ψ sobre classes combinatòries

kAAA ,,, 21 K és admissible si i només si existeix algun operador Φ sobre la corresponent

funció generadora de comptatge )(,),(),( 21 zAzAzA kK tal i que

( ) ( ))(,),()( 1,,1 zAzAzCAAC kk KK Φ=⇒Ψ= ,

on C(z) és la funció generadora de comptatge de C.

Alguns exemples sobre possibles operadors etiquetats admissibles inclourien les unions

disjuntes (denotades per ‘+’ o Union), productes particionals (‘*’ o Prod), seqüències

(Sequence), conjunts (Set), cicles (Cycle) i seqüències, conjunts i cicles amb cardinalitat

restringida. Els operadors admissibles corresponents al cas no etiquetat són: unions

disjuntes (denotades per ‘+’ o Union), productes cartesians (‘x’ o Prod), seqüències

(Sequence), conjunts sense repetició (Powerset), conjunts amb repetició (Set), cicles (Cycle)

i seqüències, conjunts (sense i amb repetició) i cicles amb cardinalitat restringida.

A continuació (Taula 1) es resumeixen les relacions entre aquestes construccions (sense

cardinalitat restringida) i les corresponents funcions generadores ([4]).

Taula 1. Funcions generadores Classe Etiquetat No Etiquetat

Union(A,B) = A + B A(z) + B(z) A(z) + B(z)

Prod(A,B) = A * B A(z) B(z) -

Prod(A,B) = A x B - A(z) B(z)

Sequence(A) )(1

1zA−

)(1

1zA−

Powerset(A) - ( )

⎟⎠

⎞⎜⎝

⎛−

>∑ nzAn

n

n )(1

0

)1(exp

Set(A) ( ))(exp zA ⎟⎟⎠

⎞⎜⎜⎝

⎛∑>0

)(expn

n

nzA

Cycle(A) ⎟⎟⎠

⎞⎜⎜⎝

⎛− )(1

1logzA

∑>

⎟⎟⎠

⎞⎜⎜⎝

⎛−0 )(1

1log)(n

nzAnnφ

Una vegada coneguts els operadors combinatoris admissibles que tractarem, procedirem a

descriure’ls breument:

Page 30: Títol: Generació Ordenada d’Estructures Combinatòries en

Capítol II – Preliminars Matemàtics

30

• Fem servir la Unió Disjunta (també anomenada sum) de dues classes A i B, per tal

de representar la unió de dues còpies disjuntes, Aº i Bº, d’A i B. Una forma de

formalitzar aquesta noció consisteix en introduir dos “marcadors” diferents Aε i Bε ,

tots dos de mida zero, i definir la unió (disjunta) A + B com:

( ) ( )BA BABA εε ×∪×=+ .

La unió disjunta és equivalent a la unió estàndard quan s’aplica a conjunts disjunts.

La mida de BA+∈γ , això és BA+

γ , és A

γ si A∈γ ó B

γ si B∈γ .

• El Producte Cartesià d’A i B està format pels parells ( )βα , tals que A∈α i B∈β ,

( )UUA B

BA∈ ∈

=×α β

βα , ,

amb ( )BABA

βαβα +=×

, .

• Si A és una classe, aleshores la classe seqüència és defineix com la suma infinita

( ) ( ) ( ) L+××+×++= AAAAAAASeq ε

Per tal de garantir que el nombre de seqüències de cada mida sigui finit és necessari

imposar que A no contingui cap objecte de mida 0 (això és 00 =a ). De la definició de la

mida provinent de la suma i el producte, la mida de la seqüència és la suma de les mides

dels seus components: si ( ) ( )ASeqK ∈= ααγ ,,1 K aleshores Kααγ ++= L1 .

• La classe Powerset d’A es defineix com la classe consistent en tots els conjunts finits

d’objectes d’A sense repeticions. Sovint s’usa el següent isomorfisme:

( ) ( )∏∈

+=A

APSetα

αε .

Els powersets no requereixen que 00 =a , però en la literatura gairebé sempre es

requereix que 00 =a .

• Els Conjunts són com els powersets, la única diferència resideix en què es permeten

les repeticions de components. Per tant,

( ) ( )∏∈

=A

SeqASetα

α .

Com en el cas de les seqüències, A no pot contenir objectes de mida 0.

• Els Cicles són seqüències definides com a permutacions cícliques: Cycle(A) =

Sequence(A)/~, on ~ és la relació d’equivalència entre seqüències definida per

( ) ( )rr ββαα ,,~,, 11 KK si i només si existeix alguna permutació cíclica σ de [1..n]

tal que per tot j, ( ) jj αβσ = ; en altres paraules, per alguna d, ( )djj ++= 1αβ nmod .

Els operadors etiquetats com les unions, seqüències, conjunts i cicles es defineixen com les

seves contrapartides no etiquetades. Però els productes tenen algunes diferències:

Page 31: Títol: Generació Ordenada d’Estructures Combinatòries en

PFC – Generació Ordenada d’Estructures Combinatòries en “MuPAD-Combinat”

31

• Donats dos objectes etiquetats α i β de mides j i n-j, respectivament, el seu

producte particional (o producte etiquetat) és un conjunt de ( )nj objectes etiquetats

de mida n que resulten del ( )nj reetiquetatges a partir del parell ( )βα , de manera

que cada àtom del parell tingui una etiqueta diferent del rang [1..n], respectant

l’ordre original de les etiquetes d’α i de β . Per exemple, si α = 132 i β = 21

aleshores α * β = {(132,54), (142,53), (143,52), ..., (354,21)}. El producte

etiquetat de les classes etiquetades A i B es defineix aleshores com

UUA B

BA∈ ∈

∗=∗α β

βα ,

amb BABA

βαβα +=∗∗

.

Encara que s’ha parlat de pocs operadors, poden ser usats per definir força classes

combinatòries útils i importants. A continuació, en les taules 2 i 3, proporcionem

especificacions per a algunes classes (etiquetades i no etiquetades) interessants, però és clar

que existeixen diverses maneres alternatives d’especificar una classe donada. Per exemple,

la classe de les permutacions pot ser descrita com Sequence(Z) ó Set(Cycle(Z)), on Z

denota una classe atòmica, això és, una classe que conté tan sols un objecte de mida 1.

Taula 2. Especificacions per a classes etiquetades Classe etiquetada Especificació

Non-plane (Cayley) trees ( )TSetZT ∗=

Binary plane trees BBZB ∗+=

General plane trees ( )GSeqZG ∗=

Set partitions ( )( )1, ≥= cardZSetSetP

Non-plane binary trees ( )2, =+= cardDSetZD

Non-plane ternary trees ( )3, =+= cardESetZE

Hierarchies ( )2, ≥+= cardHSetZH

3-balanced hierarchies ( )( )( )1,1, ≥≥= cardcardZSetSetSetI

Surjections ( )( )1, ≥= cardZSetSeqS

Functional graphs ( )( )TCycleSetF =

Taula 3. Especificacions per a classes no etiquetades Classe no etiquetada Especificació

Integer partition ( )( )1, ≥= cardZSeqSetP

Page 32: Títol: Generació Ordenada d’Estructures Combinatòries en

Capítol II – Preliminars Matemàtics

32

Binary plane trees BBZB ×+=

Binary sequences ( )ZZSeqS +=

Necklaces ( )( )1, ≥= cardZSetCycleN

Rooted unlabelled trees ( )TSetZT ×=

Non-plane binary trees ( )2, =+= cardDSetZD

Non-plane ternary trees ( )3, =+= cardESetZE

Unlabelled hierarchies ( )2, ≥+= cardHSetZH

Random mapping patterns ( )( )TCycleSetF =

Partitions without repetitions ( )( )1, ≥= cardZSeqPowersetW

Desafortunadament però, no tots els operadors combinatoris són admissibles. Per exemple,

la intersecció, la unió disjunta o la diferència són operadors combinatoris no admissibles.

Per tal de formalitzar la definició de classe admissible primer definim les especificacions

admissibles.

Definició 5. Una especificació admissible S és una col·lecció d’equacions de la forma

( )( )ij

ijii i

AAA ,,0KΨ=

on dues equacions qualssevol no poden tenir la mateixa banda esquerra, cada iΨ és un

operador admissible, i cada ( )ijr

A és o una classe ε , una classe atòmica, o existeix una

equació a la col·lecció amb aquesta classe com a la seva banda esquerra. Cada una de les

classes que apareixen a les bandes esquerres de les equacions de S es diu que són

especificades per S.

Definició 6. Si una classe A és especificada per una especificació admissible, aleshores, la

pròpia classe és admissible. Les classes admissibles també s’anomenen classes decidibles ó

ben-formades.

En aquest projecte, entenem com a classe admissible aquelles classes que poden ser

especificades finitament usant la classe ε , classe atòmica (aquelles que contenen un sol

objecte de mida 1 en general denotat per Z), unions disjuntes (Union, +), productes

Cartesians (Prod, x), productes particionals (Prod, *), seqüències (Sequence), powersets

(Powerset), conjunts (Set), cicles (Cycle), seqüències amb la cardinalitat restringida

( ( )kcardSeq µ,K ), powersets amb la cardinalitat restringida ( ( )kcardPSet µ,K ), conjunts

amb la cardinalitat restringida ( ( )kcardSet µ,K ) i els cicles amb la cardinalitat restringida

Page 33: Títol: Generació Ordenada d’Estructures Combinatòries en

PFC – Generació Ordenada d’Estructures Combinatòries en “MuPAD-Combinat”

33

( ( )kcardCycle µ,K ) de classes admissibles, on { }≥≤><=∈ ,,,,µ . Els operadors admissibles

no llistats anteriorment no seran considerats en aquest treball.

Notem que, per conveniència, a vegades abreviarem les especificacions escrivint per

exemple ( )( )ZCycleSetP = ó BBZB ∗+= en comptes de la corresponent especificació

estàndard ( ){ })(, ZCycleCCSetP == ó { }BBDDZB ∗=+= , , respectivament.

2.2 Objectes combinatoris descomposables

Una classe combinatòria descomposable és recursivament construïda des de classes

base usant un constructor. Les classes bàsiques que existeixen i sobre les quals es

construeixen la resta de classes són:

• Epsilon o Epsilon(A): una classe contenint un sol objecte de mida zero, anomenat

Epsilon o A. Una producció del tipus A = Epsilon és reescrita com A = Epsilon(A)

• Atom o Atom(A): una classe contenint un sol objecte de mida u, anomenat Atom o

A. Una producció del tipus A = Atom és reescrita com A = Atom(A)

• Z: és equivalent a Atom(Z); és una nomenclatura estàndard per a la definició

d’Atom.

Els constructors que tractem per a la construcció de noves classes són:

• Union(A, B, ...): la unió disjunta de les classes A, B, ...

• Prod(A, B, ...): el producte particional de les classes A, B, ...

• BoxedProd(A, B, ...): (per estructures etiquetades) similar al Prod però forçant a què

l’etiqueta més petita es trobi en la classe més a l’esquerra (o dreta).

• Sequence(A): totes les seqüències d’elements d’A; on A no hauria de contenir

elements de mida zero.

• Set(A ) / Multiset(A): tots els conjunts d’elements d’A amb possibles repeticions; on

A no hauria de contenir elements de mida zero.

• Powerset(A): tots els conjunt d’elements d’A sense repeticions; on A no hauria de

contenir elements de mida zero. Per al cas etiquetat, el comportament del Powerset

és equivalent al del Set(A ) / Multiset(A), ja que permetem que apareguin elements

repetits, però amb un etiquetatge diferent. Així doncs, la utilització del Powerset com

a tal, només té sentit en el cas no etiquetat.

• Cycle(A): tots els cicles dirigits d’elements d’A, excloent el cicle buit; on A no hauria

de contenir elements de mida zero.

• Alias(A), Alias(A,f): una àlies a la classe A, o la imatge de la classe A per la funció f.

Page 34: Títol: Generació Ordenada d’Estructures Combinatòries en

Capítol II – Preliminars Matemàtics

34

El constructor Sequence, així com els constructors Powerset, Set / Multiset i Cycle per al cas

de classes etiquetades, accepten paràmetres extra (MinLength, MaxLength, i Length) per a

definir restriccions de mida (tot i que també permetrem aquests tres extres per a les

mateixes classes no etiquetades). Per exemple, Sequence(A, MinLength=3, MaxLength=5)

representa totes les seqüències d’elements d’A d’entre 3 i 5 de llargada.

Una especificació combinatòria és una llista (o conjunt o taula) de diverses

produccions de la forma: A = <rhs>, on A és el nom de la classe que s’està definint,

i <rhs> és una expressió que involucra classes elementals, constructors i altres

classes. A és anomenada no-terminal.

A continuació, a mode d’exemple, es troba la definició d’algunes classes combinatòries

conegudes:

Classes Etiquetades:

[A = Prod(Z,Set(A))] non plane trees

[B = Union(Z,Prod(B,B))] plane binary trees

[C = Prod(Z,Sequence(C))] plane general trees

[D = Set (Cycle(Z))] permutations in cycle

notation

[E = Set (Cycle(A)), A=Prod(Z, Set (A))] functional graphs

[F = Set (Set (Z,MinLength=1))] set partitions

[G = Union(Z,Prod(Z, Set (G,Length=3)))] non plane ternary trees

[H = Union(Z,Set (H,MinLength=2))] hierarchies

[L = Set (Set (Set (Z,MinLength=1),MinLength=1))] 3-balanced hierarchies

[M = Sequence(Set (Z,MinLength=1))] surjections

Classes No Etiquetades

[A = Set (Sequence(Z,MinLength=1))] integer partitions

[B = Sequence(Union(Z,Z))] binary sequences

[C = Cycle(Sequence(Z,MinLength=1))] necklaces

[D = Prod(Z, Set (D))] rooted unlabelled trees

Page 35: Títol: Generació Ordenada d’Estructures Combinatòries en

PFC – Generació Ordenada d’Estructures Combinatòries en “MuPAD-Combinat”

35

[E = Powerset(Cycle(D)), D=Prod(Z,Powerset(D))] random mappings patterns

[F = Union(Z, Set (F,Length=2))] nonplane binary trees

[G = Union(Z, Set (G,Length=3))] nonplane ternary trees

[H = Union(Z, Set (H,MinLength=2))] unlabelled hierarchies

Per nosaltres, una especificació serà lliure de context (o context free) si només usa els

constructors Union, Prod i/o BoxedProd (on aquest ve representat per □*), i aquelles derivats

d’ells. Així, a la taula 4 podem veure alguns exemples de com podem descompondre altres

constructors mitjançant els constructors bàsics, donant lloc a un conjunt d’isomorfismes que

més endavant usarem.

Taula 4. Descomposició de constructors Cas Etiquetat

Seqüència )()( ASequenceAASequence ∗+= ε

Set AASet += ε)( □ )(ASet∗

Powerset -

Cycle AACycle =)( □ )(ASequence∗

Per a les Seqüències no etiquetades, ens valdrà el mateix isomorfisme si apliquem un petit

canvi i, en comptes del producte etiquetat usem el no etiquetat

( )()( ASequenceAASequence ×+= ε ). Les descomposicions dels Sets i Powersets no són

tan senzilles i ja veurem com tractarem aquests casos en el capítol dedicat a l’unranking.

Finalment, en aquest projecte no contemplem el cas dels Cicles no etiquetats.

Un factor que cal tenir en compte en les classes d’objectes combinatoris descomposables és

l’ordre de generació dels elements dels objectes. Existeixen dos tipus d’ordre per a la

generació dels objectes: l’ordre lexicogràfic (lexicogràfic order) i l’ordre bustrofèdic

(bustrophedonic order) ([4], [9]).

L’ordre lexicogràfic es pot entendre com l’ordre més natural. Així, per exemple, si C = A + B

diem que primer tenim els objectes d’A i després venen els objectes de B. Més formalment,

si γ i 'γ són dos objectes de nC , aleshores

( ) ( ) ( )BAióBióAiynnn BAC ∈∈∈∈⇔ '','','' γγγγγγγγγγγ pppp .

Page 36: Títol: Generació Ordenada d’Estructures Combinatòries en

Capítol II – Preliminars Matemàtics

36

És important remarcar aquí que, tot i que ABBA +≅+ els ordres induïts per aquestes dues

especificacions isomòrfiques no és el mateix, és a dir, ABBA ++ ≠pp .

El cas més representatiu però, el trobem quan parlem dels productes. Per exemple, en el cas

en què C = A x B, si tenim dos objectes ( )βαγ ,= i ( )','' βαγ = de C tals que j== 'αα

i jn −== 'ββ , aleshores és natural usar el criteri de l’ordre lexicogràfic per tal d’ordenar-

los: 'γγnCp si 'αα

jAp , ó 'αα = i 'ββjnB −

p . Però és clar que també ens cal definir

l’ordre quan 'αα ≠ . Així, altra vegada recorrem a l’ordre lexicogràfic, que s’indueix de

l’especificació

022110 BABABABAC nnnnn ×++×+×+×= −− L .

Formalment doncs, tenim dos objectes ( )βαγ ,= i ( )','' βαγ = de nC , aleshores

( ) ( ) ( )'''''' ββαααααααααγjnjn BAC ijióijóy

−====<⇔ ppp .

De manera similar, mitjançant el producte, podem definir l’especificació per l’ordre

bustrofèdic,

L+×+×+×+×= −− 111100 BABABABAC nnnnn .

Així, formalment diem que,

{ } { }( ) { } { }( )( ) ( ).''''

'','min,min','min,min'

ββααααααα

ααβαβαβαβαγ

jnj

n

BA

C

ijióijó

ióy

−====

<=<⇔

pp

p.

La principal diferència doncs entre l’ordre bustrofèdic i l’ordre lexicogràfic rau bàsicament en

quin ordre la mida k dels objectes de la primera classe A recorre el conjunt {0,...,n}. Si el

que tenim és un ordre lexicogràfic, la k recorrerà el conjunt d’esquerra a dreta (k = 0...n).

Altrament, si el que usem és el bustrofèdic, la k seguirà l’ordre menys natural k = 0, n, 1, n-

1, ...

Per tal de fer-nos-en una idea millor, a continuació s’exposa una il·lustració a mode

d’exemple on es veuran els objectes de la classe dels arbres binaris (B = Z + B x B) no

etiquetats de mida 4, generats mitjançant cada un dels ordres

• Ordre Lexicogràfic:

Page 37: Títol: Generació Ordenada d’Estructures Combinatòries en

PFC – Generació Ordenada d’Estructures Combinatòries en “MuPAD-Combinat”

37

• Ordre Bustrofèdic:

Un cop ja tenim clar quina són la mena d’objectes amb que tractarem d’ara en endavant, ens

cal també saber quins seran els problemes que s’estudiaran i s’implementaran en aquest

projecte:

• Generació de l’’Especificació Estàndard: donada l’especificació d’una classe, obtenir

l’especificació en el format estàndard CNS (Chomsky Normal Form).

• Unranking: donada una classe A i una mida/talla n, generar l’objecte tal que tingui el

rank que ens hagin donat dins dels objectes d’An (d’acord a un ordre específic).

• Ranking: donada una classe combinatòria i un objecte d’aquesta classe, calcular el

rank d’aquest objecte, és a dir, el nombre d’objectes de la classe de la mateixa mida

que l’objecte donat, però que són més petits (d’acord amb un ordre prèviament

fixat).

Implementarem algorismes per a l’unranking i el ranking d’objectes de talla n, el cost en el

cas pitjor dels quals serà ( )2nΟ en l’ordre lexicogràfic i ( )nn logΟ en l’ordre bustrofèdic.

Page 38: Títol: Generació Ordenada d’Estructures Combinatòries en
Page 39: Títol: Generació Ordenada d’Estructures Combinatòries en

Capítol III

Generació d’Especificacions Estàndard

Page 40: Títol: Generació Ordenada d’Estructures Combinatòries en

Capítol III – Generació d’Especificacions Estàndard

Índex del capítol

1 INTRODUCCIÓ................................................................................................... 41

2 ESPECIFICACIONS ESTÀNDARD ................................................................. 41

3 ALGORISME PER A LA GENERACIÓ D’ESPECIFICACIONS ESTÀNDARD ............................................................................................................... 47

4 RESULTATS OBTINGUTS................................................................................ 73 4.1 Tractament d’errors .................................................................................................................74 4.2 Sortides generades...................................................................................................................77

Page 41: Títol: Generació Ordenada d’Estructures Combinatòries en

PFC – Generació Ordenada d’Estructures Combinatòries en “MuPAD-Combinat”

41

1 Introducció

Totes les entrades dels nostres algorismes requereixen una determinada especificació que

anomenarem especificació estàndard. En aquest capítol tractarem què són i com es poden

obtenir especificacions d’aquest tipus.

En el segon apartat del present capítol, veurem què és el que s’entén per format estàndard

d’una especificació, i s’explicaran algunes nocions bàsiques sobre les especificacions.

En el tercer apartat es detalla l’algorisme que ens permet passar de l’especificació donada

per l’usuari a l’especificació estàndard utilitzada pels nostres algorismes.

En l’últim apartat mostrarem els resultats obtinguts amb l’algorisme propi generat. Així

mateix, es realitzarà una comparació amb els resultats que retornaria el sistema MuPAD si

l’usuari fes servir els mètodes ja implementats en MuPAD-Combinat.

2 Especificacions Estàndard

Una primera pregunta que ens podem fer en veure la introducció d’aquest apartat és per què

ha calgut generar un codi per a obtenir especificacions estàndard si MuPAD ja disposa de

mètodes per a obtenir-ne. La resposta cal buscar-la al fet que en un principi, jo no havia

tractat mai amb el sistema MuPAD i, per tant, es va creure convenient realitzar una primera

presa de contacte amb les possibilitats que oferia l’entorn de programació d’aquest sistema.

Així, es va decidir “reimplementar” i adaptar a les nostres necessitats la generació

d’especificacions estàndard utilitzant les llibreries pròpies de MuPAD. Aprofitant doncs

aquesta “reimplementació” i adaptació, es va decidir limitar el nou codi en els aspectes que

ens fossin necessaris i introduir aquells canvis que vam creure convenients. Emperò, en tot

moment es va procurar ser el màxim fidel a l’esperit dels resultats generats pel propi

sistema.

Amb aquesta idea en ment, es van realitzar algunes provatures amb el sistema per tal

d’observar els resultats retornats. I el primer que es va veure va ser que, quan MuPAD parla

d’especificacions estàndard s’està referint a especificacions que es troben representades en

Forma Normal de Chomsky (CNF o Chomsky Normal Form) ([3], [16], [17]).

La Forma Normal de Chomsky és un tipus d’estàndard per a la representació de gramàtiques.

Direm que una gramàtica lliure de context es troba en CNF si i només si totes les seves

regles de producció són de la forma:

Page 42: Títol: Generació Ordenada d’Estructures Combinatòries en

Capítol III – Generació d’Especificacions Estàndard

42

A -> BC

o bé

A -> α

on A, B i C són símbols no terminals (un símbol que mapeja una producció d’una gramàtica i

que pot genera cadenes mitjançant la substitució tant per altres símbols no terminals com

per símbols terminals, o per la combinació d’amdós), i α és un símbol de terminal (un símbol

que representa un valor constant, i que per tant, no pot ser descompost). Tant B com C

poden ser el símbol inicial.

Ara per tant, ens cal saber també què és una gramàtica i què són les gramàtiques lliures de

context. Veurem primer el més general dels dos conceptes.

Una gramàtica formal és un objecte o model matemàtic que permet especificar un llenguatge

(o llengua), és a dir, és el conjunt de regles capaces de generar totes les possibilitats

combinatòries d’aquest llenguatge, ja sigui aquest un llenguatge formal o un llenguatge

natural.

L’expressió gramàtica formal té dos sentits:

• Gramàtica d’un llenguatge formal.

• Descripció formal de part de la gramàtica d’un llenguatge natural.

Quan ens referim a llenguatge natural, aquestes regles combinatòries reben el nom de

sintaxis, i són inconscients.

Existeixen diversos tipus de gramàtiques formal que generen llenguatges formals (segons la

Jerarquia de Chomsky, existeixen quatre nivells diferenciats de gramàtiques; a nosaltres

però, només ens interessaran les de tipus 2, és a dir, les gramàtiques lliures de context).

Imaginem una gramàtica que consti de les següents dues regles:

1. A -> bAc

2. A -> de

La idea consisteix en substituir el símbol inicial de l’esquerra per altres símbols aplicant les

regles. El llenguatge al qual representa aquesta gramàtica és el conjunt de cadenes de

símbols (o paraules) que poden ser generats d’aquesta manera. En aquest cas, per exemple,

podríem generar la següent paraula:

A -> bAc -> bbAcc -> bbbAccc -> bbbdeccc

Page 43: Títol: Generació Ordenada d’Estructures Combinatòries en

PFC – Generació Ordenada d’Estructures Combinatòries en “MuPAD-Combinat”

43

L’element que es troba en majúscules és el símbol inicial. Els elements en minúscules són

símbols terminals. Les paraules del llenguatge són aquelles que tan sols contenen elements

terminals.

Passem doncs a definir formalment què és una gramàtica formal. Així, podem dir que és una

quàdrupla G = (N, T, P, S) on:

N és un alfabet de símbols no terminals (variables).

T és un alfabet de símbols terminals (constants).

S’ha de complir que la intersecció entre N i T sigui buida. Denotarem com Σ = N υ T

l’alfabet de la gramàtica.

S Є N és el símbol inicial de la gramàtica.

P és el conjunt de regles de producció de la gramàtica, de la forma P = { α → β | α Є

Σ * N Σ *, β Є Σ *}.

És a dir, la cadena α ha de contenir com a mínim una variable, que pot estar rodejada d’un

context.

Finalment, per acabar de parlar de les gramàtiques formals, parlarem també de les

derivacions. Sigui G = (N, T, P, S) una gramàtica, i siguin α, β, δ, φ, ρ, ... paraules de Σ *.

Aleshores,

β es deriva d’α en un pas de derivació, i ho denotem amb α β si existeixen dues

cadenes Φ1, Φ2 Є Σ *, y una producció δ → ρ tals que α = φ1 δ φ2, i β = φ1 ρ φ2.

Denotem amb al tancament reflexiu i transitiu de . És a dir α β denota a

una seqüència de derivacions en un nombre arbitrari de passos des d’α fins β.

x Є Σ * és una forma sentencial de G, si es pot obtenir la següent seqüència de

derivacions S x. En el cas particular de què x Є T * es diu que x és una

sentencia.

Es denomina llenguatge formal generat per G al conjunt L(G) = { x Є T * | S x

}.

Segons la seva definició informal, una gramàtica lliure de context (tant en lingüística com en

informàtica) és una gramàtica formal en què cada regla de producció és de la forma:

V -> ω

on V és un símbol no terminal i ω és una cadena de terminal i/o no terminals. El terme lliure

de context es refereix al fet de què el no terminal V pot sempre ser substituït per ω sense

tenir en compte el context en què això succeeix. Un llenguatge formal (és a dir, un conjunt

Page 44: Títol: Generació Ordenada d’Estructures Combinatòries en

Capítol III – Generació d’Especificacions Estàndard

44

de paraules de longitud finita formada a partir d’un alfabet finit) és lliure de context si

existeix alguna gramàtica lliure de context que la generi.

Vista la definició informal, serà a través de la definició formal de les gramàtiques lliures de

context que podrem observar algunes consideracions interessants sobre la generació de

cadenes a partir de la definició de les gramàtica que es troben en aquest format:

Donat G = (Vt, Vn, P, S) on

Vt és un conjunt finit de terminals

Vn és un conjunt finit de no terminals

P és un conjunt finit de produccions

S Є Vn és el denominat símbol inicial

Els element de P són de la forma

Vn -> (Vt υ Vn)*

Per exemple, a continuació s’exposa una gramàtica lliure de context per a expressions

enteres algebraiques sintàcticament correctes sobre les variables x, y i z:

S -> x | y | z | S + S | S – S | S * S | S / S | (S)

Amb la que podríem generar, per exemple, la cadena (x + y) * x – z * y / (x + x).

Existeixen bàsicament dues formes de descriure com pot ser derivada una cadena des del

símbol inicial per una certa gramàtica formal. La forma més simple és llistar les cadenes de

símbols consecutives, començant pel símbol inicial i finalitzant amb la cadena i les regles que

s’han aplicat. Si introduïm estratègies, com per exemple, reemplaçar sempre el no terminal

de més a l’esquerra primer, aleshores llistant les regles aplicades n’hi ha prou. Per exemple,

prenent la següent gramàtica:

(1) S –> S + S

(2) S -> 1

i la cadena “1 + 1 + 1”, la seva derivació a l’esquerra es pot veure en la llista [(1), (1), (2),

(2), (2)]. Anàlogament, la derivació per la dreta es defineix com la llista que obtenim si

sempre reemplacem primer el terminal de més a la dreta. En aquest cas, la llista de regles

aplicades per a la derivació de la cadena amb la gramàtica anterior seria la [(1), (2), (1),

(2), (2)].

La distinció entre la derivació per l’esquerra i per la dreta és important perquè en la majoria

d’analitzadors de cadenes, la transformació de l’entrada és definida donant una part de codi

per a cada producció que és executada quan la regla és aplicada. De manera que, és

Page 45: Títol: Generació Ordenada d’Estructures Combinatòries en

PFC – Generació Ordenada d’Estructures Combinatòries en “MuPAD-Combinat”

45

important saber quina derivació aplica l’analitzador perquè determina l’ordre en què el codi

serà executat.

Una derivació també pot ser expressada mitjançant una estructura jeràrquica sobre la

cadena que està sent derivada. Per exemple, l’estructura de la derivació a l’esquerra de la

cadena “1 + 1 + 1” amb la gramàtica anterior seria:

S -> S + S (1)

S -> S + S +S (1)

S –> 1 + S + S (2)

S –> 1 + 1 + S (2)

S –> 1 + 1 + 1 (2)

Aquesta jerarquia també es pot representar com un arbre sintàctic:

S /|\ / | \ / | \ S '+' S /|\ | / | \ | S '+' S '1' | | '1' '1'

I així, de la mateix manera podríem tenir la derivació per la dreta:

S -> S + S (1)

S -> 1 + S (2)

S –> 1 + S + S (1)

S –> 1 + 1 + S (2)

S –> 1 + 1 + 1 (2)

La qual definiria el següent arbre sintàctic:

S /|\ / | \ / | \ S '+' S | /|\ | / | \ '1' S '+' S | | '1' '1'

Si per una cadena del llenguatge d’una gramàtica existeix més d’un arbre possible, aleshores

direm que la gramàtica és ambigua. Normalment, aquestes gramàtiques són més difícils

d’analitzar perquè l’analitzador no pot decidir sempre quina producció aplicar.

Page 46: Títol: Generació Ordenada d’Estructures Combinatòries en

Capítol III – Generació d’Especificacions Estàndard

46

Podem dir també que, una gramàtica que no genera la cadena buida pot ser transformada en

un equivalent (que genera el mateix llenguatge) en Forma Normal de Chomsky. La

simplicitat de les regles en CNF té diverses implicacions teòriques i pràctiques. Per exemple,

donada una gramàtica lliure de context, es pot usar la seva forma normal per construir un

algorisme de cost polinomial que decideixi si una cadena forma part del llenguatge definit per

la gramàtica o no (conegut com a algorisme Cocke-Younger-Kasami, CYK).

Finalment, per tal de completar la informació presentada, llistarem quines són les propietats

més rellevants que es coneixen per a les gramàtiques lliures de context:

• Una de les definicions alternatives i equivalents de llenguatge lliure de context ens

diu que, un llenguatge és lliure de context si pot ser acceptat per autòmats no

deterministes.

• Un llenguatge pot ser també modelat com un conjunt de totes les seqüències de

terminals acceptades per la gramàtica. Aquest model ajuda a entendre les

operacions de conjunts sobre llenguatges.

• La unió i concatenació de dos llenguatges lliures de context és també lliure de

context. Ara bé, la intersecció no té perquè ser-ho.

• L’invers d’un llenguatge lliure de context és també lliure de context, però el

complement no té perquè ser-ho.

• Els llenguatges regulars són lliures de context perquè poden ser descrits mitjançant

una gramàtica regular.

• La intersecció d’un llenguatge lliure de context i un llenguatge regular és sempre

lliure de context.

• Existeixen llenguatges sensibles al context que no són lliures de context.

• Per a demostrar que un llenguatge donat no és lliure de context, es pot usar el Lema

del Bombeig per a llenguatges lliures de context.

• El problema de determinar si una gramàtica sensible al context descriu un llenguatge

lliure de context és indecidible.

Com a curiositat, dir que les gramàtiques lliures de context (context free) permeten

descriure la majoria dels llenguatges de programació (de fet, la sintaxis de la majoria dels

llenguatges de programació està definida mitjançant gramàtiques lliures de context). Per

altra banda, aquestes gramàtiques són prou senzilles com per permetre el disseny

d’algorismes d’anàlisi sintàctic que, per exemple per a una cadena de caràcters donada,

determini com pot ser generada des de la gramàtica. És per aquesta potència que tenen

aquest tipus de gramàtiques que, els implementadors de les llibreries de MuPAD, van decidir

que la millor manera de generar especificacions estàndard era mitjançant la CNF (la qual

cosa els va permetre implementar amb eficiència l’algorisme de comptatge, afectant de rebot

l’eficiència de tots aquells mètodes que també el feien servir, com per exemple els algorisme

d’unrank i rank).

Page 47: Títol: Generació Ordenada d’Estructures Combinatòries en

PFC – Generació Ordenada d’Estructures Combinatòries en “MuPAD-Combinat”

47

3 Algorisme per a la Generació d’Especificacions Estàndard

En aquest apartat veurem en detall les diferents parts de l’algorisme que s’ha implementat

per a l’obtenció de l’especificació estàndard a partir de l’especificació donada per l’usuari

([1], [2], [3], [14] ).

El primer que trobem en l’algorisme (cod.1) és una definició de tipus. És a dir, quin és el

format que volem que tingui una especificació no estàndard (o estàndard) per tal de poder

tractar-la i acabar convertint-la en estàndard. En aquest cas i seguint les passes del sistema

MuPAD, acceptarem com a especificació qualsevol conjunt, llista ó taula d’equacions

(producció del tipus <lhs> = <rhs>)3.

cod.1

Specification:= Type::Union(Type::SetOf(Type::Equation(DOM_IDENT)),Type::ListOf (Type::Equation(DOM_IDENT)),Type::TableOf(DOM_IDENT))

A continuació, per tal de facilitar-nos una mica les tasques posteriors, s’ha creat una taula

(cod.2) amb aquells constructors que nosaltres considerarem. Qualsevol especificació que

faci ús d’un constructor que no aparegui en aquesta taula, no serà acceptada. A més, en

aquesta taula, emmagatzemem informació addicional que ens serà útil més endavant per tal

de comprovar que l’especificació introduïda és correcte. Més concretament, emmagatzemem

informació sobre quants no terminals pot acceptar el constructor i quantes restriccions pot

portar. En el nostre cas, existeixen dos factors de disseny importants a comentar:

1. Només permetem 3 restriccions (MinLength, Length i MaxLength, és a dir, restriccions a

la cardinalitat) per als quals, tan sols podrem usar l’operador d’igualtat (queden

descartats doncs els operadors <, <=, => i >) i mai se’n podrà tenir més d’un a la

vegada.

2. La Unió i el Producte, permetrem que l’usuari ens introdueixi expressions no binàries

(per exemple, B = Union(A,B,C) ó T = Prod(Z,Z,Z)), tot i que, internament (en el nostre

desenvolupament de la taula CNS), els productes els convertirem en un seguit de

productes binaris per motius d’eficiència.

cod.2

//Constructors. //Taula de constructors de classe disponibles. constructors:=map(table( Primitive = table(NonTerminals=0, Extras=1..4), Union = table(NonTerminals=Any, Extras=0), Prod = table(NonTerminals=Any, Extras=0), BoxedProd = table(NonTerminals=Any, Extras=0),

3 En MuPAD una taula es defineix mitjançant el mètode table(index1 = val1, index2 = val2, ...) i per tant, indirectament, el contingut d’una taula ja són equacions.

Page 48: Títol: Generació Ordenada d’Estructures Combinatòries en

Capítol III – Generació d’Especificacions Estàndard

48

Sequence = table(NonTerminals=1, Extras=0..3), Set = table(NonTerminals=1, Extras=0..3), Multiset = table(NonTerminals=1, Extras=0..3), Powerset = table(NonTerminals=1, Extras=0..3), Cycle = table(NonTerminals=1, Extras=0..3) ), proc(t: DOM_TABLE) : DOM_TABLE begin if domtype(t[Extras]) = DOM_INT then t[Extras] := t[Extras] .. t[Extras]; end_if; t end_proc );

Tot seguit, es presenta la funció principal per a l’obtenció d’especificacions estàndard. Els

paràmetres que accepta la funció són els següents:

spec: aquest paràmetre, de tipus Specification, conté l’especificació introduïda per

l’usuari que volem estandaritzar.

label: mitjançant aquest paràmetre de tipus booleà, l’usuari ens indica si la classe

que està especificant és o no etiquetada. Per defecte, el valor d’aquest paràmetre és

False.

bustrofedic: per tal de què l’usuari ens pugi indicar l’ordre de generació dels àtoms

per als objectes d’aquesta classe, l’usuari pot fer servir aquest paràmetre. Per

defecte, aquest paràmetre es trobarà a False, indicant que per defecte l’ordre serà el

lexicogràfic.

MNT: normalment, entendrem que el principal no terminal (el símbol inicial), serà el

primer no terminal que ens trobem a l’especificació. Emperò, en alguns casos,

l’usuari podrà voler canviar el símbol inicial. Si l’usuari no ho canvia, el valor per

defecte d’aquest paràmetre és 1 i per tant, el codi agafa el primer no terminal com a

símbol inicial; altrament agafarem el valor introduït per l’usuari (prèvia comprovació

de què el no terminal designat per l’usuari com a símbol inicial existeixi en

l’especificació).

En resum, el que fa aquest fragment de codi és preparar els paràmetres auxiliars i les

diverses taules que es necessitaran per obtenir el resultat final, invocar la funció de

comprovació per tal d’assegurar-nos de què l’especificació donada per l’usuari no contingui

errors i, finalment, invocar la funció generador de l’especificació estàndard pròpiament dita.

cod.3

//Funció principal per adaptar l'especificació al format que ens interessa. generaEspecificacioEstandard:=proc(spec:Specification, label = FALSE, bustrofedic = FALSE, MNT = 1) local i, auxil, b, taulaCNS, t, taula; begin t :=[];

Page 49: Títol: Generació Ordenada d’Estructures Combinatòries en

PFC – Generació Ordenada d’Estructures Combinatòries en “MuPAD-Combinat”

49

//Invoquem el mètode per a la inicialització de la taula principal de l'especificació estàndard i //de la taula auxiliar . t := iniciaTaulesPrincipals(spec, label, bustrofedic, MNT); taula := indexval(t,1); taulaCNS := indexval(t,2); auxil := indexval(t,3); //Per cada una de les produccions existents en l’especificació original, en comprovem uns //mínims de correctesa invocant el mètode de comprovació, per tal d’evitar trobar-nos amb //especificacions mal construïdes. Al mètode comprova, li passem com a paràmetres la part //esquerra de cada una de les produccions i la taula auxiliar. i := 1; while i <= nops(taula) do b := comprova(op(op(taula,i),2),taula); if not(b) then error("S'ha trobat una incorrecció en l'especificació"); end_if; i := i + 1; end_while; //Mitjançant la variable auxil (que es modifica en el mètode d’inicialització de taules) verifiquem //si el no terminal introduït per l’usuari com a símbol inicial existeix o no en l’especificació. En cas //de què no existeixi, retornem un error. if (auxil = 1) then error("S'ha trobat un error en l'especificació: el MainNonTerminal no apareix a l'especificació"); else end_if; //Invoquem el mètode que generarà les subclasses per a l’expressió en format estàndard, és a //dir, el mètode que ens retornarà l’especificació estàndard en si. taula := generaEspecificacio(taula, label); //Ja només queda eliminar la taula auxiliar utilitzada, i assignar l’especificació correctament //estandarditzada a la taula CNS que retornarem. Aquesta taula restultant, al mateix temps //contindrà la informació que ens hagi passat l’usuari (o la per defecte), és a dir, contindrà //l’especificació inicial, el paràmetre label, el paràmetre bustrofedic i el paràmetre MNT. delete taula[origenPrimitive]; taulaCNS[spec]:=taula; return(taulaCNS); end_proc;

Un cop vista ja la funció principal, anem a veure en detall quines són les funcions auxiliars

que li ajuden a dur a terme el seu comès.

La primera funció que veurem i de la qual ja hem parlat una mica, és la funció utilitzada per

la inicialització de les taules i paràmetres necessaris per a l’estandardització.

cod.4

iniciaTaulesPrincipals:=proc(spec, label, bustrofedic, MNT) local t, taula, taulaCNS, auxil; begin //En un principi, per dur a terme l’estandardització de l’especificació farem ús de la taula auxiliar //denominada taula. Quan l’especificació es trobi en el format correcte, passarem a //emmagatzemar-la (com a definitiva) a la taulaCNS. //D’entrada, suposarem que el no terminal MNT no està present en l’especificació donada. auxil := 1; //Posarem a la nostra taula auxiliar una entrada que ens serà sempre vàlida segons la notació //estàndard, entenent doncs que l’identificador Z és un Àtom.

Page 50: Títol: Generació Ordenada d’Estructures Combinatòries en

Capítol III – Generació d’Especificacions Estàndard

50

taula[Z] := Primitive(1,Z); //Emmagatzemarem a la taulaCNS els paràmetres introduïts per l’usuari per tal de poder //conslultar-nos en mètodes posteriors. taulaCNS[labelled] := label; taulaCNS[ordreBustrofedic] := bustrofedic; //Si l’usuari no ens ha introduït cap valor per al paràmetre MNT (recordem que el valor per //defecte era 1), entenem que el primer no terminal que trobem en l’especificació introduïda //serà el MNT desitjat per l’usuari. if (MNT = 1) then taulaCNS[MainNonTerminal] := lhs(op(spec,1)); else taulaCNS[MainNonTerminal] := MNT; end_if; //A continuació, fem servir un bucle amb dos propòsits: primer, aprofitant que recorrerem totes //les produccions de l’especificació, corroborarem que el MNT existeixi en aquesta; segon, farem //una petita modificació en aquelles produccions que facin servir els constructors Atom i Epsilon. for prod in spec do //En el moment en què trobem una producció la part esquerra de la qual sigui igual al MNT, //haurem comprovat que aquest símbol inicial existeix en l’especificació. if (contains({taulaCNS[MainNonTerminal]},lhs(prod))) or (contains({Z},MNT)) then auxil := 2; end_if; //Donat que els constructors Atom i Epsilon poden ser usats de manera diferent, fem servir aquest //petit fragment de codi per unificar-ne el format i així facilitar-nos les tasques posteriors. Els tres //formats amb què ens podem trobar són, per exemple: // · X = Atom volem el format X = Atom(X). // · X = Atom() volem el format X = Atom(X). // · X = Atom(Y) ja ens està bé el format. //Així, cada branca del condicional tracta un dels casos. En el primer, el que farem serà //assegurar-nos de què el que tenim a la banda dreta és un identificador de nom Atom o Epsilon //i després guardar una entrada a la taula auxiliar construïda en el format que ens interessa; en //el segon cas, verifiquem que s’ha usat el constructor Atom o Epsilon sense cap paràmetre, i //guardem a la taula auxiliar una entrada en el format correcte; en el tercer ens és igual el //constructor que s’hagi fet servir, ja que l’únic que fem és introduir la informació de la producció //en la taula auxiliar. if (testtype(rhs(prod),DOM_IDENT) and (contains({Atom,Epsilon},rhs(prod)))) then taula[lhs(prod)] := rhs(prod)(lhs(prod)); elif ((op(rhs(prod),0) = Atom) and (nops(rhs(prod)) = 0)) or ((op(rhs(prod),0) = Epsilon) and (nops(rhs(prod)) = 0)) then taula[lhs(prod)] := op(rhs(prod),0)(lhs(prod)); else taula[lhs(prod)] := rhs(prod); end_if; end_for; //Finalment, el resultat que tornarem amb aquesta funció serà una taula de tres posicions, amb //la informació bona resultant. És a dir: els primers passos d’estandardització duts a terme que es //troben en la taula auxiliar estaran a la primera posició de la taula a retornar; les variables que //afecten a la especificació introduïdes per l’usuari que s’han guradat a la taulaCNS es trobaran //a la segona posició de la taula a retornar; i finalment, el paràmetre que fem servir per validar la //variable MNT, ocuparà la tercera posició de la taula a retornar. t := table(1 = taula,2 = taulaCNS,3 = auxil); return(t); end_proc;

A continuació, veurem el codi encarregat de fer les comprovacions mínimes per assegurar

que l’especificació introduïda per l’usuari és correcte.

Page 51: Títol: Generació Ordenada d’Estructures Combinatòries en

PFC – Generació Ordenada d’Estructures Combinatòries en “MuPAD-Combinat”

51

cod.5

//Funció per comprovar alguns trets bàsics de les especificacions introduïdes comprova:=proc(expr, taula): DOM_BOOL local i, j, aux, tAux, b, nonTerms; begin //La primera comprovació que realitzarem serà sobre els constructors Atom i Epsilon. if contains({Atom,Epsilon}, op(expr,0)) then //Per a aquests dos constructors, només acceptarem aquelles formes que continguin 1 o menys //paràmetres. En cas de què això no s’acompleixi, llençarem un missatge d’error on s’informarà //a l’usuari del motiu d’error. If nops(expr) = 0 then return(TRUE); elif nops(expr) > 1 then error("El constructor “.op(expr,0).” no pot portar tants operands."); return(FALSE); //Si el nombre de paràmetres és l’adequat, ara només ens cal comprovar que els possibles //identificadors de no terminals usats en la crida a Atom/Epsilon no estigui repetits (ja siguin usats) //en algun altre punt de l’especificació. Per fer això, procedim a crear una taula auxiliar on //copiem el contingut de la taula passada com a paràmetre en el propi mètode. Aleshores //poden passar dues coses: que l’expressió Atom/Epsilon sigui un paràmetre d’un constructor, o //què siguin el constructor usat en la pròpia expressió. En el primer cas, la funció auxiliar ens //retornarà el valor -1, altrament recuperarem la posició en la taula de l’expressió que estem //comprovant. Consultant el nombre de vegades en què apareix el paràmetre/identificador //que acompanyi al constructor Atom/Epsilon, determinarem si aquest es troba repetit en //l’especificació. En cas de què ja existeixi en la taula, haurem d’informar a l’usuari de què ha //usat un identificador de no terminal repetit. else tAux := taula; aux := origenExpr(expr, taula); if aux = -1 then aux := aparicionsNonTerminal(op(expr,1),tAux); if aux > 0 then error("No es pot assignar l'identificador ".op(expr,1)." a ".op(expr,0)." perquè ja identifica un no terminal"); else return(TRUE); end_if; else delete(tAux[lhs(op(taula,aux))]);aux := aparicionsNonTerminal(op(expr,1),tAux); if aparicionsNonTerminal(op(expr,1),tAux) > 0 then error("No es pot assignar l'identificador ".op(expr,1)." a “.op(expr,0).” perquè ja identifica un no terminal"); else return(TRUE); end_if; end_if; end_if; else i := 1; //Si l’operand 0, és a dir el constructor, no existeix (FAIL), això vol dir que estem tractant amb un //identificador a seques. if op(expr,0) = FAIL then //Primer de tot, comprovarem que no tinguem els constructors Atom i Epsilon sense operands. En //cas de tenir-los, els donarem per bons. if contains({Atom},expr) or contains({Epsilon}, expr) then return(TRUE);end_if; //En aquest punt, sabem que no estem tractant amb els constructors Atom i Epsilon. //Ara, ja tan sols ens cal consultar si a la taula passada com a paràmetre existeix aquest no //terminal o no. En cas de què no existeixi, informarem a l’usuari de l’error mitjançant un //missatge.

Page 52: Títol: Generació Ordenada d’Estructures Combinatòries en

Capítol III – Generació d’Especificacions Estàndard

52

while i <= nops(taula) do if op(op(taula,i),1) = expr then return(TRUE); end_if; i := i + 1; end_while; error("L’identificador “.expr.” de no terminal no està definit a l’especificació"); return(FALSE); else //Si l'expressió està composta per un o més constructors, hem de mirar recursivament, si tots els //no terminals que utilitzen/apareixen existeixen realment en la taula introduïda com a //paràmetre. Per fer això, primer farem ús de la informació emmagatzemada en la taula //constructors de la qual ja hem parlat anteriorment. Donat que ara, els constructors que ens //podem trobar és possible que portin també paràmetres extres (recordem que acceptem //algunes restriccions a la cardinalitat), hem de tenir en compte quins paràmetres són //identificadors de no terminals, i quins són informació extra. Així, el primer que farem serà //assabentar-nos del nombre de no terminals que té realment l’expressió i per fer-ho tenim //l’avantatge de saber que, per als constructors que permeten qualsevol nombre de paràmetres //(Any), no permetrem extres, i per tant, tindrem tants no terminals com ens retorni el mètode //nops (nombre d’operands) aplicat a l’expressió. Per als que si permeten extres, agafarem el //valor consultat a la taula de constructors. nonTerms := constructors[op(expr,0)][NonTerminals]; if nonTerms = Any then aux := nops(expr); else aux := nonTerms; end_if; //Ara caldrà que, per cada un dels paràmetres que no siguin extres que hi hagi en el //constructor, fem una crida de nou a la funció de comprovació per assegurar-nos de la //correctesa. while i <= aux do b := comprova(op(expr,i), taula); if not(b) then

error("El terminal no existeix");return(FALSE); end_if; i := i + 1; end_while; if contains({Primitive},op(expr,0)) then return(TRUE); end_if; //Un cop ens hem assegurat de la correctesa dels paràmetres, ara ens cal validar els possibles //extres que l’usuari hagi pogut usar. La primera comprovació doncs, consistirà en verificar que //ens hagin passat un nombre d'extres adequat al constructor. Consultarem la taula de //constructors per assabentar-nos de quants extres s’esperen, i per altra banda, obtindrem el //nombre d’extres reals (restant el nombre real d’operands del constructor del nombre de //paràmetres obtingut anteriorment). En cas de què els extres esperats no es corresponguin amb //els extres reals, informarem a l’usuari mitjançant un missatge d’error. extrasExpected := constructors[op(expr,0)][Extras]; extras := nops(expr) - aux; if (op(extrasExpected,1) <= extras and extras <= op(extrasExpected,2)) or (extras = 0) then else error("El nombre d'extres no és l'adequat per al constructor ". op(expr,0));return(FALSE); end_if; //Per tal de comprovar els extres, cal recordar que hem dit que tan sols admetríem l’ús dels //restrictors de cardinalitat MinLength, MaxLength i Length. A més, tan sols permetrem igualtats //en la seva utilització. El que farem doncs per a comprovar tot això serà crear una taula auxiliar, //on emmagatzemarem informació del nombre d’aparicions i el valor introduït per l’usuari de //cada extra. t := table(MinLength = 0, MaxLength = 0, Length = 0); i := aux + 1; j := 1;

Page 53: Títol: Generació Ordenada d’Estructures Combinatòries en

PFC – Generació Ordenada d’Estructures Combinatòries en “MuPAD-Combinat”

53

//Recorrem els extres del constructor... while (j <= extras) do //Permetrem que l’usuari ens doni els extres de dues maneres. Per exemple, Length = 2 ó 2 = //Length. Per tant, el primer que farem serà mirar si la banda dreta o la banda esquerra de //l’extra que estem tractant conté alguns dels extres esperats. En cas de què no el contingui //informem a l’usuari mitjançant un missatge d’error. if (not(contains({Length},lhs(op(expr, i))))) and (not(contains({MinLength},lhs(op(expr, i))))) and (not(contains({MaxLength},lhs(op(expr, i))))) then if (not(contains({Length},rhs(op(expr, i))))) and (not(contains({MinLength},rhs(op(expr, i))))) and (not(contains({MaxLength},rhs(op(expr, i))))) then

error("Els extres passats no es corresponen amb els esperats (Length, MinLength, MaxLength)");return(FALSE);

//En cas de què si contingui un dels extres esperats, emmagatzem la informació.

else t[rhs(op(expr, i))] := t[rhs(op(expr, i))] + 1; t[rhs(op(expr, i)).val] := op(expr, i); end_if; else t[lhs(op(expr, i))] := t[lhs(op(expr, i))] + 1; t[lhs(op(expr, i)).val] := op(expr, i); end_if; i := i + 1; j := j + 1; end_while; //Ara, cal recórrer les tres primeres posicions de la taula auxiliar que és on es guarden el nombre //d’aparicions de cada extra. i := 1; while (i <= 3) do if op(op(t,i),2) > 1 then

error("L’extra “.op(op(t,i),1).” està repetit");return(FALSE); end_if; i := i + 1; end_while; //Ara, ens cal veure que l’usuari no hagi combinat els extres entre ells mitjançant combinacions //impossibles sobre la cardinalitat. En el nostre cas, no permetrem cap combinació de l’extra //Length amb cap altre extra. Per verificar això, mirarem que no es donin a la vegada aparicions //de l’extra Length i dels altres extres en la taula auxiliar.

if (t[Length] = 1) and ((t[MinLength] = 1) or (t[MaxLength] = 1)) then error("No és possible combinar l'extra Length amb els extres MinLength o

MaxLength");return(FALSE); end_if; if (t[Length] = 0) and ((t[MinLength] = 1) and (t[MaxLength] = 1)) then if rhs(t[MinLengthval]) > rhs(t[MaxLengthval]) then

error("L'extra MinLength no pot tenir un valor més gran que l'extra MaxLength");return(FALSE); end_if; end_if; //És en aquest moment quan ens cal comprovar que l’usuari hagi introduït els extres mitjançant //l’operador d’igualtat.

if t[Length] = 1 then if (not contains({op(t[Lengthval],0)},op(x=x,0))) then error("L’extra Length ha de venir definits com a igualtats"); return(FALSE); end_if; end_if;

Page 54: Títol: Generació Ordenada d’Estructures Combinatòries en

Capítol III – Generació d’Especificacions Estàndard

54

if t[MinLength] = 1 then if (not contains({op(t[MinLengthval],0)},op(x=x,0))) then error("L’extra MinLength ha de venir definits com a igualtats"); return(FALSE); end_if; end_if; if t[MaxLength] = 1 then if (not contains({op(t[MaxLengthval],0)},op(x=x,0))) then error("L’extra MaxLength ha de venir definits com a igualtats"); return(FALSE); end_if; end_if; //Finalment, dues comprovacions per al cas concret del constructor Cycle que utilitzi extres. //Donat que la longitud per a un cicle no pot ser mai 0, ens hem d’assegurar que l’usuari no ens //hagi introduït una restricció sobre la cardinalitat que imposi això. És a dir, hem de mirar que, per //als paràmetres Length i MaxLength, el valor introduït no sigui 0. Per a MinLength, no ho mirarem //en aquest moment ja que, el fet de què l’usuari ens hagi dit que la longitud mínima sigui 0, no //implica que els cicles que creï a partir d’aquesta especificació hagin de tenir forçosament una //longitud 0. if (op(t[Lengthval],2) = 0 or op(t[Lengthval],1) = 0) and (op(expr,0) = Cycle) then

error("La longitud per a un cicle no pot ser 0"); end_if; if (op(t[MaxLengthval],2) = 0 or op(t[MaxLengthval],1) = 0) and (op(expr,0) = Cycle) then

error("La longitud per a un cicle no pot ser 0"); end_if; //En cas de què haguem arribat fins a aquest punt, retornarem el valor cert, que significa que //l’especificació acompleix els mínims imposats per estar correctament definida. return(TRUE); end_if; end_if; end_proc;

Cal doncs, que ara vegem les funcions auxiliars que s’han fet servir per a la comprovació de

l’especificació, que han estat dues: origenExpr, que ens retorna la posició dins una taula que

ocupa l’expressió, i aparicionsNonTerminal, que ens retorna el nombre d’aparicions d’un cert

no terminal en una taula.

cod.6

origenExpr := proc(expr,taula) local i, j, b; begin //Bàsicament, aquesta funció realitza un recorregut per la taula que ens han passat com a //paràmetre. Mentre no trobem l’expressió buscada anem incrementant un comptador. Si en //algun moment trobem l’expressió, posem el valor cert a un booleà, el qual ens servirà al final //de la funció per tal de determinar si el valor ha retornar ha de ser un -1 (significant que no hem //trobat l’expressió com a tal a la taula i que, per tant, aquesta expressió existeix com a //paràmetre d’un altre constructor), o el valor del comptador (que ens indica la posició de //l’expressió dins de la taula). i := 1; b:= FALSE; while (i <= nops(taula)) do if rhs(op(taula,i)) = expr then b := TRUE; j := i; end_if;

Page 55: Títol: Generació Ordenada d’Estructures Combinatòries en

PFC – Generació Ordenada d’Estructures Combinatòries en “MuPAD-Combinat”

55

i := i + 1; end_while; if b then

return(j); else

return(-1); end_if; end_proc; cod.7

aparicionsNonTerminal := proc(nT,taula) local i, n; begin //Aquesta funció també és molt senzilla. Recorre la taula i cada vegada que troba una aparició //a la taula del no terminal que ens han passat com a paràmetre, incrementa el comptador que //finalment retornarem com a resultat. i := 1; n := 0; while i <= nops(taula) do if lhs(op(taula,i)) = nT then n := n + 1; end_if; i := i + 1; end_while; return(n); end_proc;

Ara és el torn de veure el mètode més complex, que és el que s’encarrega de generar

l’especificació en format estàndard. A grans trets, el que fa és recórrer la taula auxiliar on

tenim l’especificació fragmentada i, segons l’operador que es trobi, realitzarà una acció

concreta. Com ja s’ha dit, les accions que es duen a terme estan pensades per tal d’obtenir

un resultat el més semblant possible a aquell que cabria esperar si s’haguessin usat les

llibreries pròpies de MuPAD.

cod.8

generaEspecificacio := proc(taula, label) local taulaAux, taux1, taux2, taux3, n, n2, nSeq, nSeqAux, nSet, nSetAux, nCyc, i, j, k, kaux, auxil, aux, aux2, aux3, nonTerms, URE_cont, b, s, constructor, opers, tempo; begin //Primerament, ens trobem la inicialització de les diverses variables que seran usades en aquesta //funció. Bàsicament, existeixen dos tipus: taules auxiliars, que ens ajudaran en moments //concrets en què vulguem realitzar alguna crida a un mètode que hagi d’acceptar i retornar //diversos paràmetres; després tenim un seguit de variables que ens serviran com a comptadors //per tal de desenvolupar els diversos constructors (com puguin ser les seqüències o els cicles) en //subexpressions. URE_cont := 1; n := 1; nCyc := 1; nSeq := 1; nSet := 1; nSeqAux := 0; nSetAux := 0; aux3 := 0; taux1 := []; taux2 := []; taux3 := []; taulaAux := []; //Per tal d’optimitzar una mica l’especificació resultant, i donat que en molt casos ens //apareixerà la referència al conjunt buit (representat com a Primitive(0)), guardarem la //referència a la posició en la taula de la primera aparició que tinguem d’aquest constructor, //per tal d’evitar de replicar-lo en posteriors operacions. Inicialitzem el valor a 0 (equivalent a dir //que encara no tenim aquest constructor). taula[origenPrimitive] :=0;

Page 56: Títol: Generació Ordenada d’Estructures Combinatòries en

Capítol III – Generació d’Especificacions Estàndard

56

//A continuació anirem recorrent la taula. És interessant observar que, en el condicional del //bucle, hem hagut d’usar l’operador nops (nombre d’operands). Això és degut a que, com que //la mida de la taula anirà creixent a mesura que anem afegint subexpressions a la taula, //aquestes noves subexpressions també hauran de ser tractades (ja que poden, al seu torn, //generar noves subexpressions). i := 1; taula[origenPrimitive] :=0; while i <= nops(taula) do if contains({origenPrimitive},lhs(op(taula,i))) then //Ens hem de saltar aquesta posició de la taula, ja que l’hem creat nosaltres i sabem que no s’ha //d’estandarditzar de cap manera. else //En cas de què la posició de la taula que estem tractant no posseeix cap constructor, llencem //una crida a la funció que s’encarregarà d’aquest cas particular. if op(op(op(taula,i),2),0) = FAIL then taula := casSenseConstructor(taula, i); else //En aquest punt estem segurs que la posició conté un constructor. Ara caldrà veure quin és, ja //que caldrà tractar-ne alguns de manera especial, i als que no calgui, mirar si es poden //simplificar els seus paràmetres d’alguna manera. Per tant, el primer a fer és guardar el //constructor de l’expressió actual en una variable per poder consultar-la en qualsevol moment. constructor := op(op(op(taula,i),2),0); //Preparem una llista buida per tal de poder emmagatzemar els paràmetres finals que haurà de //posseir el constructor un cop se’ls hi hagin aplicat tots els canvis necessaris.

opers:=[]; //En cas de què el constructor que ens trobem sigui Primitive, si veiem que aquest no es troba //associat a cap no termina concretl, en guardarem la posició a origenPrimitive. if constructor = Primitive then

if nops(op(op(taula,i),2)) = 1 then taula[origenPrimitive] := op(op(taula,i),2); end_if; elif constructor = Atom then //Si el constructor és Atom, el reescriurem al seu format estàndard. Per exemple, donada la //següent expressió Q = Atom(Red), la reescriuríem com Q = Primitive(1, Red). taula[lhs(op(taula,i))] := Primitive(1,op(rhs(op(taula,i)),1)); elif constructor = Epsilon then //De manera similar al cas anterior, si el constructor és Epsilon, el reescriurem al seu format //estàndard. Per exemple, donada la següent expressió Q = Epsilon(Green), la reescriuríem com //Q = Primitive(0, Green). taula[lhs(op(taula,i))] := Primitive(0,op(rhs(op(taula,i)),1)); else //Ara ja sabem que els constructors que ens podem trobar ja seran més complicats de tractar. //Ens guardem certa informació referent a cada un d’ells (extreta, com abans de la taula de //constructors) que ens podrà fer falta més endavant. nonTerms := constructors[constructor][NonTerminals]; if nonTerms = Any then aux2 := nops(op(op(taula,i),2)); else aux2 := nonTerms; end_if; //Començarem per tractar el cas del constructor Prod. Per aquest, ens és igual si l’usuari ens l’ha //introduït en format binari o no, però per tal de tenir l’especificació estandaritzada, cal que el //producte sigui binari. Per tant, si veiem que el constructor és Prod i que el nombre de //paràmetres és més gran que 2, invocarem la funció que s’encarregarà de “binaritzar” el //producte. Donat que en “binaritzar” el producte ens apareixeran noves produccions a la taula, //ens caldrà d’alguna manera, assignar nous noms a aquestes produccions. Això ho farem a //través de, en el cas del producte, la variable n, que s’incrementarà segons les noves //produccions generades a raó de la següent funció: //nombre de noves produccions = 2 * (nombre de paràmetres – 2).

Page 57: Títol: Generació Ordenada d’Estructures Combinatòries en

PFC – Generació Ordenada d’Estructures Combinatòries en “MuPAD-Combinat”

57

if (constructor = Prod) and (aux2 > 2) then n2 := n + 2 * (nops(op(op(taula,i),2)) - 2); taula := construeixTaulaPerProd(op(taula,i),n, taula); n := n2; //En cas de què el constructor sigui Sequence, invocarem en aquest moment la funció per a //desenvolupar-ne la construcció. L’únic detall a tenir en compte aquí és que la funció serveix a //la vegada per als Sets i les Seqüències, per tant, un dels paràmetres (el segon) serveix per //diferenciar quin cas estem tractant. L’altre paràmetre, consisteix en una taula auxiliar on //s’emmagatzemen totes aquelles variables que ens podrien fer falta a l’hora de desenvolupar //les seqüències en concret (per exemple, una de les posicions conté un comptador que, de //manera similar al que passava amb els productes, ens permet mantenir un control de les //subproduccions generades). elif (constructor = Sequence) then //Cal que primer, ens assegurem que la classe que acompanya a la seqüència no vingui //donada com una especificació. Si és així, arreglarem el format creant una nova subproducció. if op(op(rhs(op(taula,i)),1),0) <> FAIL then aux3 := op(taula,i); taula[sub.URE_cont] := op(rhs(aux3), 1);kaux := []; kaux := append(kaux, sub.URE_cont); for k from 2 to nops(rhs(aux3)) do kaux := append(kaux,op(rhs(aux3), k)); end_for; URE_cont := URE_cont + 1; taula[lhs(aux3)] := op(rhs(aux3),0)(op(kaux)); else end_if; //Preparem la taula auxiliar que s’usarà com a paràmetre en la pròxima crida... taux1 := table(1 = taula,2 = i,3 = nSeq,4 = nSeqAux,5 = aux3); taux1 := casSetSeq(taux1,2); //Recuperem els valors de les variables enviades a la funció, apropiadament modificades. taula := indexval(taux1,1); i := indexval(taux1,2); nSeq := indexval(taux1,3); nSeqAux := indexval(taux1,4); aux3 := indexval(taux1,5); //En el cas del constructor Alias, no ens cal fer res en concret. elif (constructor = Alias) then //Com ja s’ha dit, per al constuctor Set s’aprofitarà la mateixa funció que per al constructor //Sequence. Emperò, la construcció dels Sets etiquetats i no etiquetats no es realitza de la //mateixa manera i per tant, el primer a fer en aquest cas és consultar la variable label per tal //de saber davant de quina situació ens trobem. elif (constructor = Set or constructor = Multiset or constructor = Powersetconstructor = Set) then //Cal que primer, ens assegurem que la classe que acompanya al set no vingui donada com //una especificació. Si és així, arreglarem el format creant una nova subproducció. if op(op(rhs(op(taula,i)),1),0) <> FAIL then aux3 := op(taula,i); taula[sub.URE_cont] := op(rhs(aux3), 1);kaux := []; kaux := append(kaux, sub.URE_cont); for k from 2 to nops(rhs(aux3)) do kaux := append(kaux,op(rhs(aux3), k)); end_for; URE_cont := URE_cont + 1; taula[lhs(aux3)] := op(rhs(aux3),0)(op(kaux)); else end_if; //Si ens trobem en el cas etiquetat, el comportament és similar al del cas de les seqüències, és a //dir, recollim totes les variables necessàries en una taula auxiliar i invoquem la funció (tot

Page 58: Títol: Generació Ordenada d’Estructures Combinatòries en

Capítol III – Generació d’Especificacions Estàndard

58

//passant també el paràmetre que li indicarà que ens trobem davant del constructor Set) que //s’encarregarà de desenvolupar les subproduccions necessàries. Finalment, recuperem els //valors de les variables de la taula auxiliar retornada per la funció. Donat que els Sets (Multisets) i //Powersets etiquetats funcionen de la mateixa manera, no haurem de fer cap diferenciació //entre ells. if label then taux1 := table(1 = taula,2 = i,3 = nSet,4 = nSetAux,5 = aux3); taux1 := casSetSeq(taux1,1); taula := indexval(taux1,1); i := indexval(taux1,2); nSet := indexval(taux1,3); nSetAux := indexval(taux1,4); aux3 := indexval(taux1,5); //Per el cas dels Sets i Powersets no etiquetat, el que farem serà simplement deixa anotat en //l’espeficació estàndard quin operador estem fent servir. No es farà cap desenvolupament, ja //que tot el que faci referència a ells es calcularà en el moment en què faci falta més endavant. else end_if; //Per al constructor Cycle, també és necessari diferenciar entre els casos etiquetat i no etiquetat. elif (constructor = Cycle) then //Cal que primer, ens assegurem que la classe que acompanya al cicle no vingui donada com //una especificació. Si és així, arreglarem el format creant una nova subproducció. if op(op(rhs(op(taula,i)),1),0) <> FAIL then aux3 := op(taula,i); taula[sub.URE_cont] := op(rhs(aux3), 1);kaux := []; kaux := append(kaux, sub.URE_cont); for k from 2 to nops(rhs(aux3)) do kaux := append(kaux,op(rhs(aux3), k)); end_for; URE_cont := URE_cont + 1; taula[lhs(aux3)] := op(rhs(aux3),0)(op(kaux)); else end_if; //En cas de què sigui etiquetat, caldrà invocar en aquest moment la funció encarregada de //desenvolupar els constructors necessaris. Aquesta funció treballa de manera similar a les ja //vistes, és a dir, té un paràmetre que consisteix en una taula on s’emmagatzemen totes aquelles //variables necessàries per a dur a terme el seu comés, i retorna la mateixa taula amb les //variables modificades convenientment. if label then taux3 := table(1 = taula,2 = i,3 = nSet,4 = nSetAux,5 = nCyc ,6 = aux3); taux3 := casCycle(taux3); taula := indexval(taux3,1); i := indexval(taux3,2); nSet := indexval(taux3,3); nSetAux := indexval(taux3,4); nCyc := indexval(taux3,5); aux3 := indexval(taux3,6); //Donat que els cicles no etiquetats no existeixen, el que farem serà retornar un missatge d’error //informant a l’usuari. else error("No és possible tenir cicles no etiquetats.");

Page 59: Títol: Generació Ordenada d’Estructures Combinatòries en

PFC – Generació Ordenada d’Estructures Combinatòries en “MuPAD-Combinat”

59

end_if; //Un cop arribats en aquest punt, sabem que els constructors que ens trobem no s’han de //tractar de cap manera especial i per tant, passarem a simplificar, formalitzar i estandarditzar //tot allò que puguem. Això ho farem invocant la funció de simplificació estàndard, que //funciona de manera similar a les altres funcions ja vistes (és a dir, té com a paràmetre una //taula amb les variables que necessitarà i retorna la mateixa taula amb les variables //modificades). else taux2 := table(1 = taula,2 = i,3 = aux2,4 = URE_cont,5 = opers); taux2 := casSimplificacioStandard(taux2); taula := indexval(taux2,1); i := indexval(taux2,2); aux2 := indexval(taux2,3); URE_cont := indexval(taux2,4); opers := indexval(taux2,5); //Actualitzem la posició tractada en la volta del bucle while amb la informació modificada dels //seus operadors i ens preparem per donar una nova volta i tractar amb la resta d’expressions //de la taula. taula[op(op(taula,i),1)] := constructor(op(opers)); end_if; end_if; end_if; end_if; i := i + 1; end_while; //Unim la taula d’expressions amb la taula auxiliar generada en els casos dels constructors Set i //Powerset per tal d’evitar els possibles bucles infinits. taula := table(taula,taulaAux); //Retornem la taula d’expressions estandarditzades com a resultat de la funció. return(taula); end_proc;

Ara que ja hem vist el cos de la funció principal usada per a estandarditzar, anem a veure en

detall les diverses funcions utilitzades per a desenvolupar les subproduccions per als diversos

constructors que ens podem trobar.

La primera funció serà la que tractarà aquelles expressions per a les quals no s’ha trobat cap

constructor.

cod.9

casSenseConstructor := proc(taula, i) begin //Si hem arribat a aquest punt, és donat a què la funció principal ha trobat que en l’expressió no //es feia ús de cap constructor. Per tant, només ens podem trobar dos casos: que la posició que //estem mirant contingui a la seva part dreta la cadena “origenPrimitive” i per tant, no haguem //de fer res (ja que només és una posició auxiliar, que no figurarà en el resultat final a retornar a //l’usuari), o que ens trobem davant la redefinició del nom d’un no terminal. En aquest últim cas, //el que farem serà aplicar el format correcte, per exemple, suposant que tenim l’expressió X = Y, //aleshores volem obtenir el format X = Alias(Y). if contains({origenPrimitive},op(op(taula,i),2)) then

Page 60: Títol: Generació Ordenada d’Estructures Combinatòries en

Capítol III – Generació d’Especificacions Estàndard

60

//Ens hem topat amb la posició de l'OrigenPrmitive else taula[op(op(taula,i),1)] := Alias(op(op(taula,i),2)); end_if; return(taula); end_proc;

La següent funció s’encarrega de generar les subproduccions per a les seqüències i els sets.

Donat que el format per a la generació d’aquestes subproduccions és molt similar (ja que

només canvia el constructor a usar en elles), s’ha aprofitat el codi de tal manera que valgui

per als dos constructors. En la funció s’actuarà d’una o altra manera en funció del paràmetre

val, el qual ens haurà passat el mètode que l’hagi invocat.

cod.10 casSetSeq := proc(taux1, val) local s1, s2, s3, taula, i, nS, nSA, aux3; begin //Si hem arribat a aquest punt, és donat a què la funció principal ha trobat que en l’expressió es //feia ús del constructor Set o Sequence. En cas de què el paràmetre val sigui 1, ens trobem //davant del constructor Set i s’haurà de fer ús en les subexpressions del constructor BoxedProd. //Si el paràmetre té qualsevol altre valor, suposarem que ens trobem davant el constructor //Sequence, i per tant, haurem d’usar el constructor Prod. Així, de moment, el que farem serà //preparar tres strings on guardarem la informació que necessitarem per generar les //sudproduccions del resultat: a s1 el nom del constructor original de l’expressió; a s2 el prefix //amb que anomenarem cada una de les noves subproduccions; i a s3 el constructor que //usaran les subproduccions. if val = 1 then s1 := Set; s2 := NonTerminalSet; s3 := BoxedProd; else s1 := Sequence; s2 := NonTerminalSeq; s3 := Prod; end_if; //Recuperem els valors que ens ha enviat el mètode que hagi invocat aquesta funció que són: //taula, és el resultat de l’ estandardització de l’especificació fins al moment; i és la posició de la //taula on es troba l’expressió que anem a estandarditzar; nS és el comptador de subexpressions //d’aquest tipus que ens hem trobat fins al moment (combinant s2+nS és com es conformaran //les noves subexpressions); nSA és una variable auxiliar per a l’obtenció de nS; i finalment aux3, //que és una altra variable de tipus auxiliar. taula := indexval(taux1,1); i := indexval(taux1,2); nS := indexval(taux1,3); nSA := indexval(taux1,4); aux3 := indexval(taux1,5);

Page 61: Títol: Generació Ordenada d’Estructures Combinatòries en

PFC – Generació Ordenada d’Estructures Combinatòries en “MuPAD-Combinat”

61

//Primer, tractarem el cas en què la seqüència o el set hagin aparegut sense venir acompanyats //de cap restrictor de la cardinalitat. if nops(rhs(op(taula,i))) = 1 then //En el cas de què ens trobem amb un Set... if val = 1 then aux3 := op(taula,i); //Simplement generarem el seu desenvolupament estàndard (Set(A) = Union(ε , BoxedProd(A, //Set(A)) ) tenint en compte si existeix un origenPrimitive o no. taula[lhs(op(taula,i))] := Alias(s2.nS, _fconcat(op(rhs(op(taula,i)),0), op)); if (taula[origenPrimitive] = 0) then taula[s2.nS] := Union(s2.(nS+1),s2.(nS+2)); taula[origenPrimitive] := s2.(nS+1); taula[s2.(nS+1)] := Primitive(0); taula[s2.(nS+2)] := Alias(s2.(nS+3),op); taula[s2.(nS+3)] := s3(op(rhs(aux3),1),s2.nS); nS := nS + 4; else taula[s2.nS] := Union(taula[origenPrimitive],s2.(nS+1)); taula[s2.(nS+1)] := Alias(s2.(nS+2),op); taula[s2.(nS+2)] := s3(op(rhs(aux3),1),s2.nS); nS := nS + 4; end_if; else //Per a les Seqüències, tot funcionarà de manera similar. Generarem el seu //desenvolupament estàndard (Sequence(A) = Union(ε , Prod(A, Sequence(A)) ) tenint en //compte si existeix un origenPrimitive o no. aux3 := op(taula,i); taula[lhs(op(taula,i))] := Alias(s2.nS, _fconcat(s1,op)); if (taula[origenPrimitive] = 0) then taula[s2.nS] := Union(s2.(nS+1),s2.(nS+2)); taula[origenPrimitive] := s2.(nS+1); taula[s2.(nS+1)] := Primitive(0); taula[s2.(nS+2)] := Alias(s2.(nS+3),op); taula[s2.(nS+3)] := s3(op(rhs(aux3),1),s2.nS); nS := nS + 4; else taula[s2.nS] := Union(taula[origenPrimitive],s2.(nS+1)); taula[s2.(nS+1)] := Alias(s2.(nS+2),op); taula[s2.(nS+2)] := s3(op(rhs(aux3),1),s2.nS); nS := nS + 3; end_if; end_if; //Ara tractarem el cas en què apareguin restrictors de cardinalitat. else //Per tal de poder estandarditzar de manera correcta, hem de tenir en compte que els //constructors que estem tractant, Sequence i Set, permeten la utilització de restrcictors de la //cardinalitat, i per tant, haurem de tractar el cas de cada un dels extres permesos de manera //diferent. if contains({Length},op(op(rhs(op(taula,i)),2),1)) then //En el cas de què ens trobem amb l’extra Length, existiran també tres casos diferenciats. El //primer d’ells és quan ens demanin totes les seqüències de longitud 0. Aquí, i seguint el format //imposat per les propies llibreries de MuPAD, el que retornarem serà, suposant per exemple que //l’expressió origen sigui X = Sequence(Z, Length = 0): //X = Alias(Z, Sequence ◦ NonTerminalSeqNS) //NonTerminalSeqNS = Primitive(0), on NS és el valor de la variable nS.

Page 62: Títol: Generació Ordenada d’Estructures Combinatòries en

Capítol III – Generació d’Especificacions Estàndard

62

//En aquest cas, com podem veure, estem dient que la X no és més que un Alias per a la //composició de Sequence amb tot allò que hi hagi en la subepexpressió NonTerminalSeqNS //(que, en tractar-se del cas de Length 0, ha de ser forçosament el conjunt buit). if (op(op(rhs(op(taula,i)),2),2) = 0) then taula[lhs(op(taula,i))] := Alias(op(rhs(op(taula,i)),1), _fconcat(s1,s2.nS)); taula[s2.nS] := Primitive(0); //Donat que tan sols hem afegit una nova subexpressió, només ens cal augmentar en una unitat //la variable nS. nS := nS + 1; //Per al cas en què ens trobem amb Length = 1, encara és més senzill. Aquí, i seguint el format //imposat per les propies llibreries de Mu-PAD, el que retornarem serà, suposant per exemple que //l’expressió origen sigui X = Sequence(Z, Length = 1): //X = Alias(Z, Sequence ◦ Z). //Per tant, no ens caldrà crear cap subexpressió. elif (op(op(rhs(op(taula,i)),2),2) = 1) then taula[lhs(op(taula,i))] := Alias(op(rhs(op(taula,i)),1), _fconcat(s1,op(rhs(op(taula,i)),1))); //Finalment, tractarem el cas en què Length > 1. Aquí, i seguint el format imposat per les pròpies //llibreries de MuPAD, el que retornarem serà, suposant per exemple que l’expressió origen sigui //X = Sequence(Z, Length = 3): //X = Alias(Z, Sequence ◦ NonTerminalSeqNS1) //NonTerminalSeqNS1 = Prod(NonTerminalSeqNS2, Z)) //NonTerminalSeqNS2 = Alias(NonTerminalSeqNS3, op)) //NonTerminalSeqNS3 = Prod(Z,Z) //És a dir, suposant que Length = N, desenvoluparem a partir de NonTerminalSeqNS1 un conjunt //de subexpressions que representin els N productes del no terminal que tingui el constructor //Sequence com a paràmetre. elif (op(op(rhs(op(taula,i)),2),2) > 1) then //En nSA guardarem el valor que acompanya a Length. nSA := op(op(rhs(op(taula,i)),2),2); //Invocarem una funció auxiliar encarregada de generar el conjunt de subexpressions que //representin els N productes. taula := construeixTaulaPerSeqSet(op(taula,i),nS, taula,Length,op(op(rhs(op(taula,i)),2),2), s2, s3); taula[lhs(op(taula,i))] := Alias(s2.nS, _fconcat(s1,op)); //Per tal de mantenir el comptador nS al dia farem ús de nSA. Hem pogut observar que, el //nombre de subexpressions que es produeixen en aquest cas, sempre va en funció del valor del //paràmetre Length. Així, si el valor de Length és parell, ens hauran aparegut N – 1 noves //expressions, altrament, hauran aparegut N expressions. if _mod(nSA,2) = 0 then nS := nS + (nSA - 1); else nS := nS + nSA; end_if; end_if; //En el codi mostrat, només es veu reflectit el cas en què l’usuari hagi introduït l’expressió amb el //format Length = N. Si es volgués cobrir també el cas N = Length, caldria replicar tot el codi //substituint les crides a la funció rhs() per lhs(). //Suposem ara que l’extra utilitzat ha estat MinLength.. elif contains({MinLength},op(op(rhs(op(taula,i)),2),1)) then //En el cas de la longitud mínima, hem de tenir en compte que la idea consisteix en generar //unes subexpressions que representin la seqüència de longitud mínima designada per l’usuari i

Page 63: Títol: Generació Ordenada d’Estructures Combinatòries en

PFC – Generació Ordenada d’Estructures Combinatòries en “MuPAD-Combinat”

63

//unir-ho amb l’expressió generadora estàndard de les seqüències o sets (vista en el capítol II). //Així, sempre podrem crear seqüències més grans o iguals a la longitud mínima designada. Per //tant, el primer cas que veurem serà les seqüències de longitud mínima 0. Seguint la idea //plantejada, no ens caldrà generar cap subexpressió d’una longitud fixa, i tan sols retornarem //l’expressió generadora estàndard. En aquest cas, suposant que l’expressió d’origen que tenim //sigui X = Sequence(Z, MinLength = 0), retornarem l’expressió generadora: //X = Alias (NonTermSeqNS1, Sequence ◦ op) // NonTermSeqNS1 = Union(NonTermSeqNS2, NonTermSeqNS3) // NonTermSeqNS2 = Primitive(0) // NonTermSeqNS3 = Alias(NonTermSeqNS4, op) // NonTermSeqNS4 = Prod(Z, NonTermSeqNS1) //Mitjançant això podríem anar desenvolupant seqüències de qualsevol longitud. if (op(op(rhs(op(taula,i)),2),2) = 0) then //Com que l’expressió generador estàndard necessitarà fer referència a la posició inicial de //l’expressió, ens la guardem a la variable aux3. aux3 := op(taula,i); taula[lhs(op(taula,i))] := Alias(s2.nS, _fconcat(s1,op)); //Si no tenim cap valor emmagatzemat a la posició origenPrimitive, crearem l’expressió //Primitive(0) i en guardarem la posició a origenPrimitive. if (taula[origenPrimitive] = 0) then taula[s2.nS] := Union(s2.(nS+1),s2.(nS+2)); taula[origenPrimitive] := s2.(nS+1); taula[s2.(nS+1)] := Primitive(0); taula[s2.(nS+2)] := Alias(s2.(nS+3),op); taula[s2.(nS+3)] := s3(op(rhs(aux3),1),s2.nS); //Donat que ens han aparegut quatre noves subexpressions, incrementem el comptador en //consonància. nS := nS + 4; //Si existeix una posició per a origenPrimitive, l’aprofitem i no tornem a crear l’expressió. else taula[s2.nS] := Union(taula[origenPrimitive],s2.(nS+1)); taula[s2.(nS+1)] := Alias(s2.(nS+2),op); taula[s2.(nS+2)] := s3(op(rhs(aux3),1),s2.nS); nS := nS + 3; end_if; //En el cas de què el valor de MinLength sigui més gran que zero, la idea és crear un conjunt de //subexpressions que representin els N productes i unir-ho amb l’expressió generadora estàndard. elif (op(op(rhs(op(taula,i)),2),2) > 0) then //Si el valor de MinLength és 1, el nombre de subproduccions serà sempre 4 (només cal //modificar mínimament l’expressió generadora estàndard). if (op(op(rhs(aux3),2),2) = 1) then nSA := 4; //Altrament, el nombre de noves subexpressions que apareixeran serà sempre el valor de //MinLength multiplicat per dos i sumant-hi tres. else nSA := op(op(rhs(aux3),2),2); nSA := (nSA * 2) + 3; end_if; //Com en el cas de anterior, necessitarem guardar la posició d’origen de l’expressió. aux3 := op(taula,i); //Per tal de generar el conjunt de subexpressions que representin els N productes, fem servir la //funció auxiliar ja vista en el cas de l’extre Length. taula := construeixTaulaPerSeqSet(aux3,nS, taula,MinLength,op(op(rhs(op(taula,i)),2),2),s2,s3); taula[lhs(aux3)] := Alias(s2.nS, _fconcat(s1,op));

Page 64: Títol: Generació Ordenada d’Estructures Combinatòries en

Capítol III – Generació d’Especificacions Estàndard

64

//Incrementem el comptador de subproduccions adequadament. nS := nS + nSA; end_if; //En el cas de la longitud màxima, hem de tenir en compte que la idea consisteix en generar //totes les possibles expressions de longitud igual o inferior a la demanada i unir-les entre elles. Per //exemple, donada la següent expressió X= Sequence(Z, MaxLength = 2), generaríem: //X = Alias(NonTermSeqNS1, Sequence ◦ op) //NonTermSeqNS1 = Union(NonTermSeqNS2, NonTermSeqNS3) //NonTermSeqNS2 = Primitive(0) //NonTermSeqNS3 = Union(Z, NonTermSeqNS4) //NonTermSeqNS4 = Alias(NonTermSeqNS5, op) //NonTermSeqNS5 = Prod(Z,Z). //És a dir, generaríem 0 + Z + Z*Z. Això cobriria totes les seqüències de longitud màxima 2. elif contains({MaxLength},op(op(rhs(op(taula,i)),2),1)) then //Tenim en compte el cas en què la longitud màxima sigui 0 per tal de poder aprofitar si ja //existeix el valor d’origenPrimitive. if (op(op(rhs(op(taula,i)),2),2) = 0) then //Com sempre ens guardem l’origen de l’expressió per si ens fes falta. aux3 := op(taula,i); //Primer tractem el cas en què origenPrimitive encara no té valor assignat. if (taula[origenPrimitive] = 0) then taula[lhs(op(taula,i))] := Alias(s2.nS, _fconcat(s1,op)); taula[s2.nS] := Primitive(0); taula[origenPrimitive] := s2.nS; //Incrementem el comptador de subexpressions en una sola unitat, ja que tan sols ens ha calgut //crear la subexpressió Primitive(0). nS := nS + 1; //En aquest altre cas, no hem d’incrementar el comptador, ja que reaprofitem l’origenPrimitive. else taula[lhs(op(taula,i))] := Alias(taula[origenPrimitive], _fconcat(s1,op)); end_if; //Per al cas en què el valor de MaxLength sigui més gran que zero... elif (op(op(rhs(op(taula,i)),2),2) > 0) then //Primer ens guardem com sempre l’origen de l’expressió. aux3 := op(taula,i); //Si el valor de MaxLength és 1, aleshores de manera similar al que hem fet anteriorment, //separem el cas en què ja existeixi o no un valor per a origenPrimitive. if (op(op(rhs(op(taula,i)),2),2) = 1) then taula[lhs(op(taula,i))] := Alias(s2.nS, _fconcat(s1,op)); //En el cas de què no existeixi encara origenPrimitive, creem l’expressió a la taula i en guardem //la posició. En aquest cas, tan sols ens caldrà crear una unió entre Primitive(0) i el paràmetre del //constructor de l’expressió de inicial. if (taula[origenPrimitive] = 0) then taula[s2.nS] := Union(s2.(nS+1),op(rhs(aux3),1)); taula[s2.(nS + 1)] := Primitive(0); taula[origenPrimitive] := s2.(nS+1); //Com que en aquest cas hem afegit dues subproduccions, incrementem conseqüentment el //comptador. nS := nS + 2; else taula[s2.nS] := Union(taula[origenPrimitive],op(rhs(aux3),1)); //Aquí no ens ha calgut crear l’expressió Primitive(0) i per tant, només hem usat una nova //subexpressió. nS := nS + 1;

Page 65: Títol: Generació Ordenada d’Estructures Combinatòries en

PFC – Generació Ordenada d’Estructures Combinatòries en “MuPAD-Combinat”

65

end_if; //Per al cas que el valor MaxLength sigui més gran que 1, aleshores el que farem serà primer, //comptar quantes noves subproduccions obtenim i guardar-ne el valor a nSA. Després, //invocarem una funció auxiliar que serà l’encarregada de generar totes les subproduccions //necessàries en la taula. I finalment, incrementarem el comptador de subproduccions amb el //valor de nSA. else nSA := calculaDespla(op(op(rhs(op(taula,i)),2),2)); taula := construeixTaulaPerSeqSet(op(taula,i),nS, taula,MaxLength,op(op(rhs(op(taula,i)),2),2),s2,s3); taula[lhs(aux3)] := Alias(s2.nS, _fconcat(s1,op)); nS := nS + nSA; end_if; end_if; end_if; end_if; //Preparem la taula que retornarem emmagatzemant totes aquelles variables a les quals //haguem canviat el valor i hagin de ser reutilitzades en la funció principal. taux1 := table(1 = taula,2 = i,3 = nS,4 = nSA,5 = aux3); return(taux1); end_proc;

El següent fragment de codi és l’encarregat de generar les subproduccions referents al

constructor Cycle. El que farem serà desenvolupar l’isomorfisme per als Cicles vist en el

segon capítol ( AACycle =)( □ )(ASequence∗ ).

cod.11

casCycle := proc(taux3) local s, taula, i, nS, nSA, nC,aux3; begin //Preparem un string amb el prefix per a les subexpressions genrades d’aquest tipus. s := NonTermCyc; //Com en la funció anterior, recuperem els valors que hi ha en la taula que ens han passat com //a paràmetre: taula, és el resultat de la estandardització de l’especificació fins al moment; i és //la posició de la taula on es troba l’expressió que anem a estandarditzar; nS és el comptador de //subexpressions de tipus seqüència que ens hem trobat fins al moment; nSA és una variable //auxiliar per a l’obtenció de nS; nC és el comptador de subproduccions de tipus cicle que ens //hem trobat fins al moment (combinant s+nC és com es conformaran les noves subexpressions) i //finalment, aux3 és una altra variable de tipus auxiliar. taula := indexval(taux3,1); i := indexval(taux3,2); nS := indexval(taux3,3); nSA := indexval(taux3,4); nC := indexval(taux3,5); aux3 := indexval(taux3,6); //L’estructura també és molt similar a la vista en el cas anterior, és a dir, un condicional on en //cada branca es tracta el cas en què el constructor aparegui sol o acompanyat d’un extra. if nops(rhs(op(taula,i))) = 1 then //En cas de què el constructor aparegui sol, el que fem és desenvolupar l’isomorfisme //corresponent als Cicles, és a dir, Cycle(A) = BoxedProd(A, Sequence(A)). aux3 := op(rhs(op(taula,i)),1); taula[lhs(op(taula,i))] := Alias(s.nC, _fconcat(op(rhs(op(taula,i)),0),op)); taula[s.nC] := BoxedProd(aux3,s.(nC+1));

Page 66: Títol: Generació Ordenada d’Estructures Combinatòries en

Capítol III – Generació d’Especificacions Estàndard

66

taula[s.(nC+1)] := Alias(s.(nC+2), op); taula[s.(nC+2)] := Sequence(aux3); nC := nC + 3; else //Simplement, per al cas de l’extra Length i com ja s’ha dit, modifiquem la posició i de la taula, //usant el constructor BoxedProd. En la nova subproducció que generem, hi posem l’expressió //d’una seqüència, fent servir l’extra Length amb el seu valor inicial (emmagatzemat a aux3) //menys la unitat. Incrementem el comptador nC en una unitat per la nova subproducció //generada. if contains({Length},op(op(rhs(op(taula,i)),2),1)) then auxil := op(rhs(op(taula,i)),1); aux3 := op(op(rhs(op(taula,i)),2),2); taula[lhs(op(taula,i))] := Alias(s.nC, _fconcat(op(rhs(op(taula,i)),0),op)); taula[s.nC] := BoxedProd(auxil,s.(nC+1)); taula[s.(nC+1)] := Alias(s.(nC+2), op); taula[s.(nC+2)] := Sequence(auxil, Length = (aux3 - 1)); nC := nC + 3; //També com abans, si només permetem que l'expressió extra vingui introduïda com Length = x //no ens cal preocupar de res més. Altrament, si permetessim també x = Length, caldria replicar //el codi substituint totes les crides a la funció rhs() per lhs(). //En el cas de MinLength, la idea continua sent exactament la mateixa que en el cas anterior. //Tan sols cal destacar el fet de què, si el que tenim és que la longitud mínima és 0, aleshores, en //generar la subproducció, el valor de l’extra MinLength tindrà el valor 0 en comptes de -1. //Altrament, la generació de la subproducció es farà de manera normal (decrementant en una //unitat el valor de l’extra). elif contains({MinLength},op(op(rhs(op(taula,i)),2),1)) then auxil := op(rhs(op(taula,i)),1); aux3 := op(op(rhs(op(taula,i)),2),2); taula[lhs(op(taula,i))] := Alias(s.nC, _fconcat(op(rhs(op(taula,i)),0),op)); taula[s.nC] := BoxedProd(auxil,s.(nC+1)); taula[s.(nC+1)] := Alias(s.(nC+2), op); if aux3 = 0 then taula[s.(nC+2)] := Sequence(auxil, MinLength = (aux3)); else taula[s.(nC+2)] := Sequence(auxil, MinLength = (aux3 - 1)); end_if; nC := nC + 3; //Finalment, tot funciona de la mateixa manera per a l’extra MaxLength. elif contains({MaxLength},op(op(rhs(op(taula,i)),2),1)) then

auxil := op(rhs(op(taula,i)),1); aux3 := op(op(rhs(op(taula,i)),2),2); taula[lhs(op(taula,i))] := Alias(s.nC, _fconcat(op(rhs(op(taula,i)),0),op)); taula[s.nC] := BoxedProd(auxil,s.(nC+1)); taula[s.(nC+1)] := Alias(s.(nC+2), op); taula[s.(nC+2)] := Sequence(auxil, MaxLength = (aux3 - 1)); nC := nC + 3; end_if; end_if; //Generem la taula resultat emmagatzemant-hi totes les variables significatives que volem //retornar. taux3 := table(1 = taula,2 = i,3 = nS,4 = nSA,5 = nC, 6 = aux3); return(taux3); end_proc;

Page 67: Títol: Generació Ordenada d’Estructures Combinatòries en

PFC – Generació Ordenada d’Estructures Combinatòries en “MuPAD-Combinat”

67

El codi que veurem a continuació és l’encarregat de simplificar aquelles expressions que no

hagin estat tractades fins al moment. És a dir, aquelles expressions que no utilitzen cap dels

constructors que s’hagin de tractar específicament. Bàsicament, el que farem en aquest cas

serà fixar-nos en els paràmetres del constructor que usi l’expressió, i veure si aquests

contenen al seu temps expressions. En cas de què així sigui, substituirem l’expressió usada

com a paràmetre per un nou no terminal, i afegirem una entrada a la taula de l’especificació

on associarem el nou no terminal amb l’expressió substituïda.

cod.12

casSimplificacioStandard := proc(taux2) local s, taula, i, aux2, URE_cont, opers, j, tempo; begin //Primerament, generem un string amb el prefix que farem servir per a nombrar les noves //subproduccions. s := sub; //Com en les funcions anteriors, recuperem els valors que hi ha en la taula que ens han passat //com a paràmetre: taula, és el resultat de la estandardització de l’especificació fins al moment; //i és la posició de la taula on es troba l’expressió que anem a estandarditzar; aux2 és el nombre //d’operands que té l’expressó; URE_cont és el comptador que farem servir per a portar el //control del nombre de subexpressions d’aquest tipus existents i finalment, opers és una taula //auxiliar que ens servirà per emmagatzemar els paràmetres un cop estandarditzats (en un //principi aquesta taula està buida). taula := indexval(taux2,1); i := indexval(taux2,2); aux2 := indexval(taux2,3); URE_cont := indexval(taux2,4); opers := indexval(taux2,5); //Per cada un dels paràmetres de l’expressió actual, mirarem que podem fer... j := 1; while j <= aux2 do //Recuperem l’expressió i l’emmagatzemem a la variable tempo... tempo := op(op(op(taula,i),2),j); //Si el paràmetre que estem tractant conté el constructor Atom o Epsilon sense cap operador, //aleshores els associarem a Z (notació estàndard per Atom) i a Primitive(0) (notació estàndard //per a Epsilon). if (contains({Atom},tempo) or contains({Atom()},tempo) ) then tempo := Z; elif (contains({Epsilon},tempo) or contains({Epsilon()},tempo)) then if (taula[origenPrimitive] = 0) then taula[s.URE_cont] := Primitive(0); tempo := s.URE_cont; taula[origenPrimitive] := s.URE_cont; URE_cont := URE_cont + 1; else tempo := taula[origenPrimitive]; end_if; //Si el paràmetre està composta per algun altre constructor... else //Ens podem trobar el cas en què el paràmetre sigui tan sols per un no terminal, amb la qual //cosa no ens caldrà realitzar cap mena d’estandardització.

if op(tempo,0) = FAIL then //Altrament i arribat en aquest punt, sabem que aquest paràmetre conté un constructor, i per //tant, no hauria de ser un operador de l’expressió actual, sinó una subproducció. Per tant, el //que farem serà generar una nova subproducció l’expressió de la qual serà el paràmetre que //estem tractant.

else

Page 68: Títol: Generació Ordenada d’Estructures Combinatòries en

Capítol III – Generació d’Especificacions Estàndard

68

taula[s.URE_cont] := op(op(op(taula,i),2),j); tempo := s.URE_cont; //Com que hem afegit una nova subexpressió incrementem conseqüentment el comptador. URE_cont := URE_cont + 1; end_if; end_if; //Afegim el paràmetre tractat a la llista auxiliar d’operadors. Així, un cop aquesta llista estigui //plena, hi constaran els operadors finals per a l’expressió. opers := append(opers,tempo); j := j + 1; end_while; //Recollim els valors que ens interessa retornar en la taula resultat. taux2 := table(1 = taula,2 = i,3 = aux2,4 = URE_cont,5 = opers); return(taux2); end_proc;

El següent fragment de codi és l’encarregat de generar el conjunt de subexpressions de tipus

producte que ens apareixen en els desenvolupaments de les seqüències i sets,

desenvolupant els isomorfismes ja vistos en el capítol 2

( )()( ASequenceAASequence ∗+= ε i AASet += ε)( □ )(ASet∗ ). Bàsicament, és una

funció de tipus recursiu que, en un primer moment, esbrina quin tipus d’extra s’està

utilitzant i aleshores llença crides a si mateix per anar formant les subexpressions. Cal

recordar, que les noves subexpressions generades seran binàries.

Donat que aquesta funció ha de servir per als dos casos (seqüències i sets), s’ha codificat el

màxim de genèricament possible; així, per exemple, un dels paràmetres de la funció és

operador, el qual té per valor el nom del constructor que s’ha de fer servir en cada cas (per a

les seqüències és Prod i per als sets BoxedProd).

cod.13

construeixTaulaPerSeqSet:=proc(expr, i, taula, param, long, s, operador) local aux, opers; begin //En cas de què l’extra que estem tractant sigui Length... if (contains({Length},param)) then //Si la longitud és 2, agafem i construïm una expressió mitjançant el constructor que ens hagin //passat com a paràmetre (operador) i obtenint el no terminal que acompanya a l’expressió //principal. if long = 2 then taula[s.i] := operador(op(rhs(expr),1),op(rhs(expr),1)); //Si la longitud és més gran que 2... else if _mod(long, 2) = 0 then //Per al cas en què el valor que acompanyi a l’extra Length sigui parell, el que farem serà //construir una expressió per a la qual, els dos paràmetres de la nova expressió faran referència //a la nova subexpressió. La crida recursiva a la pròpia funció, s’haurà de fer dividint entre dos el //valor del paràmetre Length (cada subexpressió aportarà la meitat del valor de l’extra). Així

Page 69: Títol: Generació Ordenada d’Estructures Combinatòries en

PFC – Generació Ordenada d’Estructures Combinatòries en “MuPAD-Combinat”

69

//podem reaprofitar subexpressions i ens evitem de repetir-les. Això s’ha fet així per tal de seguir //el format presentat per les llibreries de Mu-PAD. taula[s.i] := operador(s.(i+1),s.(i+1)); taula[s.(i+1)] := Alias(s.(i+2),op); taula := construeixTaulaPerSeqSet(expr,i+2, taula,Length,long - 2, s, operador); //En cas de què el valor sigui senar, el que fem és crear una nova expressió on aparegui una //operació entre el paràmetre que acompanya l’expressió original i el resultat de la crida //recursiva a la pròpia funció decrementant en un la unitat que acompanya a l’extra. else taula[s.i] := operador(s.(i+1),op(rhs(expr),1)); taula[s.(i+1)] := Alias(s.(i+2),op); taula := construeixTaulaPerSeqSet(expr,i+2, taula,Length,long - 1, s, operador); end_if; end_if; //De manera molt similar, en el cas de MinLength, tractem els diferents casos segons el valor que //acompanya l’extra. elif (contains({MinLength},param)) then //Si el valor és 1, aleshores el que fem dependrà de si la posició origenPrimitive té un valor //assignat o no. if long = 1 then aux := (i+1); //Generarem el desenvolupament general per a les seqüències i sets, de manera igual a com es //genera en les pròpies llibreries de MuPAD. taula[s.i] := operador(op(rhs(expr),1),s.aux); if (taula[origenPrimitive] = 0) then taula[s.aux] := Union(s.(aux+1),s.(aux+2)); taula[origenPrimitive] := s.(aux+1); taula[s.(aux+1)] := Primitive(0); taula[s.(aux+2)] := Alias(s.i,op); else taula[s.aux] := Union(taula[origenPrimitive],s.(aux+1)); taula[s.(aux+1)] := Alias(s.i,op); end_if; else //Per al cas en què la longitud sigui més gran, caldrà que generem una nova subproducció on //es realitzarà el producte o el boxedProd entre el desenvolupament d’un conjunt de //subexpressions (de longitud igual al valor de l’extra) i l’expressió general de la seqüència o set. //Per fer això, primer determinem si el valor que acompanya a l’extra és senar o parell, ja que a //partir d’aquest, podem saber el nombre de subproduccions de tipus producte o boxedprod //que generarem. Aleshores, tan sols ens caldrà invocar una funció auxiliar que ens construirà //aquestes subproduccions, i construir la subexpressió enllaçant aquest resultat amb l’expressió //general. if (_mod(long,2)=0) then aux := long; else aux := long+1; end_if; aux := (i+1+aux); taula[s.i] := operador(s.(i+1),s.aux); taula := generaProductesOrBoxed(op(rhs(expr),1), i+1, long, taula, s, operador); //Com sempre, hem de tenir en compte si origenPrimitive ja té un valor assignat a l’hora de //construir l’expressió general. if (taula[origenPrimitive] = 0) then taula[s.aux] := Union(s.(aux+1),s.(aux+2));taula[origenPrimitive] := s.(aux+1); taula[s.(aux+1)] := Primitive(0);

Page 70: Títol: Generació Ordenada d’Estructures Combinatòries en

Capítol III – Generació d’Especificacions Estàndard

70

taula[s.(aux+2)] := Alias(s.(aux+3),op); taula[s.(aux+3)] := operador(op(rhs(expr),1),s.aux); else taula[s.aux] := Union(taula[origenPrimitive],s.(aux+1)); taula[s.(aux+1)] := Alias(s.(aux+2),op); taula[s.(aux+2)] := operador(op(rhs(expr),1),s.aux); end_if; end_if; //En el cas de MaxLength, la tasca és més senzilla, ja que la construcció de les unions de //seqüències i sets les realitzarà una funció auxiliar que tan sols necessitarà saber la longitud per //a la qual volem generar les construccions. elif (contains({MaxLength},param)) then if (taula[origenPrimitive] = 0) then taula[s.i] := Union(s.(i+1),s.(i+2)); taula[s.(i+1)] := Primitive(0); taula[origenPrimitive] := s.(i+1); taula := generaUnionsProdsOrBoxed(op(rhs(expr),1),(i+2),long,taula,s,operador); else taula[s.i] := Union(s.(i+1),s.(i+1)); taula := generaUnionsProdsOrBoxed(op(rhs(expr),1),(i+1),long,taula,s,operador); end_if; end_if; //Finalment retornem la taula que hem anat modificant, afegint les noves subproduccions. return(taula); end_proc;

El pròxim fragment de codi s’encarrega tan sols de generar un conjunt de subproduccions

que representin un producte o un boxedprod de longitud determinada, mitjançant sempre

construccions binàries. Per fer-ho, realitza crides recursives a si mateix, decrementant el

valor de longitud en cada una de les crides. El valor pel paràmetre operador tal i com ja

passava en casos anteriors i per tal d’evitar replicar codi, pot ser de dos tipus: Prod (per a

les seqüències) i BoxedProd (per als sets).

cod.14 generaProductesOrBoxed:=proc(param, a, b, taula, s, operador) local opers; begin //En el cas base, construïm la subexpressió binària formada per l’operador i la repetició del //paràmetre que acompanyava a l’expressió origen. if b = 2 then taula[s.a] := Alias(s.(a+1),op); taula[s.(a+1)] := operador(param, param); else //Per a la resta de casos, tot dependrà de si el valor que ha rebut la funció és parell o senar. taula[s.a] := Alias(s.(a+1), op); //Per al cas en què sigui parell, el que fem és generar la subexpressió binària formada per //l’operador i repetint el resultat de la crida recursiva a la pròpia funció passant el valor actual //entre dos. if (_mod(b,2)=0) then taula[s.(a+1)] := operador(s.(a+2),s.(a+2)); taula := generaProductesOrBoxed(param, (a+2), (b/2), taula, s, operador);

Page 71: Títol: Generació Ordenada d’Estructures Combinatòries en

PFC – Generació Ordenada d’Estructures Combinatòries en “MuPAD-Combinat”

71

//En el cas d’un valor senar, generem la subexpressió formada per l’operador i el paràmetre de //l’expressió original combinat amb el resultat de la crida recursiva en la pròpia funció //decrementant el valor actual en una unitat. else taula[s.(a+1)] := operador(param,s.(a+2)); taula := generaProductesOrBoxed(param, (a+2), (b-1), taula, s, operador); end_if; end_if; //Finalment retornem la taula amb totes les modificacions realitzades. return(taula); end_proc;

A continuació veurem el codi encarregat de convertir aquelles expressions de tipus Prod per

a les quals l’usuari no hagi respectat el caràcter binari. El funcionament per aquesta funció

també és recursiu, i el que fem és anar construint subexpressions formades pel producte

entre un element de l’expressió inicial i una nova subexpressió formada pel resultat de la

crida recursiva a la pròpia funció decrementant en un element l’expressió passada per

paràmetre.

cod.15

construeixTaulaPerProd:=proc(expr, i, taula) local s, opers; begin s := subProd; //Quan arribem al cas base, haurem desmontat l’expr de tal manera que ja només tindrà dos //paràmetres, i per tant, la podrem assignar directament a una subexpressió. if nops(rhs(expr)) = 2 then taula[s.(i-1)] := rhs(expr); //En cas de què l’expressió encara no sigui binària, generem una subexpressió de tipus binàri, i //llencem una crida recursiva a la pròpia funció, on el primer paràmetre serà una versió //retallada de l’expressió origen (amb retallada ens referim a què hi haurem suprimit un //element). else taula[lhs(expr)] := Prod(op(rhs(expr),1),s.i); taula[s.i] := Alias(s.(i+1),op); taula := construeixTaulaPerProd(s.(i+1)=Prod(op(rhs(expr),2),op(rhs(expr),3..nops(rhs(expr)))), i+2, taula); end_if; //Retornem la taula amb totes les modificacions realitzades. return(taula); end_proc;

Per tal de poder realitzar el desenvolupament de MaxLength de forma correcta, ens fa falta

disposar una funció tal que ens generi unions de productes (o boxedprods). Així, la següent

funció és l’encarregada de realitzar aquesta tasca mitjançant un bucle on, per cada iteració,

anirem construint conjunts de productes (cada vegada menors) que anirem unint entre ells.

cod.16

generaUnionsProdsOrBoxed:=proc(param,i,long,taula, s, operador) local j, aux; begin //Mitjançant el valor del paràmetre d’entrada long, anirem realitzant crides a la funció ja vista //generaProductesOrBoxed, la qual ens generarà conjunts de N productes (o boxedprods). //Anirem unint els resultats de les diverses iteracions decrementant el valor de la longitud fins //que, finalment, per a longitud 2 tancarem el conjunt d’Unions.

Page 72: Títol: Generació Ordenada d’Estructures Combinatòries en

Capítol III – Generació d’Especificacions Estàndard

72

while(long>2)do if (_mod(long,2) = 0) then aux := long; else aux := long + 1; end_if; taula[s.i] := Union(s.(i+aux+1), s.(i+1)); taula := generaProductesOrBoxed(param, (i+1), long, taula, s, operador); i := i + aux + 1; long := long - 1; end_while; //Generem l’última unió entre el paràmetre de l’expressió original i el producte (o boxedprod) //binàri. La unió entre aquest resultat i el conjunt buit es realitza en el mètode origen de la crida. taula[s.i] := Union(param, s.(i+1)); taula := generaProductesOrBoxed(param, (i+1), long, taula, s, operador); //Retornem la taula apropiadament modificada. return(taula); end_proc;

En el cas ja vist de la funció casSetSeq hem observat que, quan es donava la situació en què

apareixia l’extra MaxLength, a l’hora d’incrementar el comptador de noves subexpressions

generades s’ha fet ús d’una nova funció auxiliar. Això és així donat que el nombre de

subexpressions noves en aquesta situació ve determinat per la suma del nombre de

subproduccions que apareixen en les unions construïdes. Així, en la següent funció podrem

veure que per descobrir el valor amb què incrementarem el comptador, el que farem serà

utilitzar un bucle on anirem acumulant el valor del nombre de subexpressions generades per

cada producte (o boxedprod) de la unió resultant.

cod.17

calculaDespla:=proc(i) local j, aux1, aux2; begin aux := i - 1; j := 0; //Depenent de si el valor d’i és parell o senar, sumarem un valor o un altre a l’acumulador. while (i > 1) do if (_mod(i,2) = 0) then aux2 := i; else aux2 := i + 1; end_if; j := j + aux2; i := i - 1; end_while; j := j + aux; //Retornem el valor total acumulat. return(j); end_proc;

Arribats a aquest punt, ja només ens queda veure un conjunt d’operacions que consisteixen

en l’adaptació de les operacions de la pròpia llibreria de Mu-PAD per tal de què aquestes

puguin funcionar mitjançant la meva pròpia estructura d’especificació. Així, per cada una de

les operacions, s’ha invocat una crida a l’equivalent de Mu-PAD desmuntant la meva

Page 73: Títol: Generació Ordenada d’Estructures Combinatòries en

PFC – Generació Ordenada d’Estructures Combinatòries en “MuPAD-Combinat”

73

estructura de manera que s’adapti al format del mètode desitjat, i retornant directament el

resultat generat per les funcions de la llibreria combinat.

cod.18

//Adaptació d'operacions per a què puguin funcionar amb la meva estructura d'especificació. generadorAdaptat:=proc(spec,n) local aux; begin aux := combinat::decomposableObjects(lhs(op(spec,4)),Labelled = (rhs(op(spec,1)))); return(aux::generator(n,rhs(op(spec,3)))); end_proc;

cod.19 countAdaptat:=proc(spec,n) local aux; begin aux := combinat::decomposableObjects(lhs(op(spec,4)),Labelled = (rhs(op(spec,1)))); return(aux::count(n,rhs(op(spec,3)))); end_proc; cod.20

listAdaptat:=proc(spec,n) local aux; begin aux := combinat::decomposableObjects(lhs(op(spec,4)),Labelled = (rhs(op(spec,1)))); return(aux::list(n,rhs(op(spec,3)))); end_proc; cod.21 standardSpecificationAdaptat:=proc(spec) local aux; begin aux := rhs(op(spec,4)); return(aux); end_proc;

4 Resultats obtinguts

Per tal de comprovar la correctesa i validesa del codi mostrat fins al moment, en el present

apartat es realitzaran alguns jocs de proves.

En l’apartat de Tractament d’errors, veurem quins són els outputs del nostre codi quan les

entrades no siguin correctes. És a dir, veurem el funcionament del codi de comprovació

esmentat anteriorment, per cada una de les situacions d’error que hem tingut en compte.

Ara bé, en aquest primer apartat no podrem comparar els resultats amb els de MuPAD, ja

Page 74: Títol: Generació Ordenada d’Estructures Combinatòries en

Capítol III – Generació d’Especificacions Estàndard

74

que aquest permet introduir paràmetres incorrectes en les especificacions, retornant

missatges d’error quan s’intenta utilitzar un mètode que produeix una situació de fallida.

En el segon apartat, compararem les sortides del nostre codi quan aquest funciona

correctament amb les produïdes per les pròpies llibreries de Mu-PAD.

En quant un fragment de text faci referència l’input de l’usuari, veurem que el color de fons

del paràgraf serà en gris. Si l’output del programa que estem veient prové del nostre codi, el

color de fons del paràgraf serà en un blau clar mentre que si prové de les llibreries de MuPAD

serà de color blauc fosc.

4.1 Tractament d’errors Capçalera de la funció generaEspecificacioEstandard(spec, label, bustrofedic, MNT)

spec Conjunt, llista o taula d'equacions amb l'especificació de les classes.

label Booleà que indica si estem treballant amb classe etiquetades (TRUE --> etiquetades / FALSE --> no etiquetades).

bustrofedic Booleà que indica si estem treballant amb ordre bustrofèdic (TRUE --> bustrofèdic / FALSE --> lexicogràfic).

MNT Identificador del Main Non Terminal. Si no hi posem res, agafa per defecte el primer identificador que troba en spec (començant per l'esquerra).

1. Especificació per a la qual el constructor Atom té massa operands.

L := {Q = Atom(Red, Blue)};

{Q = Atom(Red, Blue)}

generaEspecificacioEstandard(L, TRUE);

Error: El constructor Atom/Epsilon no pot portar tants operands. [comprova]

2. Especificació per a la qual el constructor Epsilon té massa operands.

L := {Q = Epsilon(Red, Blue)};

{Q = Epsilon(Red, Blue)}

generaEspecificacioEstandard(L, TRUE);

Error: El constructor Atom/Epsilon no pot portar tants operands. [comprova]

3. Intent d’assignar a Atom el nom d’un no terminal que ja existeix en l’especificació (en

una altra producció).

L := {Q = Atom(A), A = Union(Z,Z)};

{A = Union(Z, Z), Q = Atom(A)}

generaEspecificacioEstandard(L, TRUE);

Error: No es pot assignar l'identificador A a Atom perquè ja identifica un no terminal

[comprova]

Page 75: Títol: Generació Ordenada d’Estructures Combinatòries en

PFC – Generació Ordenada d’Estructures Combinatòries en “MuPAD-Combinat”

75

4. Intent d’assignar a Atom el nom d’un no terminal que ja existeix en l’especificació (en la

mateixa producció).

L := {Q = Union(Z,Atom(Q))};

{Q = Union(Z, Atom(Q))}

generaEspecificacioEstandard(L, TRUE);

Error: No es pot assignar l'identificador Q a Atom perquè ja identifica un no terminal

[comprova]

5. Intentem usar un identificador de no terminal que no existeix en l’especificació.

L := {Q = N};

{Q = N}

generaEspecificacioEstandard(L, TRUE);

Error: L'identificador N de no terminal no està definit a l'especificació. [comprova]

6. Intentem usar més extres del compte amb el constructor Sequence.

L := {Q = Sequence(Z, Length = 2, Length = 2, Length = 2, Length = 2)};

{Q = Sequence(Z, Length = 2, Length = 2, Length = 2, Length = 2)}

generaEspecificacioEstandard(L, TRUE);

Error: El nombre d'extres no és l'adequat per al constructor Sequence [comprova]

7. Usem un extra repetit per al constructor Sequence.

L := {Q = Sequence(Z, MinLength = 2, MinLength = 2)};

{Q = Sequence(Z, MinLength = 2, MinLength = 2)}

generaEspecificacioEstandard(L, TRUE);

Error: L'extra MinLength està repetit [comprova]

8. Intentem utilitzar un extra que no es troba entre els esperats.

L := {Q = Sequence(Z, Longitud = 2)};

{Q = Sequence(Z, Longitud = 2)}

generaEspecificacioEstandard(L, TRUE);

Error: Els extres passats no es corresponen amb els esperats (Length, MinLength, MaxLength)

[comprova]

9. Intentem combinar l’extra Length amb l’extra MaxLength.

L := {Q = Sequence(Z, Length = 2, MaxLength = 3)};

{Q = Sequence(Z, Length = 2, MaxLength = 3)}

generaEspecificacioEstandard(L, TRUE);

Error: No és possible combinar l'extra Length amb els extres MinLength o MaxLength

[comprova]

10. Intentem combinar l’extra Length amb l’extra MinLength

L := {Q = Sequence(Z, Length = 2, MinLength = 3)};

Page 76: Títol: Generació Ordenada d’Estructures Combinatòries en

Capítol III – Generació d’Especificacions Estàndard

76

{Q = Sequence(Z, Length = 2, MinLength = 3)}

generaEspecificacioEstandard(L, TRUE);

Error: No és possible combinar l'extra Length amb els extres MinLength o MaxLength

[comprova]

11. Intentem combinar els extres MinLength i MaxLength assignant el valor més gran a

MinLength.

L := {Q = Sequence(Z, MinLength = 4, MaxLength = 2)};

{Q = Sequence(Z, MinLength = 4, MaxLength = 2)}

generaEspecificacioEstandard(L, TRUE);

Error: L'extra MinLength no pot tenir un valor més gran que l'extra MaxLength [comprova]

12. Intentem definir l’extra MinLength mitjançant una desigualtat.

L := {Q = Sequence(Z, MinLength < 4)};

{Q = Sequence(Z, MinLength < 4)}

generaEspecificacioEstandard(L, TRUE);

Error: L'extra MinLength ha de venir definit com a igualtat [comprova]

13. Intentem definir l’extra Length mitjançant una desigualtat.

L := {Q = Sequence(Z, Length < 4)};

{Q = Sequence(Z, Length < 4)}

generaEspecificacioEstandard(L, TRUE);

Error: L'extra Length ha de venir definit com a igualtat [comprova]

14. Intentem definir l’extra MaxLength mitjançant una desigualtat.

L := {Q = Sequence(Z, MaxLength < 4)};

{Q = Sequence(Z, MaxLength < 4)}

generaEspecificacioEstandard(L, TRUE);

Error: L'extra MaxLength ha de venir definit com a igualtat [comprova]

15. Intentem definir un cicle de longitud zero.

L := {Q = Cycle(Z, Length = 0)};

{Q = Cycle(Z, Length = 0)}

generaEspecificacioEstandard(L, TRUE);

Error: La longitud per a un cicle no pot ser 0 [comprova]

16. Intentem definir un cicle de longitud màxima zero.

L := {Q = Cycle(Z, MaxLength = 0)};

{Q = Cycle(Z, MaxLength = 0)}

generaEspecificacioEstandard(L, TRUE);

Error: La longitud per a un cicle no pot ser 0 [comprova]

Page 77: Títol: Generació Ordenada d’Estructures Combinatòries en

PFC – Generació Ordenada d’Estructures Combinatòries en “MuPAD-Combinat”

77

4.2 Sortides generades

A continuació anirem generant diversos exemples per veure la major part de les

funcionalitats que cobreix el codi vist en l’apartat anterior.

1. Especificació per a un àtom genèric.

k := {A = Atom()};

{A = Atom()}

generaEspecificacioEstandard(K, FALSE, FALSE);

table(

{A=Atom()}=table(

A=Primitive(1,A),

Z=Primitive(1, Z)),

MainNonTerminal=A,

ordreBustrofedic=FALSE,

labelled=FALSE)

table(

A=Primitive(1, A))

2. Especificació per a un àtom assignant un identificador.

k := {A = Atom(Red)};

{A = Atom(Red)}

generaEspecificacioEstandard(K, FALSE, FALSE);

table(

{A=Atom(Red)}=table(

A=Primitive(1,Red),

Z=Primitive(1, Z)),

MainNonTerminal=A,

ordreBustrofedic=FALSE,

labelled=FALSE)

table(

A=Primitive(1, Red))

3. Assignació d’un Alias a Z.

k := {A = Z};

{A = Z}

generaEspecificacioEstandard(K, FALSE, FALSE);

table(

{A=Z}=table(

A=Alias(Z),

Z=Primitive(1, Z)),

MainNonTerminal=A,

ordreBustrofedic=FALSE,

labelled=FALSE)

table(

A=Alias(Z)

Z=Primitive(Z))

4. Especificació per a un Epsilon assignant un identificador.

k := {A = Epsilon(Blue)};

{A = Epsilon(Blue)}

generaEspecificacioEstandard(K, FALSE, FALSE);

Page 78: Títol: Generació Ordenada d’Estructures Combinatòries en

Capítol III – Generació d’Especificacions Estàndard

78

table(

{A=Epsilon(Blue)}=table(

A=Primitive(0,Blue),

Z=Primitive(1, Z)),

MainNonTerminal=A,

ordreBustrofedic=FALSE,

labelled=FALSE)

table(

A=Primitive(0, Blue))

5. Especificació dels arbres binàris no etiquetats en ordre lexicogràfic.

k := {B=Union(Z,Prod(B,B)) };

{B=Union(Z,Prod(B,B))}

generaEspecificacioEstandard(K, FALSE, FALSE);

table(

{ B=Union(Z,Prod(B,B)) }=table(

sub1=Prod(B,B),

B=Union(Z,sub1)

Z=Primitive(1, Z)),

MainNonTerminal=B,

ordreBustrofedic=FALSE,

labelled=FALSE)

table(

NonTerminal1=Prod(B,B),

B=Union(Z,NonTerminal1),

Z=Primitive(1, Z))

6. Especificació d’una Seqüència sobre els arbres binàris no etiquetats en ordre lexicogràfic.

k := {S=Sequence(B), B=Union(Z,Prod(B,B)) };

{B=Union(Z,Prod(B,B)), S=Sequence(B)}

generaEspecificacioEstandard(K, FALSE, FALSE);

table(

{ B=Union(Z,Prod(B,B)), S=Sequence(B)}=table(

S=Alias(NonTerminalSeq1, Sequence·op),

NonTerminalSeq1=Union(NonTerminalSeq2,

NonTerminalSeq3),

NonTerminalSeq2=Primitive(0),

NonTerminalSeq3=Alias(NonTerminalSeq4,

op),

NonTerminalSeq4=Prod(B,NonTerminalSeq1),

sub1=Prod(B,B),

B=Union(Z,sub1)

Z=Primitive(1, Z)),

MainNonTerminal=S,

ordreBustrofedic=FALSE,

labelled=FALSE)

table( Z=Primitive(1, Z), B=Union(Z,NonTerminal5), NonTerminal5=Prod(B, B), S=Alias(NonTerminalSequence1,

Sequence, object -> (if op(object, 0) = f and nops(object)

= 1 then return(op(object)) else return(NIL) end_if)), NonTerminalSequence1=Union(NonT

erminal2, NonTerminal4), NonTerminal4=Alias(NonTerminal3,

op), NonTerminal3=Prod(B,

NonTerminalSequence1), NonTerminal2=Primitive(0))

7. Especificació d’un Set sobre els arbres binàris no etiquetats en ordre lexicogràfic.

k := {S=Set(B), B=Union(Z,Prod(B,B)) };

{B=Union(Z,Prod(B,B)), S=Set (B)}

generaEspecificacioEstandard(K, FALSE, FALSE);

table( table( Z=Primitive(1, Z),

Page 79: Títol: Generació Ordenada d’Estructures Combinatòries en

PFC – Generació Ordenada d’Estructures Combinatòries en “MuPAD-Combinat”

79

{ B=Union(Z,Prod(B,B)), S=Set (B)}=table(

S=Set(B),

sub1=Prod(B,B),

B=Union(Z,sub1)

Z=Primitive(1, Z)),

MainNonTerminal=S,

ordreBustrofedic=FALSE,

labelled=FALSE)

B=Union(Z,NonTerminal2), NonTerminal2=Prod(B, B), S=Alias(NonTerminal1, z ->

hold(Set)(op(z)) NonTerminal1=Multiset(B))

8. Especificació d’un Powerset sobre els arbres binàris no etiquetats en ordre lexicogràfic.

k := {S=Powerset(B), B=Union(Z,Prod(B,B)) };

{B=Union(Z,Prod(B,B)), S=Powerset (B)}

generaEspecificacioEstandard(K, FALSE, FALSE);

table(

{ B=Union(Z,Prod(B,B)), S=Powerset (B)}=table(

S=Powerset(B),

sub1=Prod(B,B),

B=Union(Z,sub1)

Z=Primitive(1, Z)),

MainNonTerminal=S,

ordreBustrofedic=FALSE,

labelled=FALSE)

table( Z=Primitive(1, Z), B=Union(Z,NonTerminal2), NonTerminal2=Prod(B, B), S=Alias(NonTerminal1, z ->

hold(Powerset)(op(z)) NonTerminal1=Powerset(B))

9. Especificació d’un Set sobre els arbres binàris etiquetats en ordre lexicogràfic.

k := {S=Set(B), B=Union(Z,Prod(B,B)) };

{B=Union(Z,Prod(B,B)), S=Set (B)}

generaEspecificacioEstandard(K, TRUE, FALSE);

table(

{ B=Union(Z,Prod(B,B)), S=Set (B)}=table(

S=Alias(NonTerminalSet1, Set·op),

NonTerminalSet1=Union(NonTerminalSet2,

NonTerminalSet3),

NonTerminalSet2=Primitive(0),

NonTerminalSet3=Alias(NonTerminalSet4,op),

NonTerminalSet4=BoxedProd(B,NonTerminal

Set1),

sub1=Prod(B,B),

B=Union(Z,sub1)

Z=Primitive(1, Z)),

MainNonTerminal=S,

ordreBustrofedic=FALSE,

labelled=TRUE)

table( Z=Primitive(1, Z), B=Union(Z,NonTerminal2), NonTerminal2=Prod(B, B), S=Alias(NonTerminal1, z ->

hold(Set)(op(z)) NonTerminal1=Multiset(B))

10. Especificació d’un Cycle sobre els arbres binàris etiquetats en ordre lexicogràfic.

k := {S=Cycle(B), B=Union(Z,Prod(B,B)) };

{B=Union(Z,Prod(B,B)), S=Cycle(B)}

generaEspecificacioEstandard(K, TRUE, FALSE);

Page 80: Títol: Generació Ordenada d’Estructures Combinatòries en

Capítol III – Generació d’Especificacions Estàndard

80

table(

{ B=Union(Z,Prod(B,B)), S=Cycle (B)}=table(

S=Alias(NonTermCyc1, Cycle·op),

NonTermCyc1=BoxedProd(B,NonTermCyc2),

NonTermCyc2=Alias(NonTermCyc3,op),

NonTermCyc3=Alias(NonTerminalSeq1,Sequen

ce·op),

NonTerminalSeq1=Union(NonTerminalSeq2,

NonTermi nalSeq3),

NonTerminalSeq2=Primitive(0),

NonTerminalSeq3=Alias(NonTerminalSeq4,op),

NonTerminalSe4=Prod(B,NonTerminalSeq1),

sub1=Prod(B,B),

B=Union(Z,sub1)

Z=Primitive(1, Z)),

MainNonTerminal=S,

ordreBustrofedic=FALSE,

labelled=TRUE)

table( Z=Primitive(1, Z), B=Union(Z,NonTerminal1), NonTerminal1=Prod(B, B), S=Cycle(B))

11. Especificació d’una Seqüència sobre Z amb cardinalitat igual a 3.

k := {S=Sequence(Z, Length=3) };

{ S=Sequence(Z, Length=3)}

generaEspecificacioEstandard(K, FALSE, FALSE);

table(

{ S=Sequence(Z,Length=3)}=table(

S=Alias(NonTerminalSeq1, Sequence·op),

NonTerminalSeq1=Prod(NonTerminalSeq2,Z),

NonTerminalSeq2=Alias(NonTerminalSeq3, op),

NonTerminalSeq3=Prod(Z,Z),

Z=Primitive(1, Z)),

MainNonTerminal=S,

ordreBustrofedic=FALSE,

labelled=FALSE)

table( Z=Primitive(1, Z), S=Alias(NonTerminal3,Sequence·op), NonTerminal3=Prod(NonTerminal2,Z), NonTerminal2=Alias(NonTerminal1,op

), NonTerminal1=Prod(Z,Z))

12. Especificació d’una Seqüència sobre Z amb cardinalitat igual o major a 3.

k := {S=Sequence(Z, MinLength=3) };

{ S=Sequence(Z, MinLength=3)}

generaEspecificacioEstandard(K, FALSE, FALSE);

table(

{ S=Sequence(Z,MinLength=3)}=table(

S=Alias(NonTerminalSeq1, Sequence·op),

NonTerminalSeq1=Prod(NonTerminalSeq2,Non

TerminalSeq6),

NonTerminalSeq2=Alias(NonTerminalSeq3, op),

NonTerminalSeq3=Prod(Z,NonTerminalSeq4),

NonTerminalSeq4=Alias(NonTerminalSeq5, op),

table( Z=Primitive(1, Z), S=Alias(NonTerminal9,Sequence·op), NonTerminal9=Prod(NonTerminal4,

NonTerminalSequence5), NonTerminalSequence5=Union(NonTer

minal6, NonTerminal8), NonTerminal8=Alias(NonTerminal7, op), NonTerminal7=Prod(Z,NonTerminalSequ

ence5), Nonterminal6=Primitive(0), NonTerminal4=Alias(Nonterminal3, op), NonTerminal3=Prod(NonTerminal2, Z),

Page 81: Títol: Generació Ordenada d’Estructures Combinatòries en

PFC – Generació Ordenada d’Estructures Combinatòries en “MuPAD-Combinat”

81

NonTerminalSeq5=Prod(Z,Z),

NonTerminalSeq6=Union(NonTerminalSeq7,

NonTerminalSeq8),

NonTerminalSeq7=Primitive(0),

NonTerminalSeq8=Alias(NonTerminalSeq9, op),

NonTerminalSeq9=Prod(Z,NonTerminalSeq6),

Z=Primitive(1, Z)),

MainNonTerminal=S,

ordreBustrofedic=FALSE,

labelled=FALSE)

NonTerminal2=Alias(NonTerminal1, op), NonTerminal1=Prod(Z,Z))

13. Especificació d’una Seqüència sobre Z amb cardinalitat igual o menor a 3.

k := {S=Sequence(Z, MaxLength=3) };

{ S=Sequence(Z, MaxLength=3)}

generaEspecificacioEstandard(K, FALSE, FALSE);

table(

{ S=Sequence(Z,MaxLength=3)}=table(

S=Alias(NonTerminalSeq1, Sequence·op),

NonTerminalSeq1=Union(NonTerminalSeq2,

NonTerminalSeq3),

NonTerminalSeq2=Primitive(0),

NonTerminalSeq3=Union(NonTerminalSeq8,

NonTerminalSeq4),

NonTerminalSeq4=Alias(NonTerminalSeq5, op),

NonTerminalSeq5=Prod(Z,NonTerminalSeq6),

NonTerminalSeq6=Alias(NonTerminalSeq7, op),

NonTerminalSeq7=Prod(Z,Z),

NonTerminalSeq8=Union(Z,NonTerminalSeq9),

NonTerminalSeq9=Alias(NonTerminalSeq10,

op),

NonTerminalSeq10=Prod(Z,Z),

Z=Primitive(1, Z)),

MainNonTerminal=S,

ordreBustrofedic=FALSE,

labelled=FALSE)

table( Z=Primitive(1, Z), S=Alias(NonTerminal8, Sequence, object

-> (if op(object, 0) = f and nops(object) = 1 then

return(op(object)) else return(NIL) end_if)), NonTerminal8=Union(NonTerminal1,

NonTerminal7), NonTerminal7=Union(NonTerminal5,

NonTerminal6), NonTerminal6=Union(NonTerminal3, Z), NonTerminal5=Alias(NonTerminal4, op), NonTerminal4=Prod(NonTerminal3, Z), NonTerminal3=Alias(NonTerminal2, op), NonTerminal2=Prod(Z, Z), NonTerminal1=Primitive(0))

Page 82: Títol: Generació Ordenada d’Estructures Combinatòries en
Page 83: Títol: Generació Ordenada d’Estructures Combinatòries en

Capítol IV

Unranking

Page 84: Títol: Generació Ordenada d’Estructures Combinatòries en

Capítol IV – Unranking

Índex del capítol

1 INTRODUCCIÓ................................................................................................... 85

2 ESTUDI DE LA FUNCIÓ D’ UNRANKING ..................................................... 85 2.1 Unranking de classes no etiquetades .......................................................................................88 2.2 Unranking de classes etiquetades ............................................................................................99

3 IMPLEMENTACIÓ DE L’UNRANKING ....................................................... 103

4 ANÀLISI DEL COST ........................................................................................ 133 4.1 Sortides generades.................................................................................................................138

Page 85: Títol: Generació Ordenada d’Estructures Combinatòries en

PFC – Generació Ordenada d’Estructures Combinatòries en “MuPAD-Combinat”

85

1 Introducció

En aquest capítol estudiarem la problemàtica de l’unranking, i presentarem l’algorisme

implementat com a solució.

Tal i com hem dit, entenem per unranking la generació d’un objecte combinatori donada la

seva posició, la seva mida i una especificació de la classe combinatòria a la que l’objecte

pertany. Emperò, ens calen més detalls per a la correcta consecució del present objectiu; ens

farà falta conèixer també si estem tractant amb una classe etiquetada o no, i saber si volem

generar els objectes seguint l’ordre lexicogràfic o l’ordre bustrofèdic.

Tenint tot això en compte, s’ha dividit el present capítol en quatre apartats:

• L’apartat 2 ha estat dividit al seu temps en 2 subapartats més:

o En el subapartat 2.1 estudiarem els algorismes existents per a l’unranking de

les classes no etiquetades.

o En el subapartat 2.2, de manera similar, estudiarem la mateixa problemàtica

per a les classes etiquetades.

• En l’apartat 3, veurem l’algorisme implementat en MuPAD per a l’obtenció de la

funció d’unranking.

• Finalment, en l’apartat 4, veurem i compararem els nostres resultats amb els

obtinguts mitjançant MuPAD si l’usuari fes servir els mètodes ja implementats en

MuPAD-Combinat.

2 Estudi de la funció d’ Unranking

La major part del contingut d’aquest apartat s’ha extret de les referències [4], [5], [8], [9] i

[12].

Abans de començar a parlar dels algorismes existents per a l’Unranking, cal fer una última

definició de dos conceptes. En el capítol II ja hem parlat dels dos ordres que utilitzarem per a

la generació d’objectes: el lexicogràfic i el bustrofèdic. Ara bé, no hem parlat dels ordres

existents a l’hora d’etiquetar. Cal dir que, per tal d’enfrontar-nos a l’etiquetatge dels objectes

obtinguts amb l’Unranking, l’estratègia a seguir a consistit en, primer, generar l’objecte i,

després, calcular l’etiqueta que li corresponia. Però, és clar, la generació de les etiquetes

també bé marcada per un ordre.

Page 86: Títol: Generació Ordenada d’Estructures Combinatòries en

Capítol IV – Unranking

86

Quan parlem dels Productes particionals i dels BoxedProds hem de tenir en compte les

etiquetes dels àtoms. Donada una partició ρ de [1..n] en un j-subconjunt { }jll ,,1 K i un (n-

j)-subconjunt { }''1 ,, jnll −K , denotem ( )ρβα ,, a l’objecte etiquetat de mida n que resulta

quan reetiquetem els àtoms del parell ( )βα , d’acord a ρ . Per exemple, si α = 21, β =

213 i ρ = { } { }5,4,2,3,1 , aleshores ( )ρβα ,, = 31425. Diem que ρ és una (n,j)-partició.

Denotem jnS , com el conjunt de totes les possibles (n,j)-particions i assumim que existeix

un ordre jnS ,

p . Per exemple, si n = 7 i j = 4, aleshores jnS , conté (7,4)-particions:

{ } { } { } { } { } { } { } { }{ }3,2,1,7,6,5,4,4,2,1,7,6,5,3,,7,6,4,5,3,2,1,7,6,5,4,3,2,1 K

El conjunt βα ∗ és el conjunt de ⎟⎟⎠

⎞⎜⎜⎝

⎛jn

objectes etiquetats que obtenim en reetiquetar els

àtoms del parell ( )βα , d’acord a cada una de les (n,j)-particions:

( ){ }jnS ,,, ∈=∗ ρρβαβα .

Dos ordres diferents per als objectes de jnj BA −∗ ens apareixen de manera natural de les

següents especificacions:

( )U U Uj jn jnA B S

jnj BA∈ ∈ ∈

−−

=∗α β ρ

ρβα,

,, ,

i

( )U U Ujn j jnS A B

jnj BA,

,,∈ ∈ ∈

−−

=∗ρ α β

ρβα .

Si usem la primera de les especificacions, tenim que per dos objectes ( )ρβαγ ,,= i

( )'''' ,, ρβαγ = de jnj BA −∗ aleshores γ és més petit que 'γ si i només si α és més petit

que 'α d’acord amb l’ordre de jA , ó 'αα = i β és més petita que 'β d’acord amb l’ordre de

jnB − , ó '' ,, βαβα = i ρ és més petita que 'ρ en l’ordre induït per jnS ,

p . És a dir,

( ) ( ) ( ) ( ) ( )''''''''',

,,,,,, ρρβαβαββααααρβαρβαjnjnjjnj SBABA ióió pppp ==⇔

−−∗

.

D’altra banda, si fem cas a la segona especificació, primer comparem les particions ( ρ i 'ρ )

i, després, els parells etiquetats “interns” ( βα , i '' ,βα ):

( ) ( ) ( ) ( ) ( )'''''''',

,,,, ββααρρααρρρρρβαρβαjnjjnjnj BASBA iióió

−−===⇔∗ pppp .

Page 87: Títol: Generació Ordenada d’Estructures Combinatòries en

PFC – Generació Ordenada d’Estructures Combinatòries en “MuPAD-Combinat”

87

Al primer dels ordres obtinguts l’anomenarem Partition-First (PF) o estàndard, i al segon

Structure-First (SF). A continuació es mostren dues il·lustracions on es troben els arbres

binaris de mida 3 generats en ordre PF i SF. Es mostra el rank i una representació lineal a

sota de cada un dels arbres.

Arbres binaris de mida 3 en ordre PF

Arbres binaris de mida 3 en ordre SF

Així doncs, queda clar que l’elecció de l’ordre PF ó SF en els objectes etiquetats influirà en

gran manera en com obtindrem els objectes. En el nostre cas utilitzarem l’ordre PF on, a

1

2 3

2

1 3

3

1 2

1

3 2

2

3 1

3

2 1 1 2

3

1 3

2

2 3

1

2 1

3

3 1

2

3 2

1

1

2 3

1

3 2

2

1 3

2

3 1

3

1 2

3

2 1 1 2

3

2 1

3

1 3

2

3 1

2

2 3

1

3 2

1

0, ( ) ( ) ( )( )321 ZZZ ∗∗ 1, ( ) ( ) ( )( )312 ZZZ ∗∗ 2, ( ) ( ) ( )( )213 ZZZ ∗∗ 3, ( ) ( ) ( )( )231 ZZZ ∗∗

4, ( ) ( ) ( )( )132 ZZZ ∗∗ 5, ( ) ( ) ( )( )123 ZZZ ∗∗ 6, ( ) ( )( ) ( )321 ZZZ ∗∗ 7, ( ) ( )( ) ( )231 ZZZ ∗∗

8, ( ) ( )( ) ( )132 ZZZ ∗∗ 9, ( ) ( )( ) ( )312 ZZZ ∗∗ 10, ( ) ( )( ) ( )213 ZZZ ∗∗ 11, ( ) ( )( ) ( )123 ZZZ ∗∗

0, ( )321 ZZZ ∗∗ 2, ( )312 ZZZ ∗∗

4, ( )213 ZZZ ∗∗

3, ( )132 ZZZ ∗∗

5, ( )123 ZZZ ∗∗ 6, ( ) 321 ZZZ ∗∗

8, ( ) 231 ZZZ ∗∗ 10, ( ) 132 ZZZ ∗∗

7, ( ) 312 ZZZ ∗∗

9, ( ) 213 ZZZ ∗∗ 11, ( ) 123 ZZZ ∗∗

1, ( )231 ZZZ ∗∗

Page 88: Títol: Generació Ordenada d’Estructures Combinatòries en

Capítol IV – Unranking

88

partir de cada objecte no etiquetat, generem tots els possibles etiquetatges. Amb tot però,

no ha de resultar difícil adaptar els algorismes que es veuran en el present capítol per tal de

què funcionin també en ordre SF. Per la seva banda, MuPAD utilitza l’ordre SF. Emperò,

computacionalment ambdós ordres aporten la mateixa complexitat.

En quant al cost d’usar un o altre ordre, en el fons, és aproximadament el mateix. Així que

l’elecció d’un o l’altre ordre per aquest motiu no és molt rellevant.

2.1 Unranking de classes no etiquetades

En aquest apartat ens ocuparem d’estudiar la funció d’unranking per aquelles classes no

etiquetades construïdes a partir dels constructors admissibles definits en el capítol II

(Unions, Prods, Sequences, Powersets, Sets i Cicles). Per cada un dels constructors,

estudiarem els algorismes existents, els quals adaptarem més endavant per obtenir la nostra

solució en MuPAD.

Primerament, només dir que els algorismes d’unranking no etiquetat per als casos d’ε i les

classes atòmiques són molt simples, ja que tan sols existeix un element per a aquestes

classes. Així, tan sols retornarem un resultat en el cas en què se’ns demani l’element 0 (el

primer element) i la mida es correspongui a la de la classe que estem tractant (0 per ε, 1 per

les classes atòmiques).

L’algorisme per a l’unranking de les unions no etiquetades també és força senzill, però

requereix una petita explicació. L’objecte de rank i en (A+B)n és l’objecte de rank i d’An si

;0 nai <≤ altrament és l’objecte de rank nai − de Bn (algorisme 1).

Algorisme 1. Unranking per Unions Disjuntes Unrank(A+B, n, i)

i’ := i – Count(A, n)

si i’ < 0 llavors Unrank(A, n, i)

sinó Unrank(B, n, i’)

fsi

Per tal d’enfrontar-nos a l’unranking no etiquetat del producte cartesià, assumirem

primerament el cas de l’ordre lexicogràfic. El primer que caldrà fer serà determinar la mida,

diguem-ne j, de la primera component de l’objecte; després, només ens caldrà generar

l’unrank dels objectes d’A de mida j, i l’unrank dels objectes de B de mida n-j. Així doncs, si

βαγ ,= és l’objecte de rank i d’(AxB)n aleshores α=j satisfà

Page 89: Títol: Generació Ordenada d’Estructures Combinatòries en

PFC – Generació Ordenada d’Estructures Combinatòries en “MuPAD-Combinat”

89

∑ ∑<≤ ≤≤

−− ⋅<≤⋅jk jk

knkknk baiba0 0

i γ és l’objecte de rank ∑<≤

−⋅−=jk

knk baii0

' en jnj BA −× . Cada objecte d’ jA s’utilitza en la

construcció dels b = jnb − objectes diferents d’ jnj BA −× . Per aquesta raó, si βαγ ,= és

l’objecte de rank i’ de jnj BA −× , aleshores α és l’objecte de rank (i’ div b) d’ jA . De la

mateixa manera, β és l’objecte de rank (i’ mod b) d’ jnB − . Tot això es pot veure en

l’algorisme 2, que es mostra a continuació.

Algorisme 2. Unranking no etiquetat per Productes (Lexicogràfic) Unrank(AxB, n, i)

c := 0; j := 0; d := Count(A, j) · Count(B, n-j)

mentre c + d ≤ i fer

c := c + d; j := j + 1; d := Count(A, j) · Count(B, n-j)

fmentre

i’ := i – c; b := Count(B, n-j)

α := Unrank(A, j, i’ div b); β := Unrank(B, n-j, i’ mod b)

retorna βα ,

Si en comptes d’usar l’ordre lexicogràfic fem servir l’ordre bustrofèdic, l’ unranking dels

productes és molt similar. La principal diferència consistirà en com es determina la mida de

la primera component, tal i com es pot veure en l’algorisme 3. La mida de la primera

component va de la mida més petita no usada a la mida més gran no usada, i així anar fent.

Algorisme 3. Unranking no etiquetat per Productes (Bustrofèdic) Unrank(AxB, n, i)

c := 0; k := 0; j := 0; d := Count(A, j) · Count(B, n-j)

mentre c + d ≤ i fer

c := c + d; k := k + 1; j := k div 2;

si parell(k) llavors d := Count(A, j) · Count(B, n-j)

sinó d := Count(A, n-j) · Count(B, j)

fsi

fmentre

si senar(k) llavors j := n-j;

fsi

i’ := i – c; b := Count(B, n-j)

α := Unrank(A, j, i’ div b); β := Unrank(B, n-j, i’ mod b)

retorna βα ,

Page 90: Títol: Generació Ordenada d’Estructures Combinatòries en

Capítol IV – Unranking

90

Donat que, com ja sabem, les Seqüències es poden desenvolupar en funció d’Unions i de

Productes, és doncs evident que no ens caldrà cap algorisme en particular, i que mitjançant

els algorismes ja desenvolupats podrem obtenir perfectament l’unranking no etiquetat per

als objectes d’una Seqüència.

Per tal de tractar els Powersets (conjunts d’objectes no etiquetats sense repeticions), primer

cal definir un ordre entre ells. Per definir-lo, descomponem cada Powerset en dues parts: un

bloc líder que conté totes les components de mida més petita, i una cua amb totes les

components restants. Definirem l’ordre usant un criteri lexicogràfic per comparar els blocs

líders i el següent isomorfisme

( )⎣ ⎦

UU U0 1

1

),()(> = =

>−×=+==n

n

j jnkjkjnj APSetkcardAPSetAPSetB ε

on jA> és el conjunt d’objectes en A la mida dels quals és estrictament més gran que j.

Siguin β i 'β dos objectes de nB , { }γαααβ ,,,, 21 kK= i { }'''2

'1

' ,,,, γαααβ kK= , on

{ } ),(,,, 21 kcardAPSet jk =∈ααα K forma el bloc líder en β ,

{ } ),(,,, '''2

'1 ' kcardAPSet

jk =∈ααα K és el bloc líder en 'β , ( )jkjn APSet >−∈γ és la cua de

β i ( )''''

jjknAPSet>−

∈γ és la cua de 'β . A més, assumim que kαα pKp1 i ''1 kαα pKp .

Aleshores,

( ) ( )( )( )

{ } { }( )'''11

''''

''''

,,,,

:1::

γγαααα

αααα

ββ

kjn

j

n

Bkk

lliAi

B

and

orillandiandkkandjj

orkkandjjorjj

−=

=<≤∀∃==

>=<⇔

pKK

p

p

Aquest ordre és ben natural i pot ser definit equivalentment com l’ordenació lexicogràfica

dels Powersets donada la seva representació “canònica”. És a dir, per exemple,

{ }mγγγ ,,1 K= amb 1+iAi γγ p per tots els mii <≤1: , sent 1+iAi γγ p si i només si

1+< ii γγ , ó 1+== iij γγ i 1+iAi jγγ p .

També es poden considerar algunes alternatives de l’ isomorfisme bàsic dels Powersets vist

més amunt. Per exemple, l’ordre dels Powersets depèn de la mida i la cardinalitat del seu

bloc líder. Així, podríem:

• Ordenar els Powersets en ordre ascendent (S) ó descendent (s) segons la mida de

les component dels seus blocs líders.

• Ordenar els Powersets en ordre ascendent (C) ó descendent (c) segons el nombre

d’objectes dels seus blocs líders.

• Ordenar primer segons la mida de les components (S/s), i després segons la

cardinalitat (C/c); o tot això al revés.

Page 91: Títol: Generació Ordenada d’Estructures Combinatòries en

PFC – Generació Ordenada d’Estructures Combinatòries en “MuPAD-Combinat”

91

D’altra banda, podem definir també el bloc líder com el conjunt que conté les components

més petites (L) ó les components més grans (l).

L’ordre de la cua es defineix recursivament. Així, per tal de completar la definició d’ordre en

els Powersets és l’ordre entre el blocs líders quan aquests tenen la mateixa cardinalitat i la

mateixa mida en les components. Per tal de comparar els blocs líders de dos Powersets quan

ambdós tenen k components de mida j, l’opció més natural és disposar les seves

components en ordre ascendent de ranks i comparar lexicogràficament (aquest ordre es

denota com R).

Així, l’ordre induït per l’isomorfisme ja vist és LScR, i serà l’ordre que usarem en els nostres

algorismes d’Unranking.

Sigui jn,δ̂ la cardinalitat de la classe dels Powersets d’ A tals que la seva component més

petita és de mida com a mínim j. Òbviament, ( ) ( )APSetAPSetnn #ˆ11, == ≥δ . Fixant una

mida n, aquesta classe pot ser definida recursivament com

( ) ( ) { } ( )⎣ ⎦U

jnkjkjn

kjjj APSetAAPSetAPSet

≤≤+≥−+≥≥ ×+=

111 ,

( ) 0=≥ jn APSet si 0>> nj i ( ) ε=≥ jAPSet0 si 0≥j . Per tant tenim que 1ˆ,0 =jδ per tot

0≥j i per Nn ≤≤1 la recurrència satisfeta pels jn,δ̂ ’s és

⎣ ⎦⎪⎩

⎪⎨⎧

≤⎟⎟⎠

⎞⎜⎜⎝

⎛+

>= ∑

≤≤+−+

jnkjkjn

jjn

jn njsika

njsi

11,1,

, ˆˆ

,0ˆ

δδδ

Així, jn,δ̂ es pot calcular per Nnj ≤≤≤1 en ( )NNO log2 operacions aritmètiques:

( ) ( ) ( )⎣ ⎦

∑ ∑ ∑ ∑≤≤ ≤≤ ≤≤ ≤≤

==Nn nj jnk Nn

NNOnnOO1 1 1

2

1loglog1 .

Així, el nombre de Powersets de mida n amb com a mínim una component de mida més

petita o igual a j, és a dir, la cardinalitat de

{ } ( )⎣ ⎦

U U1

1

1

1

= =+≥−×

j

l lnklkln

kl APSetA ,

és ( ) ( )jnnjnn APSetAPSet ≥≥ −=− ##ˆˆ1,1, δδ . Assumint que els valors jn,δ̂ han estat

precalculats i emmagatzemats en taules, ja podem presentar l’algorisme d’Unrank per als

Powersets (Algorisme 4).

Page 92: Títol: Generació Ordenada d’Estructures Combinatòries en

Capítol IV – Unranking

92

Algorisme 4. Unranking no etiquetat per Powersets Unrank(PSet(A), n, i)

si n = 0 llavors retorna ε fsi

j := 1; mentre ≤− +1,1,ˆˆ

jnn δδ i fer j := j +1 fmentre

//La component més petita té mida j.

i’ := i – ( jnn ,1,ˆˆ δδ − )

si j = n llavors k := 1; i’’ := i’

sinó k := 1; c := 0; d := ⎟⎟⎠

⎞⎜⎜⎝

⎛k

jACount ),(1,

ˆ+−⋅ jkjnδ

mentre (k + 1)·j ≤ n i c + d ≤ i’ fer

c := c + d; k := k + 1; d := ⎟⎟⎠

⎞⎜⎜⎝

⎛k

jACount ),(1,

ˆ+−⋅ jkjnδ

fmentre

i’’ := i’ – c

fsi

//Hi ha k components de mida j.

iα := i’’ div 1,ˆ

+− jkjnδ ; i β := (i’’ mod 1,ˆ

+− jkjnδ ) + ( 1,ˆ

kjn−δ - 1,ˆ

+− jkjnδ )

//La cua β es recupera com un objecte de PSet( A ), no de PSet( jA> ); és per això

//que cal afegir ( 1,ˆ

kjn−δ - 1,ˆ

+− jkjnδ ).

α := Unrank( { }kjA , kj, iα ); β := Unrank(PSet( A ), n – kj, i β )

retorna βα ,

EL primer pas consisteix en determinar la mida més petita j entre les components del

Powerset, i després el nombre k de components de mida j (la cardinalitat del bloc líder).

A continuació és necessari fer l’unrank dels blocs líder { }kjA en R-ordre:

{ } { } ( )( ){ }1−×∈=

kjj

kj AAA αα f ,

on ( ) { }αααα ff '' AA ∈= , és a dir, el subconjunt d’ A -objectes la mida dels quals és

estrictament més gran que α o el rank dels quals és més gran que el rank de 2α ; per tant,

( ) { }ααααjAjj AA ff '' ∈= . Les components en { }k

jA es calculen en ordre ascendent

segons el rank, així l’algorisme troba el rank de la component més petita i la part restant es

realitza recursivament. L’algorisme es basa en el fet que hi ha ⎟⎟⎠

⎞⎜⎜⎝

⎛−−11

ka j Powersets amb la

Page 93: Títol: Generació Ordenada d’Estructures Combinatòries en

PFC – Generació Ordenada d’Estructures Combinatòries en “MuPAD-Combinat”

93

component més petita de rank 0, hi ha ⎟⎟⎠

⎞⎜⎜⎝

⎛−−12

ka j Powersets amb la component més petita de

rank 1, hi ha ⎟⎟⎠

⎞⎜⎜⎝

⎛−−13

ka j Powersets amb la component més petita de rank 2, i així anar fent.

Una cop el rank m de la component més petita s’ha calculat, la resta de components L[l] es

troben de la mateixa manera, tal i com podem veure en el següent algorisme (algorisme 5).

Algorisme 5. Unranking no etiquetat per Powersets de k components de mida j

Unrank( { }kjA , n, i)

si n = 0 llavors retorna ε fsi

L[0] := 0; i’ := i

per l := 1 fins a k fer

m := 1; r := 0; d :=

mentre r + d ≤ i’ fer

r := r + d; m := m + 1; d :=

//L[l-1] es resta ja que els primers L[l-1] ranks jA no es

//poden repetir en la nova cerca.

fmentre

i’ := i’ – r

//m és el rank de l’actual component l.

L[l] := m + L[l-1]

//Les components es troben en ordre ascendent, així cal afegir el rank

//de la component prèvia L[l-1].

fper

per l := 1 fins a k fer lα := Unrank( A , j , L[l]) fper

retorna kk αααα ,,,, 121 −K

A continuació considerarem l’unranking dels Sets (és a dir, conjunts amb repeticions) no

etiquetats, d’acord amb un ordre LScR,

( ) { }{ } ( )⎣ ⎦

UU U0 1

1

> = =>−×+=

n

n

j jnkjkjn

kj ASetAASet ε ,

Sigui jn,δ la cardinalitat dels Sets de mida n amb la component més petita de mida com a

mínim j; és a dir, la cardinalitat de

( ) ( ) { }{ } ( )⎣ ⎦U

jnkjkjn

kjjnjn ASetAASetASet

≤≤+≥−+≥≥ ×+=

111 ,

on ( ) 0=≥ jn ASet si 0>> nj i ( ) ε=≥ jASet0 si 0≥j . Aleshores, tenim que 1,0 =jδ per

tota 0≥j i per Nn ≤≤1 la recurrència

( )⎟⎟⎠

⎞⎜⎜⎝

⎛−

−−−1

]1[,k

mlLjACount

( )⎟⎟⎠

⎞⎜⎜⎝

⎛−

−−−1

]1[,k

mlLjACount

Page 94: Títol: Generació Ordenada d’Estructures Combinatòries en

Capítol IV – Unranking

94

⎣ ⎦⎪⎩

⎪⎨⎧

≤⎟⎟⎠

⎞⎜⎜⎝

⎛ −++

>= ∑

≤≤+−+

jnkjkjn

jjn

jn njsikka

njsi

11,1,

,1

,0

δδδ

Anàlogament a jn.δ̂ , aquests valors es poden calcular en ( )NNO log2 operacions

aritmètiques per tot Nnj ≤≤≤1 . Assumint doncs que els valors de les jn.δ ’s han estat

prèviament calculats i emmagatzemats en taules, l’algorisme pels Sets és bàsicament el

mateix que l’algorisme 4 pels Powersets, però usem jn.δ en comptes de jn.δ̂ . Una vegada

s’ha calculat la mida més petita j de les components dels Sets, calculem la cardinalitat del

bloc líder (algorisme 6).

Algorisme 6. Unranking no etiquetat per Sets Unrank(Set(A), n, i)

si n = 0 llavors retorna ε fsi

j := 1; mentre ≤− +1,1, jnn δδ i fer j := j +1 fmentre

//La component més petita té mida j.

i’ := i – ( jnn ,1, δδ − )

si j = n llavors k := 1; i’’ := i’

sino k := 1; c := 0; d := ⎟⎟⎠

⎞⎜⎜⎝

⎛ −+k

kjACount 1),( 1, +−⋅ jkjnδ

mentre (k + 1)·j ≤ n i c + d ≤ i’ fer

c := c + d; k := k + 1; d := ⎟⎟⎠

⎞⎜⎜⎝

⎛ −+k

kjACount 1),(1, +−⋅ jkjnδ

fmentre

i’’ := i’ – c

fsi

//Hi ha k components de mida j.

iα := i’’ div 1, +− jkjnδ ; i β := (i’’ mod 1, +− jkjnδ ) + ( 1,kjn−δ - 1, +− jkjnδ )

//La cua β es recupera com un objecte de Set( A ), no de Set( jA> ); és per això

//que cal afegir ( 1,kjn−δ - 1, +− jkjnδ ).

α := Unrank( { }{ }kjA , kj, iα ); β := Unrank(Set( A ), n – kj, i β )

retorna βα ,

Finalment, ens cal fer l’unrank dels Sets de k components de mida j (els blocs líders):

{ }{ } { } ( )( ) { }{ }U f

1

kl

lkjj

lkj AAA

=

−×∈= αα ,

Page 95: Títol: Generació Ordenada d’Estructures Combinatòries en

PFC – Generació Ordenada d’Estructures Combinatòries en “MuPAD-Combinat”

95

on altre vegada ( ) { }ααααjAjj AA ff '' ∈= . Comparant { }k

jA dels Powersets i { }{ }kjA dels

Sets, és fàcil veure que l’unranking dels Sets és similar a l’algorisme 5: tan sols és necessari

utilitzar ⎟⎟⎠

⎞⎜⎜⎝

⎛ −+yyx 1

en l’algorisme 5 el càlcul de d abans i dins del bucle mentre en comptes

de ⎟⎟⎠

⎞⎜⎜⎝

⎛yx

. En l’algorisme 7 presentem la versió final de l’unrank dels Sets amb k components

de mida j.

Algorisme 7. Unranking no etiquetat per Sets de k components de mida j

Unrank( { }{ }kjA , n, i)

si n = 0 llavors retorna ε fsi

L[0] := 0; i’ := i

per l := 1 fins a k fer

m := 1; r := 0; d :=

mentre r + d ≤ i’ fer

r := r + d; m := m + 1; d :=

//L[l-1] es resta ja que els primers L[l-1] ranks jA no es

//poden repetir en la nova cerca.

fmentre

i’ := i’ – r

//m és el rank de l’actual component l.

L[l] := m + L[l-1]

//Les components es troben en ordre ascendent, així cal afegir el rank

//de la component prèvia L[l-1].

fper

per l := 1 fins a k fer lα := Unrank( A , j , L[l]) fper

retorna kk αααα ,,,, 121 −K

Si ara ens fixem en l’unranking d’aquells constructors que es poden veure afectats per

restriccions de cardinalitat, veiem que les Seqüències, tal i com es troben definides per

l’isomorfisme ( ) ( )ASeqAASeq ×+= ε , ja s’encarreguen de generar correctament els

resultats desitjats. Ara bé, per tal de realitzar l’unrank dels Powersets i Sets amb cardinalitat

fixada, considerem l’ordre LScR i cal usar uns algorismes específics.

Per als Powersets necessitem definir { }kjn,δ̂ , el nombre de Powersets de mida n amb k

components de mida com a mínim j; és a dir,

{ } ( ) { }( )n

kjjn

kjn AkcardAPSet ≥≥ === #,#ˆ

,δ .

( ) ( )⎟⎟⎠

⎞⎜⎜⎝

⎛−

−−−−−−1

11]1[,k

kmlLjACount

( ) ( )⎟⎟⎠

⎞⎜⎜⎝

⎛−

−−−−−−1

11]1[,k

kmlLjACount

Page 96: Títol: Generació Ordenada d’Estructures Combinatòries en

Capítol IV – Unranking

96

En concret, { } { }( )

nk

jk

n A#ˆ1, =δ . Així, tenim que { } 1ˆ 0

,0 =jδ per tot 0≥j i per n > 0 la recurrència

és

{ }{ } { }

⎣ ⎦{ }⎪⎩

⎪⎨⎧

≤⎟⎟⎠

⎞⎜⎜⎝

⎛+

>= ∑

≤≤

−+−+

hjnl

lhjljn

jhjn

hjn njsi

la

njsi

,min11,1,

, ˆˆ

,0ˆ

δδδ

on ⎣ ⎦{ }kjnh ,min1 ≤≤ . D’aquesta manera, és fàcil calcular aquests valors per

Nnj ≤≤≤1 i ⎣ ⎦{ }kjnh ,min1 ≤≤ en { }( )22 ,logmin kNNO operacions aritmètiques:

( ) { }( )⎣ ⎦{ }⎣ ⎦{ }

∑ ∑ ∑ ∑≤≤ ≤≤ ≤≤ ≤≤

=Nn nj kjnh hjnl

kNNOO1 1 ,min1 ,min1

22 ,logmin1 .

Assumint que aquests valors han estat precalculats i emmagatzemats per al seu ús posterior,

el nombre de Powersets amb alguna component de mida estrictament menor que j i

cardinalitat k és { } { } { }( ) { }( )

nkjn

kkjn

kn AA ≥≥ −=− ##ˆˆ

1,1, δδ . Així, l’unranking de { }kA es pot veure en el

següent algorisme (algorisme 8), que és molt similar als algorismes 5 i 7, i té els mateixos

passos principals.

Algorisme 8. Unranking no etiquetat per Powersets amb cardinalitat fixada

Unrank( { }kA , n, i)

si n = 0 llavors retorna ε fsi

j := 1; mentre { } { } ≤− +kjn

kn 1,1,

ˆˆ δδ i fer j := j +1 fmentre

//La component més petita té mida j

i’ := i - ( { } { }kjn

kn ,1,

ˆˆ δδ − ); p := 1; c := 0; d := { }pkjpjn

j

pa −

+−⋅⎟⎟⎠

⎞⎜⎜⎝

⎛1,δ̂

mentre c + d ≤ i i p ≤ k fer

c := c + d; p := p + 1; d := { }pkjpjn

j

pa −

+−⋅⎟⎟⎠

⎞⎜⎜⎝

⎛1,δ̂

fmentre

//Hi ha exactament p components amb mida j.

i’’ := i’ – c

iα := i’’ div { }pkjpjn

−+− 1,δ̂ ; i β := (i’’ mod { }pk

jpjn−

+− 1,δ̂ ) + ( { } { }pkjpjn

pkpjn

−+−

−− − 1,0,

ˆˆ δδ )

//La cua β s’obté de l’unrank de { }pkA − , no de { }pkjA −

> ; és per això que

//afegim { } { }( ) { }( )( )pjn

pkj

pkjpjn

pkpjn A

−−

≤−

+−−

− =− #ˆˆ1,0, δδ .

α := Unrank( { }pjA , pj, iα ); β := Unrank( { }pkA − , n – pj, i β )

retorna βα ,

Page 97: Títol: Generació Ordenada d’Estructures Combinatòries en

PFC – Generació Ordenada d’Estructures Combinatòries en “MuPAD-Combinat”

97

Per tal de solucionar l’unranking de { }kA ≤ i { }kA ≥ s’utilitzen idees similars, tal i com es pot

veure en l’algorisme 9 i l’algorisme 10.

Algorisme 9. Unranking no etiquetat per Powersets amb cardinalitat major o igual a k

Unrank( { }kA ≥ , n, i)

si n = 0 llavors retorna ε fsi

c := 0; k := k; d := { }kn 0,δ̂

mentre c + d ≤ i fer

c := c + d

k := k + 1

d := { }kn 0,δ̂

fmentre

retorna (Unrank({ }kA , n, (i - c)))

Algorisme 10. Unranking no etiquetat per Powersets amb cardinalitat menor o igual a k

Unrank( { }kA ≤ , n, i)

si n = 0 llavors retorna ε fsi

c := 0; k := 1; d := { }kn 0,δ̂

mentre c + d ≤ i fer

c := c + d

k := k + 1

d := { }kn 0,δ̂

fmentre

retorna (Unrank({ }kA , n, (i - c)))

Finalment, l’unranking dels Sets amb cardinalitat fixada es comporta de manera molt similar

al dels Powersets. Primer, cal fer un petit canvi en el càlcul de les deltes per tal d’adaptar-lo

als Sets. Necessitem definir { }{ }kjn,δ , el nombre de Sets de mida n amb k components de mida

com a mínim j; és a dir,

{ }{ } ( ) { }{ }( )n

kjjn

kjn AkcardASet ≥≥ === #,#,δ .

En concret, { }{ } { }{ }( )n

kj

kn A#1, =δ . Així, tenim que { }{ } 10

,0 =jδ per tot 0≥j i per n > 0 la

recurrència és

Page 98: Títol: Generació Ordenada d’Estructures Combinatòries en

Capítol IV – Unranking

98

{ }{ }{ }{ } { }{ }

⎣ ⎦{ }⎪⎩

⎪⎨⎧

≤⎟⎟⎠

⎞⎜⎜⎝

⎛ −++

>= ∑

≤≤

−+−+

hjnl

lhjljn

jhjn

hjn njsi

lla

njsi

,min11,1,

,1,0

δδδ

on ⎣ ⎦{ }kjnh ,min1 ≤≤ .

Assumint que aquests valors han estat precalculats i emmagatzemats per al seu ús posterior,

el nombre de Sets amb alguna component de mida estrictament menor que j i cardinalitat k

és { }{ } { }{ } { }{ }( ) { }{ }( )n

kjn

kkjn

kn AA ≥≥ −=− ## 1,1, δδ . Així, l’unranking de { }{ }kA es pot veure en el següent

algorisme (algorisme 11), que és molt similar als algorismes 5 i 7, i té els mateixos passos

principals, però substitueix ⎟⎟⎠

⎞⎜⎜⎝

⎛yx

per ⎟⎟⎠

⎞⎜⎜⎝

⎛ −+yyx 1

, per tal de permetre les repeticions..

L’unranking de { }{ }k

A≤

i { }{ }k

A≥

segueix arguments anàlegs, i es poden veure en els

algorismes 12 i 13.

Algorisme 11. Unranking no etiquetat per Sets amb cardinalitat fixada

Unrank( { }{ }kA , n, i)

si n = 0 llavors retorna ε fsi

j := 1; mentre { }{ } { }{ } ≤− +kjn

kn 1,1, δδ i fer j := j +1 fmentre

//La component més petita té mida j.

i’ := i - ( { }{ } { }{ }kjn

kn ,1, δδ − )

p := 1; c := 0; d := { }{ }pkjpjn

j

ppa −

+−⋅⎟⎟⎠

⎞⎜⎜⎝

⎛ −+1,

mentre c + d ≤ i i p ≤ k fer

c := c + d; p := p + 1; d := { }{ }pkjpjn

j

ppa −

+−⋅⎟⎟⎠

⎞⎜⎜⎝

⎛ −+1,

fmentre

//Hi ha exactament p components amb mida j.

i’’ := i’ – c

iα := i’’ div { }{ }pkjpjn

−+− 1,δ ; i β := (i’’ mod { }{ }pk

jpjn−

+− 1,δ ) + ( { }{ } { }{ }pkjpjn

pkpjn

−+−

−− − 1,0, δδ )

//La cua β s’obté de l’unrank de { }{ }pk

A−

, no de { }{ }pk

jA−

> ; és per això que

//afegim { }{ } { }{ }( ) { }{ }( )( )pjn

pkj

pkjpjn

pkpjn A

−−

≤−

+−−

− =− #1,0, δδ .

α := Unrank( { }{ }pjA , pj, iα ); β := Unrank(

{ }{ }pk

A−

, n – pj, i β )

retorna βα ,

Page 99: Títol: Generació Ordenada d’Estructures Combinatòries en

PFC – Generació Ordenada d’Estructures Combinatòries en “MuPAD-Combinat”

99

Algorisme 12. Unranking no etiquetat per Sets amb cardinalitat major o igual a k

Unrank( { }{ }kA ≥ , n, i)

si n = 0 llavors retorna ε fsi

c := 0; k := k; d := { }{ }kn 0,δ

mentre c + d ≤ i fer

c := c + d

k := k + 1

d := { }{ }kn 0,δ

fmentre

retorna (Unrank({ }{ }kA , n, (i - c)))

Algorisme 13. Unranking no etiquetat per Sets amb cardinalitat menor o igual a k

Unrank( { }{ }kA ≤ , n, i)

si n = 0 llavors retorna ε fsi

c := 0; k := 1; d := { }{ }kn 0,δ

mentre c + d ≤ i fer

c := c + d

k := k + 1

d := { }{ }kn 0,δ

fmentre

retorna (Unrank({ }{ }kA , n, (i - c)))

2.2 Unranking de classes etiquetades

En aquest apartat, i de la mateixa manera que en l’apartat anterior, ens ocuparem d’estudiar

la funció d’unranking per aquelles classes etiquetades construïdes a partir dels constructors

admissibles definits en el capítol II. Com abans, estudiarem els algorismes existents, que

seran els que adaptarem més endavant per obtenir la nostra solució en MuPAD.

Els algorismes per als casos d’ε i les classes atòmiques, donat la seva senzillesa no seran

explicats, i ja es comentarà més endavant, en l’apartat d’implementació en MuPAD, com

s’han tractat.

L’algorisme d’unrank per a les unions etiquetades funciona exactament de la mateixa manera

vista en l’apartat anterior, ja que és totalment independent del fet de si la classe és o no

etiquetada. Tan sols es limita a comparar en quina de les classes pertanyents a la unió es

Page 100: Títol: Generació Ordenada d’Estructures Combinatòries en

Capítol IV – Unranking

100

pot trobar l’objecte a generar, i per tant, no té en compte cap mena d’aspecte combinatori.

Així, s’utilitzarà altra vegada l’algorisme 1 ja vist.

Com en el cas d’abans, per a l’unranking etiquetat del producte particional, assumirem

primerament el cas de l’ordre lexicogràfic. El funcionament serà molt similar, tan sols caldrà

que tinguem en compte l’aspecte combinatori, és a dir, no només haurem de generar

l’objecte correcte, sinó que també haurem d’obtenir l’etiqueta corresponent. Així, el primer

que caldrà fer serà determinar la mida, diguem-ne j, de la primera component de l’objecte;

després, només ens caldrà generar l’unrank dels objectes d’A de mida j, i l’unrank dels

objectes de B de mida n-j i, finalment, obtenir el rank de la corresponent partició. Així doncs,

si γβαγ l,,= és l’objecte de rank i d’(A*B)n aleshores α=j satisfà

∑ ∑<≤ ≤≤

−− ⋅⋅⎟⎟⎠

⎞⎜⎜⎝

⎛<≤⋅⋅⎟⎟

⎞⎜⎜⎝

jk jkknkknk ba

kn

ibakn

0 0

i γ és l’objecte de rank ∑<≤

−⋅⋅⎟⎟⎠

⎞⎜⎜⎝

⎛−=

jkknk ba

kn

ii0

' en jnj BA −∗ . Cada objecte d’ jA s’utilitza en

la construcció dels b = jnb

jn

−⋅⎟⎟⎠

⎞⎜⎜⎝

⎛ objectes diferents d’ jnj BA −∗ . Per aquesta raó, si

l,,βαγ = és l’objecte de rank i’ de jnj BA −∗ , aleshores α és l’objecte de rank (i’ div b)

d’ jA . De la mateixa manera, β és l’objecte de rank ((i’ mod b) div ⎟⎟⎠

⎞⎜⎜⎝

⎛jn

) d’ jnB − , i l’etiqueta

l és la ((i’ mod b) mod ⎟⎟⎠

⎞⎜⎜⎝

⎛jn

)-èsima partició entre els ⎟⎟⎠

⎞⎜⎜⎝

⎛jn

etiquetatges diferents

corresponents a βα ∗ . Tot això es pot veure en l’algorisme 14, que es mostra a

continuació.

Algorisme 14. Unranking etiquetat per Productes (Lexicogràfic) Unrank(A*B, n, i)

c := 0; j := 0; d := Count(A, j) · Count(B, n-j)

mentre c + d ≤ i fer

c := c + d; j := j + 1; d := ⎟⎟⎠

⎞⎜⎜⎝

⎛jn

· Count(A, j) · Count(B, n-j)

fmentre

i’ := i – c; b := ⎟⎟⎠

⎞⎜⎜⎝

⎛jn

· Count(B, n-j); l := (i’ mod b) mod ⎟⎟⎠

⎞⎜⎜⎝

⎛jn

α := Unrank(A, j, i’ div b); β := Unrank(B, n-j, (i’ mod b) div ⎟⎟⎠

⎞⎜⎜⎝

⎛jn

)

retorna l,,βα

Page 101: Títol: Generació Ordenada d’Estructures Combinatòries en

PFC – Generació Ordenada d’Estructures Combinatòries en “MuPAD-Combinat”

101

Si en comptes d’usar l’ordre lexicogràfic fem servir l’ordre bustrofèdic, l’ unranking etiquetat

dels productes és molt similar. La principal diferència consistirà en com es determina la mida

de la primera component, tal i com es pot veure en l’algorisme 15. La mida de la primera

component va de la mida més petita no usada a la mida més gran no usada, i així anar fent.

Algorisme 15. Unranking etiquetat per Productes (Bustrofèdic) Unrank(AxB, n, i)

c := 0; k := 0; j := 0; d := Count(A, j) · Count(B, n-j)

mentre c + d ≤ i fer

c := c + d; k := k + 1; j := k div 2;

si parell(k) llavors d := ⎟⎟⎠

⎞⎜⎜⎝

⎛jn

·Count(A, j) · Count(B, n-j)

sino d := ⎟⎟⎠

⎞⎜⎜⎝

⎛jn

·Count(A, n-j) · Count(B, j)

fsi

fmentre

si senar(k) llavors j := n-j;

fsi

i’ := i – c; b := Count(B, n-j); l := (i’ mod b) mod ⎟⎟⎠

⎞⎜⎜⎝

⎛jn

α := Unrank(A, j, i’ div b); β := Unrank(B, n-j, (i’ mod b) div ⎟⎟⎠

⎞⎜⎜⎝

⎛jn

)

retorna l,,βα

Donat que, com ja sabem, les Seqüències es poden desenvolupar en funció d’Unions i de

Productes (a partir de l’isomorfisme ja vist, ( ) ( )ASeqAASeq ∗+= ε ), és doncs evident que

no ens caldrà cap algorisme en particular, i que mitjançant els algorismes ja desenvolupats

podrem obtenir perfectament l’unranking etiquetat per als objectes d’una Seqüència.

Finalment, l’unranking per als BoxedProds és anàleg al dels productes ja vistos, amb la

provisió de què el BoxedProd α □*β de cada parell d’objectes conté només ⎟⎟

⎞⎜⎜⎝

⎛−−

11

jn

objectes etiquetats, sent αβα =+= jin . Això significa que és suficient substituir els

Page 102: Títol: Generació Ordenada d’Estructures Combinatòries en

Capítol IV – Unranking

102

coeficients binomials ⎟⎟⎠

⎞⎜⎜⎝

⎛jn

per ⎟⎟⎠

⎞⎜⎜⎝

⎛−−

11

jn

, i començar amb j := 1 en l’algorisme per l’unranking

de productes, tal i com es pot veure en els algorisme 16 i 17.

Algorisme 16. Unranking etiquetat per BoxedProds (Lexicogràfic)

Unrank(A□*B, n, i)

c := 0; j := 1; d := Count(A, j) · Count(B, n-j)

mentre c + d ≤ i fer

c := c + d; j := j + 1; d := ⎟⎟⎠

⎞⎜⎜⎝

⎛−−

11

jn

· Count(A, j) · Count(B, n-j)

fmentre

i’ := i – c; b := ⎟⎟⎠

⎞⎜⎜⎝

⎛−−

11

jn

· Count(B, n-j); l := (i’ mod b) mod ⎟⎟⎠

⎞⎜⎜⎝

⎛−−

11

jn

α := Unrank(A, j, i’ div b); β := Unrank(B, n-j, (i’ mod b) div ⎟⎟⎠

⎞⎜⎜⎝

⎛−−

11

jn

)

retorna l,,βα

Algorisme 17. Unranking etiquetat per BoxedProds (Bustrofèdic)

Unrank(A□*B, n, i)

c := 0; k := 0; j := 1; d := Count(A, j) · Count(B, n-j)

mentre c + d ≤ i fer

c := c + d; k := k + 1; j := k div 2;

si parell(k) llavors d := ⎟⎟⎠

⎞⎜⎜⎝

⎛−−

11

jn

·Count(A, j) · Count(B, n-j)

sino d := ⎟⎟⎠

⎞⎜⎜⎝

⎛−−

11

jn

·Count(A, n-j) · Count(B, j)

fsi

fmentre

si senar(k) llavors j := n-j;

fsi

i’ := i – c; b := ⎟⎟⎠

⎞⎜⎜⎝

⎛−−

11

jn

·Count(B, n-j) ; l := (i’ mod b) mod ⎟⎟⎠

⎞⎜⎜⎝

⎛−−

11

jn

α := Unrank(A, j, i’ div b); β := Unrank(B, n-j, (i’ mod b) div ⎟⎟⎠

⎞⎜⎜⎝

⎛−−

11

jn

)

retorna l,,βα

Page 103: Títol: Generació Ordenada d’Estructures Combinatòries en

PFC – Generació Ordenada d’Estructures Combinatòries en “MuPAD-Combinat”

103

3 Implementació de l’Unranking A continuació, es presenta el codi implementat per a l’unranking d’objectes etiquetats i no

etiquetats.

A grans trets, la idea bàsica consisteix en tenir una funció principal que s’encarrega de

comprovar, abans de fer res, si és possible obtenir l’objecte amb rank demanat (és a dir, si

en la classe especificada hi ha com a mínim tants objectes com el rank passat com a

paràmetre). Després, es mira si estem tractant amb una classe etiquetada o no, i s’invoca la

subfunció pertinent per tractar cadascun d’aquests dos casos. Aquesta subfunció té una

estructura condicional, i analitza el constructor de la classe tractada, per tal d’invocar la

funció d’unrank adient. Tot el funcionament de crides entre funcions dels constructors és

recursiu, fins a arribar als casos base de les classes atòmiques o buides.

Un petit detall a comentar és que els algorismes utilitzats (és a dir, els vistos en els apartats

anteriors) consideren que els ranks dels objectes d’una classe es mouen entre 0 i la

cardinalitat de la classe per a la mida passada per l’usuari - 1. Ara bé, per tal de fer més

comprensibles les capçaleres de les funcions per als usuaris, i al mateix temps, seguir el

mateix format de les funcions ja existents en Mupad, l’entrada per a la funció principal

acceptarà un rank entre 1 i la cardinalitat de la classe per la mida donada.

Així, el primer fragment de codi que veurem serà el de la funció principal. Cal destacar el fet

que ha calgut implementar una funció anomenada especEquivalent per tal de què en tot

moment poguéssim fer ús de la funció ja existent en Mupad Count4 sense haver de

reeimplementar-la. L’objectiu d’especEquivalent doncs, és obtenir el descomposableObject

equivalent a la nostra funció en Mupad (ja que la funció Count només pot ser invocada des

d’objectes d’aquest tipus).

cod.22 funcioUnrank:=proc(spec, size: Type::NonNegInt, rank: Type::PosInt) local aux1, auxil, t; option remeber; begin //Primerament, caldrà inicialitzar una taula, que només farem servir per al cas en què estiguem //tractant una classe etiquetada. Aquesta taula emmagatzemarà en una posició l’objecte, i en //l’altra, l’etiqueta que li correspon. Així, ja podem començar a preveure que l’objecte i el seu //etiquetatge es calcularan separadament. t := []; //Obtenim el descomposableObject equivalent a la nostra especificació. Aquest objecte //l’anirem passant en totes les crides que farem, per tal de poder invocar en tot moment i sense //problemes la funció Count. aux1 := especEquivalent(rhs(op(spec,4)),rhs(op(spec,1))); //Realitzem la comprovació destinada a verificar que el rank passat com a paràmetre sigui //possible tenint en compte el nombre d’objectes de mida size en l’especificació. if aux1::count(size,rhs(op(spec,3))) < rank then return(FAIL); 4 La capçalera per aquesta funció és count(nonnegative integer n, <A>), i retorna el nombre d’objectes de mida n derivats del no terminal A de l’especificació. Per defecte, el no Terminal A és el main non terminal.

Page 104: Títol: Generació Ordenada d’Estructures Combinatòries en

Capítol IV – Unranking

104

end_if; if spec[labelled] then //En cas de què la classe sigui etiquetada invoquem la funció per a fer l’unrank etiquetat. t := unrankEtiquetat(spec, rhs(op(spec,3)), rhs(op(spec,4)), size, (rank - 1), aux1); //Calculem l’etiqueta que li pertoca a l’objecte, invocant la funció etiq i passant-li com a //paràmetre la etiqueta no desenvolupada que ens hagi retornat la funció unrank. t[2] := etiq(t[2]); //Posem l’etiqueta en l’objecte i retornem el resultat final. return(etiquetaObjecte(spec,t[1],t[2])); else //En cas de què la classe no sigui etiquetada, fem la crida a la funció d’unrank senzilla. return(unrankNoEtiquetat(spec, rhs(op(spec,3)), rhs(op(spec,4)), size, (rank - 1), aux1)); end_if; end_proc;

Els tres fragments de codi que veurem a continuació, pertanyen a tres petits funcions

auxiliars.

La primera d’elles, que ja s’ha comentat abans, és la que serveix per crear un objecte de

tipus decomposableObject equivalent a la nostra especificació.

cod.23 especEquivalent := proc(taula, label) local i, t, aux; option remember; begin //Rebem com a paràmetres la taula de l’especificació, i un booleà que ens indica si estem //tractant classes etiquetades. t := []; i := 1; //Convertim la nostra taula d’especificació, en un conjunt d’equacions de l’estil X = Y, on X és //l’element de la banda esquerra d’una posició de la taula i Y l’element de la banda dreta. while i <= nops(taula) do aux := (lhs(op(taula,i))=rhs(op(taula,i))); t := append(t,aux); i := i + 1; end_while; //Retornem l’objecte resultat d’invocar la funció combinat::decomposableObjects, amb //paràmetres el conjunt d’equacions generat, i el booleà label. return(combinat::decomposableObjects({op(t)},Labelled = label)); end_proc;

La següent funció no es més que una generació exhaustiva (és a dir, generar tots els

elements d’una certa mida), basada en la funció d’unrank. Tot i que existeixen maneres molt

més eficients d’implementar la generació exhaustiva, la manera com la definirem aquí ja

servirà als nostres propòsits.

cod.24 funcioLlistar := proc(spec, size: Type::NonNegInt) local i, t, aux1, aux2; option remember; begin t := [];

Page 105: Títol: Generació Ordenada d’Estructures Combinatòries en

PFC – Generació Ordenada d’Estructures Combinatòries en “MuPAD-Combinat”

105

i := 1; //Obtenim un decomposableObject equivalent a la nostra especificació, i consultem el nombre //d’elements que existeixen per a la classe donada la mida size i el guardem a aux2. aux1 := especEquivalent(rhs(op(spec,4)),rhs(op(spec,1))); aux2 := aux1::count(size,rhs(op(spec,3))); //Realitzem un bucle on la i servirà per anar donant-nos el rank de l’element a generar. Mentre //el rank de la i sigui més petit que aux2, invoquem la funció d’unrank. while i <= aux2 do aux1 := funcioUnrank(spec, size, i); t := append(t,aux1); i := i + 1; end_while; return(t); end_proc; En aquest moment també implementarem una generació aleatòria d’objectes (Random)

basada en la funció d’unrank, de manera molt similar a la generació exhaustiva vista

anteriorment.

cod.25 funcioRandom := proc(spec, size: Type::NonNegInt) local r, aux; option remember; begin //Obtenim un decomposableObject equivalent a la nostra especificació. aux := especEquivalent(rhs(op(spec,4)),rhs(op(spec,1))); //Creem una funció que generi nombres aleatoris entre 1 i el nombre d’elements de mida size //que té la classe. r := random(1..aux::count(size,rhs(op(spec,3)))); //Invoquem la funció d’unrank, passant com a paràmetre rank el valor que ens retorni la funció //de random. return(funcioUnrank(spec, size, r())); end_proc;

A continuació, veiem el codi destinat a l’unrank de classes no etiquetades. Com ja s’ha dit, la

seva estructura és de tipus condicional, i s’encarrega de fer subcrides depenent del

constructor que usi la classe que estigui tractant. També s’encarrega de tractar el cas base,

és a dir, les classes atòmiques i buides.

cod.26 unrankNoEtiquetat:=proc(spec, MNT, taula, n, i, aux1) local const, t; option remember; begin //En el cas en què en la posició MNT de la taula no hi hagi un constructor, voldrà dir que tenim //una posició del tipus A = B i que hi hem arribat amb MNT = A. Per tant, el que fem és tornar a //cridar la pròpia funció actual, però passant com a paràmetre MNT, el que tingués el cantó //dret de la posició MNT actual de la taula (en el cas de l’exemple, la B). if op(taula[MNT],0) = FAIL then return(unrankNoEtiquetat(spec,taula[MNT],taula,n,i, aux1)); else //En cas de què arribem aquí, sabem segur que tenim un constructor.

Page 106: Títol: Generació Ordenada d’Estructures Combinatòries en

Capítol IV – Unranking

106

if op(taula[MNT],0) = Primitive then //Si el constructor que tenim és Primitive, sabem que estem tractant o bé la classe buida o bé //una classe atòmica. Aquestes dues classes tan sols tenen un element, i per tant, si el rank que //ens han passat no és 0 (és a dir, si no ens han demanat quin és el primer element), retornarem //un FAIL. if i <> 0 then return(FAIL); else //Si la mida n amb què hem arribat aquí no es correspon a la mida 0 ó 1 (les dues mides vàlides //per a les classes que utilitzen el constructor Primitive), retornarem un FAIL. if n <> op(taula[MNT],1) then return(FAIL); else //En cas que la posició MNT de la taula només tingui un element, ens trobarem sempre en una //situació com X = Primitive(0), i per tant, el que retornarem arribats a aquest punt serà el primer //element de mida 0, que nosaltres anomenem Epsilon. if nops(taula[MNT]) = 1 then return(Epsilon); //Si la posició MNT de la taula té més d’un element, serà una posició de tipus X = Primitive(0/1, Y), //i per tant, el que voldrem serà retornar la Y. else return(op(taula[MNT],2)); end_if; end_if; end_if; //El següent constructor que tractem és l’Alias. elif op(taula[MNT],0) = Alias then if op(op(taula[MNT],2),3) = arrow then else //Com que l’Alias pot aparèixer en diverses situacions, caldrà que esbrinem en quin cas concret //ens trobem. Per exemple, si veiem que el nombre d’operands del segon element de la posició //MNT de la taula és 2, tindrem per exemple una situació com aquesta X = Alias(Y, Sequence·op) //(els dos elements són Sequence i op). Per tant, estem tractant o una Sequencia, o un Set, o //una estructura d’aquest tipus. El que farem en aquest cas serà una crida a unrankNoEtiquetat, //però com a MNT li passarem (en el nostre cas) Y. Aleshores, haurem de formatar el resultat //mitjançant diverses crides a op per tal de què aquest aparegui com nosaltres volem. if nops(op(taula[MNT],2)) = 2 then if op(taula[op(taula[MNT],1)],0) = Prod then return(op(op(taula[MNT],2),1)( op(unrankNoEtiquetat(spec,op(taula[MNT],1),taula,n,i, aux1)))); else return(op(op(taula[MNT],2),1)(unrankNoEtiquetat(spec,op(taula[MNT],1),taula,n,i, aux1))); end_if; //Si no tenim dos elements, significa que tindrem una posició de la taula com X = Alias(Y, op), i //per tant, només caldrà fer una crida a unrankNoEtiquetat passant com a paràmetre MNT la Y, i //després formatar el resultat mitjançant el mètode op. else //Podem tenir el cas en què simplement tinguem un alias directe, com X = Alias(Y). if nops(taula[MNT]) = 1 then return((unrankNoEtiquetat(spec,op(taula[MNT],1),taula,n,i, aux1))); //O un Alias amb l’aparició d’op... else return(op(op(taula[MNT],2),1)(unrankNoEtiquetat(spec,op(taula[MNT],1),taula,n,i, aux1))); end_if; end_if;

Page 107: Títol: Generació Ordenada d’Estructures Combinatòries en

PFC – Generació Ordenada d’Estructures Combinatòries en “MuPAD-Combinat”

107

end_if; //Si el constructor és Union, invocarem una crida cap a la funció específica per a tractar unions. elif op(taula[MNT],0) = Union then return(unrankUnionNoEtiquetat(spec,MNT,taula,n,i, aux1)); //Si el constructor és Prod, farem una crida cap a la funció específica depenent de si estem //tractant amb una classe que contempla l’ordre bustrofèdic o lexicogràfic. elif op(taula[MNT],0) = Prod then if rhs(op(spec,2)) then return(unrankProdNoEtiquetatBustrofedic(spec,MNT,taula,n,i,aux1)); else return(unrankProdNoEtiquetatLexicografic(spec,MNT,taula,n,i,aux1)); end_if; //Per al cas de les classes no etiquetades, recordem que pot aparèixer el constructor Powerset, i //per tant, caldrà tenir-lo en compte. El que farem serà primer mirar si el constructor Powerset //apareix sol o acompanyat d’algun restrictor de cardinalitat. elif op(taula[MNT],0) = Powerset then if nops(taula[MNT]) = 1 then //Si el constructor Powerset apareix sol, caldrà primer calcular les deltes que faran falta (com //s’ha explicat en apartats anteriors), i després invocarem la funció d’unrank per Powersets. t := taulaDeltaPowerset(spec, MNT, taula, n, i, aux1); return(Powerset(unrankPowersetNoEtiquetat(spec,MNT,taula,n,i,aux1,t))); else //Si el constructor Powerset apareix acompanyat, caldrà primer calcular les deltes restringides //que faran falta (com s’ha explicat en apartats anteriors), i després invocarem la funció //d’unrank per Powersets restringits que li correspongui. t := taulaDeltaPowersetRestrictedCard(spec, MNT, taula, n, i, op(op(taula[MNT],2),2), aux1); if op(op(taula[MNT],2),1) = Length then return(Powerset(unrankPowersetNoEtiquetatRestrictedCard(spec,MNT,taula,n,i,op(op(taula[MNT],2),2),aux1,t))); elif op(op(taula[MNT],2),1) = MinLength then return(Powerset(unrankPowersetNoEtiquetatMinLength(spec,MNT,taula,n,i,op(op(taula[MNT],2),2),aux1,t))); elif op(op(taula[MNT],2),1) = MaxLength then return(Powerset(unrankPowersetNoEtiquetatMaxLength(spec,MNT,taula,n,i,op(op(taula[MNT],2),2),aux1,t))); end_if; end_if; //El comportament per als Sets, és anàleg al que acabem de veure per als Powersets. És a dir, //mirem si apareix el constructor sol o acompanyat, generem les deltes, i invoquem la funció que //li escaigui d’unrank. elif op(taula[MNT],0) = Set then if nops(taula[MNT]) = 1 then t := taulaDeltaSet(spec, MNT, taula, n, i, aux1); return(Set(unrankSetNoEtiquetat(spec,MNT,taula,n,i,aux1,t))); else t := taulaDeltaSetRestrictedCard(spec, MNT, taula, n, i, op(op(taula[MNT],2),2), aux1); if op(op(taula[MNT],2),1) = Length then return(Set(unrankSetNoEtiquetatRestrictedCard(spec,MNT,taula,n,i,op(op(taula[MNT],2),2),aux1,t))); elif op(op(taula[MNT],2),1) = MinLength then return(Set(unrankSetNoEtiquetatMinLength(spec,MNT,taula,n,i,op(op(taula[MNT],2),2),aux1,t))); elif op(op(taula[MNT],2),1) = MaxLength then

Page 108: Títol: Generació Ordenada d’Estructures Combinatòries en

Capítol IV – Unranking

108

return(Set(unrankSetNoEtiquetatMaxLength(spec,MNT,taula,n,i,op(op(taula[MNT],2),2),aux1,t))); end_if; end_if; end_if; end_if; end_proc;

La primera de les funcions específiques d’unrank que veurem serà la de les unions.

Bàsicament, el funcionament és el mateix que el vist en l’algorisme 1.

cod.27 unrankUnionNoEtiquetat:=proc(spec, MNT, taula, n, i, auxil) local aux1, aux2, aux3; option remember; begin //En la posició MNT de la taula tindrem una estructura de tipus X = Union(Y,W). aux1 := auxil::count(n,op(taula[MNT],1)); aux2 := i - aux1; if aux2 < 0 then //Si l’objecte s’ha de construir a partir de la primera classe, invoquem la funció general //unrankNoEtiquetat, però li passem com a paràmetre MNT el primer element (en el nostre cas //d’exemple la Y). return(unrankNoEtiquetat(spec,op(taula[MNT],1),taula,n,i, auxil)); else //Altrament, invoquem l’unrnakNoEtiquetat però passant-li com a paràmetre MNT la segona //classe (en el nostre cas la W). return(unrankNoEtiquetat(spec,op(taula[MNT],2),taula,n,aux2, auxil)); end_if; end_proc;

De les dues funcions d’unranking per a productes, la primera és la que s’encarrega de

generar objectes quan l’ordre utilitzat hagi de ser lexicogràfic. Bàsicament aquest codi és el

ja vist en l’algorisme 2.

cod.28 unrankProdNoEtiquetatLexicografic:=proc(spec, MNT, taula, n, i, aux1) local orig, equiv, aux2, aux3, aux4, aux5, auxil, c, j, d, sub1, sub2; option remember; begin //La posició MNT de la taula té una estructura de tipus X = Prod(Y, W). //El primer que farem serà buscar la mida de la primera component, és a dir, el valor per la j. c := 0; j := 0; //Seguint el nostre exemple, mirem quants objectes de mida j hi ha en la classe Y . aux2 := aux1::count(j,op(taula[MNT],1)); //Mirem quants elements de mida (n-j) hi ha en la classe W.

Page 109: Títol: Generació Ordenada d’Estructures Combinatòries en

PFC – Generació Ordenada d’Estructures Combinatòries en “MuPAD-Combinat”

109

aux3 := aux1::count((n - j),op(taula[MNT],2)); d := aux2 * aux3; //Mentre no tinguem prous elements, anem incrementant el valor de la mida j. while (c + d) <= i do c := c + d; j := j + 1; aux2 := aux1::count(j,op(taula[MNT],1));

aux3 := aux1::count((n - j),op(taula[MNT],2)); d := aux2 * aux3; end_while; //Obtenim els valors per calcular el rank per a l’objecte de mida j que s’haurà de generar en Y, i //l’objecte de mida n-j que s’haurà de generar en W. aux4 := i - c; aux5 := aux1::count((n - j),op(taula[MNT],2)); //Retornarem un objecte conformat per Prod(a, b), on a i b seran el resultat d’una crida a //unrankNoEtiquetat amb paràmetres: // a MNT: Y, size: j, rank: div(aux4,aux5) // b MNT: W, size: (n-j), rank: mod(aux4, aux5) return(Prod(unrankNoEtiquetat(spec,op(taula[MNT],1),taula,j,_div(aux4,aux5), aux1),unrankNoEtiquetat(spec,op(taula[MNT],2),taula,(n - j),_mod(aux4,aux5), aux1))); end_proc;

La segona funció d’unranking per a productes correspon a l’algorisme 3, i s’encarrega dels

productes quan l’ordre que tenim és el bustrofèdic.

cod.29 unrankProdNoEtiquetatBustrofedic:=proc(spec, MNT, taula, n, i, aux1) local orig, equiv, aux2, aux3, aux4, aux5, auxil, c, j, k, d, sub1, sub2; option remember; begin //La posició MNT de la taula té una estructura de tipus X = Prod(Y, W). //Com abans, el primer que farem serà buscar la mida j de la primera component. Ara bé, //caldrà anar amb compte, ja que s’haurà de vigilar amb el vaivé de mides (controlat amb la k) //que li correspon a l’ordre bustrofèdic. c := 0; k := 0; j := 0; aux2 := aux1::count(j,op(taula[MNT],1)); aux3 := aux1::count((n - j),op(taula[MNT],2)); d := aux2 * aux3; while (c + d) <= i do c := c + d; k := k + 1; j := _div(k,2); //Segons el valor que prengui la k, haurem de realitzar el comptatge d’elements en les classes Y i //W, del dret (count(j,Y) i count(n-j,W)) o del revés (count(n-j,Y) i count(j,W)). if _mod(k,2) = 0 then aux2 := aux1::count(j,op(taula[MNT],1)); aux3 := aux1::count((n - j),op(taula[MNT],2)); else aux2 := aux1::count((n - j),op(taula[MNT],1)); aux3 := aux1::count(j,op(taula[MNT],2));

Page 110: Títol: Generació Ordenada d’Estructures Combinatòries en

Capítol IV – Unranking

110

end_if; d := aux2 * aux3; end_while; //Cal mirar per darrera vegada el valor de la k, per saber realment quin haurà de ser el valor per //la j. if _mod(k,2) <> 0 then j := n - j; end_if; //Com abans, caldrà conèixer els valors per calcular el rank per a l’objecte de mida j que //s’haurà de generar en Y, i l’objecte de mida n-j que s’haurà de generar en W. aux4 := i - c; aux5 := aux1::count((n - j),op(taula[MNT],2)); //Retornarem un objecte conformat per Prod(a, b), on a i b seran el resultat d’una crida a //unrankNoEtiquetat amb paràmetres: // a MNT: Y, size: j, rank: div(aux4,aux5) // b MNT: W, size: (n-j), rank: mod(aux4, aux5) return(Prod(unrankNoEtiquetat(spec,op(taula[MNT],1),taula,j,_div(aux4,aux5),aux1),unrankNoEtiquetat(spec,op(taula[MNT],2),taula,(n - j),_mod(aux4,aux5),aux1))); end_proc;

A continuació cal tractar amb les funcions d’unranking per Powersets i Sets, que són les més

complicades. Per tal d’abordar-les, primer cal implementar el càlcul de les deltes (tal i com

hem vist en l’apartat anterior). Com que el cost de l’algorisme per calcular aquestes deltes

no és trivial, ens interessar que el nombre de crides a aquesta funció sigui el més petit

possible. És per això, que en aquest moment es farà ús d’una opció força interessant que ens

ofereix Mupad: la opció remember. Aquesta paràmetre modifica la funció a la que

acompanya de tal manera que aquesta recorda els resultats que han estat calculats

prèviament. Així, per tal de calcular les deltes, tindrem una primer funció anomenada

taulaDelta que calcularà les deltes amb valors per n entre 1 i la mida passada com a

paràmetre. D’aquesta manera, quan més endavant alguna funció d’unrank demani un valor

de delta que es trobi entre les ja calculades, el cost per obtenir aquesta serà 0.

cod.30 taulaDeltaPowerset := proc(spec, MNT, taula, size, rank, aux1) local i, j, auxil, resul, delta; //Per si mai ens tornen a demanar que generem aquesta taula en concret, activem la opció //remember. option remember; begin //El que farem serà anar fent crides a la funció que calcula les deltes pròpiament dita per valors //que aniran variant d’n i j. Per fer això, farem un bucle on la i anirà des de 1 fins a n, i la j es //decrementarà des del valor de i fins a 1. Així haurem generat totes les possibles combinacions //de n i j. i := 1; if i <= size then while i <= size do j := i; while j >= 1 do auxil := calculaDeltaPowerset(MNT, taula, i, aux1, j); //Els valors de les deltes els anirem guardant en una taula per si en algun moment, més //endavant, els necessitem.

Page 111: Títol: Generació Ordenada d’Estructures Combinatòries en

PFC – Generació Ordenada d’Estructures Combinatòries en “MuPAD-Combinat”

111

delta["delta-".i."-".j] := auxil; j := j - 1; end_while; i := i + 1; end_while; else delta := []; end_if; //Finalment, personalitzem una mica la taula resultat perquè quedi clar que aquests valors de //delta són vàlids per a una spec concreta i partint d’un MNT concret. resul[espec] := spec; resul[main] := MNT; resul[mida] := size; resul[deltes] := delta; return(resul); end_proc;

Ara doncs, ens cal veure el codi per a la funció encarregada del càlcul de les deltes. Aquesta

funció implementa la operació per al càlcul de les deltes dels Powersets que s’ha vist en

apartats anteriors i la seva estructura és de tipus recursiu.

cod.31 calculaDeltaPowerset := proc(MNT, taula, size, auxil, midaj) local aux1, aux2, aux3, k; //Tal i com hem dit abans, en aquesta funció és crucial la utilització de l’opció remember per tal //d’evitar futurs càlculs carregosos innecessàris. option remember; begin //Primer implementem els diversos casos base que ens serviran d’aturador per la recursivitat. if size = 0 then return(1); elif size < midaj then return(0); elif size = midaj then //Una de les situacions curioses de la fórmula presentada succeeix quan els valors de la n i la j //coincideixen; la fórmula es simplifica i acabem obtenint que el valor de la delta és aj. Per tant, //en aquest cas només ens cal realitzar un count sobre la classe sobre la que tenim el Powerset. return(auxil::count(size,op(taula[MNT],1))); elif size > midaj then //Aquí és on entra en joc la recursivitat. Calculem la delta per n i (j+1), i després l’acumulat de les //diverses deltes per (n - kj) i (j + 1). aux1 := calculaDeltaPowerset(MNT, taula, size, auxil, (midaj+1)); k := 1; while k <= trunc(size/midaj) do aux2 := auxil::count(midaj, op(taula[MNT],1)); aux3 := combinat::chooseNK::count(aux2, k); aux1 := aux1 + (aux3 * calculaDeltaPowerset(MNT, taula, (size-(k*midaj)), auxil, (midaj+1))); k := k +1; end_while; //Finalment retornem el valor de la delta per n i j. return(aux1); end_if; end_proc;

Ara ja podem veure el codi encarregat de fer l’unranking per al constructor Powerset, que es

correspon amb l’algorisme 4 vist en apartats anteriors.

Page 112: Títol: Generació Ordenada d’Estructures Combinatòries en

Capítol IV – Unranking

112

cod.32 unrankPowersetNoEtiquetat := proc(spec, MNT, taula, n, i, aux1, t) local j, auxil, auxil2, iaux1, iaux2, ialfa, ibeta, c, d, k, taux; option remember; begin //Si ens demanen els Powersets amb elements de mida 0, simplement retornarem l’Epsilon (que, //a més, també haurà d’aparèixer en tots els Powersets). if n = 0 then return(Epsilon); end_if; //Donat que hem fet servir la opció remember, no ens haurem de preocupar del cost de //calcular les diverses Deltes que anem necessitant. j := 1; auxil := calculaDeltaPowerset(MNT, taula, n, aux1, 1); auxil2 := auxil - (calculaDeltaPowerset(MNT, taula, n, aux1, (j+1))); while auxil2 <= i do j := j + 1; auxil2 := auxil - (calculaDeltaPowerset(MNT, taula, n, aux1, (j+1))); end_while; iaux1 := i - (auxil - (calculaDeltaPowerset(MNT, taula, n, aux1, j))); if j = n then k := 1; iaux2 := iaux1; else //En aquest punt, si volguéssim variar l’ordre de generació dels Powersets per tal de què no //anessin apareixent de menor a major, hauríem d’introduir alguns canvis: en l’assignació que //fem a continuació a k, en comptes d’un 1 hi hauríem de posar ; en la condició del bucle //while de sota, s’hauria de substituir l’expressió de l’esquerra de l’and per k > 0; i finalment, dins //del bucle, en comptes d’incrementar la k, l’hauríem de decrementar. k := 1; c := 0; auxil := calculaDeltaPowerset(MNT, taula, (n - (k*j)), aux1, (j+1)); d := (combinat::chooseNK::count(aux1::count(j,op(taula[MNT],1)), k))* auxil; while ((k+1)*j <= n) and ((c + d) <= iaux1) do c := c + d; k := k + 1; auxil := calculaDeltaPowerset(MNT, taula, (n - (k*j)), aux1, (j+1)); d := (combinat::chooseNK::count(aux1::count(j,op(taula[MNT],1)), k))* auxil; end_while; iaux2 := iaux1 - c; end_if; auxil := calculaDeltaPowerset(MNT, taula, (n - (k*j)), aux1, (j+1)); ialfa := _div(iaux2, auxil); ibeta := _mod(iaux2, auxil) + (calculaDeltaPowerset(MNT, taula, (n - (k*j)), aux1, 1) - auxil); //Com que el valor de la n per la crida recursiva a unrankPowersetNoEtiquetat ha canviat, //tornem a invocar la funció per el càlcul de les deltes amb el nou valor de n. taux := taulaDeltaPowerset(spec, MNT, taula, (n - (k*j)), ibeta, aux1); return(( rhs(op(unrankPowersetAjkNoEtiquetat( spec, op(taula[MNT],1), taula, j, k, (k*j), ialfa, aux1, taux))), unrankPowersetNoEtiquetat(spec,MNT,taula,(n - (k*j)),ibeta,aux1,taux) )); end_proc;

Ara ens cal veure també el codi per a la funció d’unranking de Powersets de k components

de mida j, és a dir, el codi que adapta l’algorisme 5.

⎣ ⎦jn

Page 113: Títol: Generació Ordenada d’Estructures Combinatòries en

PFC – Generació Ordenada d’Estructures Combinatòries en “MuPAD-Combinat”

113

cod.33 unrankPowersetAjkNoEtiquetat := proc(spec, MNT, taula, j, k, n, i, aux1, t) local l, L, iaux, m, r, d, alfes; option remember; begin //Com abans, si ens estan donant la mida 0, aleshores hem de retornar l’element Epsilon. if n = 0 then return(Epsilon); end_if; L[0] := 0; iaux := i; //En aquest primer bucle obtindrem els ranks de les diverses components de mida j que posseeix //el powerset. Aquests ranks els anirem guardant en una llista que en el següent bucle //recorrerem i farem servir per anar invocant la funció d’unrankNoEtiquetat i així anar obtenint els //diversos objectes (les components), que al seu temps també anirem guardant en una taula //que, finalment, serà el resultat que retornarem. És per això que en la funció anterior, //unrankPowersetNoEtiquetat, havíem de fer un rhs(op()) al resultat de la crida a //unrankPowersetAjkNoEtiquetat. for l from 1 to k do m := 1; r := 0; d := combinat::chooseNK::count((aux1::count(j,MNT) - L[(l - 1)] - m), (k - 1)); while (r + d) <= iaux do r := r + d; m := m + 1; d := combinat::chooseNK::count((aux1::count(j,MNT) - L[(l - 1)] - m), (k - 1)); end_while; iaux := iaux - r; L[l] := m + L[(l - 1)]; end_for; for l from 1 to k do alfes["alfa-".l] := unrankNoEtiquetat(spec, MNT, taula, j, (L[l] - 1), aux1); end_for; //Retornem la taula amb les k components de mida j que li pertoquen al powerset. return(alfes); end_proc;

Finalment, per tancar els Powersets cal que implementem les funcions destinades a cobrir els

casos en què tinguem restriccions de cardinalitat. Com ja hem vist, per aquests casos, el

càlcul de les deltes varia una mica, i per tant, cal implementar unes noves funcions per al

càlcul de les deltes amb cardinalitat restringida.

cod.34 taulaDeltaPowersetRestrictedCard := proc(spec, MNT, taula, size, rank, card, aux1) local i, j, auxil, resul, delta; option remember; begin //El funcionament d’aquesta funció és anàleg al vist per a les deltes sense cardinalitat //restringida. Tan sols varia la crida a la funció, que en aquest cas incorpora un paràmetre més, //la cardinalitat. i := 1; if i <= size then while i <= size do j := i; while j >= 1 do auxil := calculaDeltaPowersetRestrictedCard(MNT, taula, i, aux1, j, card); delta["delta-".i."-".j."-".card] := auxil; j := j - 1;

Page 114: Títol: Generació Ordenada d’Estructures Combinatòries en

Capítol IV – Unranking

114

end_while; i := i + 1; end_while; else delta := []; end_if; resul[espec] := spec; resul[main] := MNT; resul[mida] := size; resul[deltes] := delta; return(resul); end_proc;

En el cas del càlcul de les deltes cal anar amb una mica més de compte, ja que ara ens

apareixen algunes situacions concretes més problemàtiques.

cod.35 calculaDeltaPowersetRestrictedCard := proc(MNT, taula, size, auxil, midaj, card) local aux1, aux2, aux3, l, cont; option remember; begin if (size = 0) and (card = 0) then return(1); elif size < midaj then return(0); elif size = midaj then //Si analitzem la fórmula per al cas en què la n i la j són iguals, veiem que, si el valor de la //cardinalitat és diferent de 1, aleshores realment retornarem un 0; emperò no ens podem //arriscar a què s’arribi a aquest punt automàticament, ja que si per un casual la cardinalitat //prengués per valor 0, aleshores rebríem un missatge d’error en intentar calcular el //chooseNK. Per tant, això ho evitem posant el següent condicional. if card <> 1 then return (0); elif card = 1 then return(auxil::count(size,op(taula[MNT],1))); end_if; elif size > midaj then aux1 := calculaDeltaPowersetRestrictedCard(MNT, taula, size, auxil, (midaj+1), card); l := 1; //Com abans, per evitar mal funcionaments, cal que si la j és 0, no es faci la divisió entre n i j. Per //tant, de nou posem un condicional per solucionar-ho. if midaj = 0 then cont := card; else cont := (min(trunc(size/midaj),card)); end_if; while l <= cont do aux2 := auxil::count(midaj, op(taula[MNT],1)); aux3 := combinat::chooseNK::count(aux2, l); aux1 := aux1 + (aux3 * calculaDeltaPowersetRestrictedCard(MNT, taula, (size-(l*midaj)), auxil, (midaj+1), (card - l))); l := l + 1; end_while; return(aux1); end_if; end_proc;

I ara ja podem veure els codis per al càlcul de l’unrank dels Powersets quan aquest

apareixen acompanyats per l’extra Length, MinLength ó MaxLength. Primer veurem el codi

corresponent a l’algorisme 8.

Page 115: Títol: Generació Ordenada d’Estructures Combinatòries en

PFC – Generació Ordenada d’Estructures Combinatòries en “MuPAD-Combinat”

115

cod.36

unrankPowersetNoEtiquetatRestrictedCard := proc(spec, MNT, taula, n, i, card, aux1, t) local j, auxil, auxil2, iaux1, iaux2, ialfa, ibeta, c, d, p, taux; option remember; begin //Si l’extra que ens han passat és Length, aleshores en la comparació inicial, no només cal que //mirem si la n és 0; en cas de què la cardinalitat sigui 0, haurem de retornar l’objecte Epsilon. if (n = 0) or (card = 0) then return(Epsilon); end_if; j := 1; auxil := calculaDeltaPowersetRestrictedCard(MNT, taula, n, aux1, 1, card); auxil2 := auxil - (calculaDeltaPowersetRestrictedCard(MNT, taula, n, aux1, (j+1), card)); //Amb el següent bucle trobarem la mida de la component més petita, que serà j. while auxil2 <= i do j := j + 1; auxil2 := auxil - (calculaDeltaPowersetRestrictedCard(MNT, taula, n, aux1, (j+1), card)); end_while; iaux1 := i - (auxil - (calculaDeltaPowersetRestrictedCard(MNT, taula, n, aux1, j, card))); p := 1; c := 0; d := combinat::chooseNK::count((aux1::count(j,op(taula[MNT],1))),p) * (calculaDeltaPowersetRestrictedCard(MNT, taula, (n - (p*j)), aux1, (j+1), (card-p))); //A continuació sabrem quantes components del Powerset tenen mida j. while ((c+d) <= i) and (p <= card) do c := c + d; p := p + 1; d := combinat::chooseNK::count((aux1::count(j,op(taula[MNT],1))),p) * (calculaDeltaPowersetRestrictedCard(MNT, taula, (n - (p*j)), aux1, (j+1), (card-p))); end_while; iaux2 := iaux1 - c; auxil := (calculaDeltaPowersetRestrictedCard(MNT, taula, (n - (p*j)), aux1, (j+1), (card-p))); ialfa := _div(iaux2, auxil); ibeta := _mod(iaux2, auxil) + (calculaDeltaPowersetRestrictedCard(MNT, taula, (n - (p*j)), aux1, 0, (card - p)) - auxil); taux := taulaDeltaPowersetRestrictedCard(spec, MNT, taula, (n - (p*j)),ibeta,(card -p),aux1); //I finalment, obtenim les p components de mida j del Powerset, i invoquem un altre cop la //funció unrankPowersetNoEtiquetatRestrictedCard però amb cardinalitat = (k - p) (que seran el //nombre de components que encara ens falten), i mida = (n - pj). return(( rhs(op(unrankPowersetAjkNoEtiquetat( spec, op(taula[MNT],1), taula, j, p, (p*j), ialfa, aux1, taux))), unrankPowersetNoEtiquetatRestrictedCard(spec,MNT,taula,(n - (p*j)),ibeta,(card-p),aux1,taux) )); end_proc;

El següent fragment de codi és l’equivalent a l’algorisme 9 per Powersets amb cardinalitat

major o igual a k.

Page 116: Títol: Generació Ordenada d’Estructures Combinatòries en

Capítol IV – Unranking

116

cod.37

unrankPowersetNoEtiquetatMinLength := proc(spec, MNT, taula, n, i, card, aux1, t) local j, auxil, auxil2, iaux1, iaux2, ialfa, ibeta, c, d, k; option remember; begin //Com abans, cal controlar el cas en què la n o la card siguin 0. if (n = 0) or (card = 0) then return(Epsilon); end_if; c := 0; k := card; d := calculaDeltaPowersetRestrictedCard(MNT, taula, n, aux1, 0, k); //Cal que mirem quants Powersets existeixen amb mida més gran o igual que k per saber quin //serà el valor del rank per a aquest conjunt, i guardem aquest valor a c. while (c + d) <= i do c := c + d; k := k + 1; d := calculaDeltaPowersetRestrictedCard(MNT, taula, n, aux1, 0, k); end_while; //Invoquem al càlcul dels Powersets amb una cardinalitat fixada, però fent servir els valors de k //per la cardinalitat i (i – c) per al rang. return(unrankPowersetNoEtiquetatRestrictedCard(spec,MNT,taula,n,(i - c),k,aux1,t)); end_proc;

I tancant el codi referent als Powersets, seguidament es pot veure el fragment de codi

equivalent a l’algorisme 10 per Powersets amb cardinalitat menor o igual a k.

cod.38

unrankPowersetNoEtiquetatMaxLength := proc(spec, MNT, taula, n, i, card, aux1, t) local j, auxil, auxil2, iaux1, iaux2, ialfa, ibeta, c, d, k; option remember; begin //Controlem el cas en què la mida o la cardinalitat donada siguin zero. if (n = 0) or (card = 0) then return(Epsilon); end_if; //Com ja s’ha dit, no cal preocupar-se pel cost de les operacions de càlcul de les deltes. c := 0; k := 1; d := calculaDeltaPowersetRestrictedCard(MNT, taula, n, aux1, 0, k); //Ara actuarem de manera similar a com ho hem fet en el codi anterior, però en aquest cas la k //es mourà des de 1 fins, com a màxim, la cardinalitat. while (c + d) <= i do c := c + d; k := k + 1; d := calculaDeltaPowersetRestrictedCard(MNT, taula, n, aux1, 0, k); end_while; //Invoquem al càlcul dels Powersets amb una cardinalitat fixada, però fent servir els valors de k //per la cardinalitat i (i – c) per al rang. return(unrankPowersetNoEtiquetatRestrictedCard(spec,MNT,taula,n,(i - c),k,aux1,t)); end_proc;

Tal i com ja sabem per tot el que hem vist en l’apartat anterior, el funcionament per als Sets

és molt similar al dels Powersets. Tan sols s’han de fer unes petites variacions en el càlcul de

les deltes i en els algorismes d’unrank per tal de tenir en compte el fet de que podem tenir

components repetides. Així, els fragments de codi que veurem a continuació estaran

mínimament comentats.

Page 117: Títol: Generació Ordenada d’Estructures Combinatòries en

PFC – Generació Ordenada d’Estructures Combinatòries en “MuPAD-Combinat”

117

El primer que veurem doncs, serà el codi encarregat de calcular les deltes. Com abans,

tindrem una primera funció encarregada de generar totes les possibles crides a la funció de

càlcul de les deltes.

cod.39

taulaDeltaSet := proc(spec, MNT, taula, size, rank, aux1) local i, j, auxil, resul, delta; option remember; begin //Aquesta funció no presenta variacions respecte al seu equivalent per Powersets. i := 1; if i <= size then while i <= size do j := i; while j >= 1 do auxil := calculaDeltaSet(MNT, taula, i, aux1, j); delta["delta-".i."-".j] := auxil; j := j - 1; end_while; i := i + 1; end_while; else delta := []; end_if; resul[espec] := spec; resul[main] := MNT; resul[mida] := size; resul[deltes] := delta; return(resul); end_proc;

cod.40

calculaDeltaSet := proc(MNT, taula, size, auxil, midaj) local aux1, aux2, aux3, k; option remember; begin //Els canvis que implementa aquest fragment de codi són els necessaris per adaptar la fórmula //del càlcul de les deltes per Sets. És a dir, bàsicament només varien les crides a chooseNK. if size = 0 then return(1); elif size < midaj then return(0); elif size = midaj then return(auxil::count(size,op(taula[MNT],1))); elif size > midaj then aux1 := calculaDeltaSet(MNT, taula, size, auxil, (midaj+1)); k := 1; while k <= trunc(size/midaj) do aux2 := auxil::count(midaj, op(taula[MNT],1)); aux3 := combinat::chooseNK::count((aux2 + (k - 1)), k); aux1 := aux1 + (aux3 * calculaDeltaSet(MNT, taula, (size-(k*midaj)), auxil, (midaj+1))); k := k + 1; end_while; return(aux1); end_if; end_proc;

A continuació podem veure el codi que adapta l’algorisme 6.

Page 118: Títol: Generació Ordenada d’Estructures Combinatòries en

Capítol IV – Unranking

118

cod.41

unrankSetNoEtiquetat := proc(spec, MNT, taula, n, i, aux1, t) local j, auxil, auxil2, iaux1, iaux2, ialfa, ibeta, c, d, k, taux; option remember; begin //En la funció encarregada de generar l’unrank dels sets, els canvis que es poden observar són //dos: les crides a les deltes ara es fan a la funció específica per a sets; la crida a chooseNK //també ha variat per tal de cobrir la possibilitat de tenir components repetides. if n = 0 then return(Epsilon); end_if; j := 1; auxil := calculaDeltaSet(MNT, taula, n, aux1, 1); auxil2 := auxil - (calculaDeltaSet(MNT, taula, n, aux1, (j+1))); while auxil2 <= i do j := j + 1; auxil2 := auxil - (calculaDeltaSet(MNT, taula, n, aux1, (j+1))); end_while; iaux1 := i - (auxil - (calculaDeltaSet(MNT, taula, n, aux1, j))); if j = n then k := 1; iaux2 := iaux1; else k := 1; c := 0; auxil := calculaDeltaSet(MNT, taula, (n - (k*j)), aux1, (j+1)); d := (combinat::chooseNK::count((aux1::count(j,op(taula[MNT],1))+k-1), k))* auxil; while ((k+1)*j <= n) and ((c + d) <= iaux1) do c := c + d; k := k + 1; auxil := calculaDeltaSet(MNT, taula, (n - (k*j)), aux1, (j+1)); d := (combinat::chooseNK::count((aux1::count(j,op(taula[MNT],1))+k-1), k))* auxil; end_while; iaux2 := iaux1 - c; end_if; auxil := calculaDeltaSet(MNT, taula, (n - (k*j)), aux1, (j+1)); ialfa := _div(iaux2, auxil); ibeta := _mod(iaux2, auxil) + (calculaDeltaSet(MNT, taula, (n - (k*j)), aux1, 1) - auxil); taux := taulaDeltaSet(spec, MNT, taula, (n - (k*j)), ibeta, aux1); return(( ( (op(unrankSetAjkNoEtiquetat( spec, op(taula[MNT],1), taula, j, k, (k*j), ialfa, aux1, t)) ) ) , unrankSetNoEtiquetat(spec,MNT,taula,(n - (k*j)),ibeta,aux1,t) )); end_proc;

L’algorisme 7, tal i com passava amb el seu equivalent per als Powersets, s’ha pogut

codificar pràcticament sense cap canvi.

cod.42

unrankSetAjkNoEtiquetat := proc(spec, MNT, taula, j, k, n, i, aux1, t) local l, L, iaux, m, r, d, alfes; option remember; begin if n = 0 then return(Epsilon); end_if; alfes := [];

Page 119: Títol: Generació Ordenada d’Estructures Combinatòries en

PFC – Generació Ordenada d’Estructures Combinatòries en “MuPAD-Combinat”

119

if k = 1 then alfes := append(alfes, unrankNoEtiquetat(spec, MNT, taula, j, i, aux1)); else if (aux1::count(j,MNT) = 1) then for l from 1 to k do alfes := append(alfes, unrankNoEtiquetat(spec, MNT, taula, j, 0, aux1)); end_for; else L[0] := 0; iaux := i; for l from 1 to k do m := 1; r := 0; d := combinat::chooseNK::count(( (aux1::count(j,MNT) - L[(l - 1)] - m) + (k - 1) - 1), (k - 1)); while (r + d) <= iaux do r := r + d; m := m + 1; d := combinat::chooseNK::count(( (aux1::count(j,MNT) - L[(l - 1)] - m) + (k - 1) - 1), (k - 1), (k - 1)); end_while; iaux := iaux - r; L[l] := m + L[(l - 1)]; end_for; for l from 1 to k do alfes := append(alfes, unrankNoEtiquetat(spec, MNT, taula, j, (L[l] - 1), aux1)); end_for; end_if; end_if; return(alfes); end_proc;

Ja vist l’unrank per als Sets “bàsics”, passem ara a parlar dels casos en què apareguin

acompanyats d’algun restrictor de cardinalitat. Com ja sabem, és necessària una nova delta

per a poder cobrir aquest cas. Així, a continuació veurem els ja coneguts fragments de codi

que generen la taula de deltes i les calculen.

cod.43

taulaDeltaSetRestrictedCard := proc(spec, MNT, taula, size, rank, card, aux1) local i, j, auxil, resul, delta; option remember; begin //Com en el cas dels powersets, ara també cal tenir en compte la cardinalitat... i := 1; if i <= size then while i <= size do j := i; while j >= 1 do auxil := calculaDeltaSetRestrictedCard(MNT, taula, i, aux1, j, card); delta["delta-".i."-".j."-".card] := auxil; j := j - 1; end_while; i := i + 1; end_while; else delta := []; end_if; resul[espec] := spec;

Page 120: Títol: Generació Ordenada d’Estructures Combinatòries en

Capítol IV – Unranking

120

resul[main] := MNT; resul[mida] := size; resul[deltes] := delta; return(resul); end_proc;

cod.44

calculaDeltaSetRestrictedCard := proc(MNT, taula, size, auxil, midaj, card) local aux1, aux2, aux3, l, cont; option remember; begin //Com en els altres casos, aquí cal anar bàsicament en compte en els possibles casos específics //que ens puguem trobar en la fórmula. En aquest cas, són els mateixos vistos en el cas del //càlcul de les deltes per als powersets, però també haurem d’aplicar els canvis pertinents de la //fórmula per adaptar-la al cas dels sets (és a dir, tenir en compte el canvi que es produeix en els //chooseNK). if (size = 0) and (card = 0) then return(1); elif size < midaj then return(0); elif size = midaj then if card <> 1 then return (0); elif card = 1 then return(auxil::count(size,op(taula[MNT],1))); end_if; elif size > midaj then aux1 := calculaDeltaSetRestrictedCard(MNT, taula, size, auxil, (midaj+1), card); l := 1; if midaj = 0 then cont := card; else cont := (min(trunc(size/midaj),card)); end_if; while l <= cont do aux2 := auxil::count(midaj, op(taula[MNT],1)); aux3 := combinat::chooseNK::count(((aux2+l)-1), l); aux1 := aux1 + (aux3 * calculaDeltaSetRestrictedCard(MNT, taula, (size-(l*midaj)), auxil, (midaj+1), (card - l))); l := l + 1; end_while; return(aux1); end_if; end_proc;

Per tancar els casos dels Sets i de l’unrank no etiquetat, ja només ens queda veure la

implementació dels algorismes d’unrank per als Sets amb cardinalitat restringida.

El primer que veurem serà l’equivalent a l’algorisme 11, és a dir, l’unranking de Sets amb

cardinalitat fixada.

cod.45

unrankSetNoEtiquetatRestrictedCard := proc(spec, MNT, taula, n, i, card, aux1, t) local j, auxil, auxil2, iaux1, iaux2, ialfa, ibeta, c, d, p, taux; option remember; begin //El funcionament és exactament el mateix que en el cas dels Powersets, però amb els petits //canvis que ja coneixem, que són: crides a la delta pertinent per a aquest cas; i la modificació //de les crides a chooseNK. if (n = 0) or (card = 0) then

Page 121: Títol: Generació Ordenada d’Estructures Combinatòries en

PFC – Generació Ordenada d’Estructures Combinatòries en “MuPAD-Combinat”

121

return(Epsilon); end_if; j := 1; auxil := calculaDeltaSetRestrictedCard(MNT, taula, n, aux1, 1, card); auxil2 := auxil - (calculaDeltaSetRestrictedCard(MNT, taula, n, aux1, (j+1), card)); while auxil2 <= i do j := j + 1; auxil2 := auxil - (calculaDeltaSetRestrictedCard(MNT, taula, n, aux1, (j+1), card)); end_while; iaux1 := i - (auxil - (calculaDeltaSetRestrictedCard(MNT, taula, n, aux1, j, card))); p := 1; c := 0; d := combinat::chooseNK::count((((aux1::count(j,op(taula[MNT],1)))+p)-1),p) * (calculaDeltaSetRestrictedCard(MNT, taula, (n - (p*j)), aux1, (j+1), (card-p))); while ((c+d) <= i) and (p <= card) do c := c + d; p := p + 1; d := combinat::chooseNK::count((((aux1::count(j,op(taula[MNT],1)))+p)-1),p) * (calculaDeltaSetRestrictedCard(MNT, taula, (n - (p*j)), aux1, (j+1), (card-p))); end_while; iaux2 := iaux1 - c; auxil := (calculaDeltaSetRestrictedCard(MNT, taula, (n - (p*j)), aux1, (j+1), (card-p))); ialfa := _div(iaux2, auxil); ibeta := _mod(iaux2, auxil) + (calculaDeltaSetRestrictedCard(MNT, taula, (n - (p*j)), aux1, 0, (card - p)) - auxil); taux := taulaDeltaSetRestrictedCard(spec, MNT, taula, (n - (p*j)),ibeta,(card -p),aux1); return(( op(unrankSetAjkNoEtiquetat( spec, op(taula[MNT],1), taula, j, p, (p*j), ialfa, aux1, t)), unrankSetNoEtiquetatRestrictedCard(spec,MNT,taula,(n - (p*j)),ibeta,(card-p),aux1,taux) )); end_proc;

Anem a veure ara la implementació de l’algorisme 12, és a dir, per al cas en què el Set

aparegui acompanyat pel restrictor MinLength.

cod.46

unrankSetNoEtiquetatMinLength := proc(spec, MNT, taula, n, i, card, aux1, t) local j, auxil, auxil2, iaux1, iaux2, ialfa, ibeta, c, d, k; option remeber; begin //El seu funcionament és totalment igual al del seu anàleg per als Powersets. if (n = 0) or (card = 0) then return(Epsilon); end_if; c := 0; k := card; d := calculaDeltaSetRestrictedCard(MNT, taula, n, aux1, 0, k); while (c + d) <= i do c := c + d; k := k + 1; d := calculaDeltaSetRestrictedCard(MNT, taula, n, aux1, 0, k); end_while; return(unrankSetNoEtiquetatRestrictedCard(spec,MNT,taula,n,(i - c),k,aux1,t)); end_proc;

Page 122: Títol: Generació Ordenada d’Estructures Combinatòries en

Capítol IV – Unranking

122

I finalment, el codi per als Sets acompanyats per l’extra MaxLength, és a dir, l’algorisme 13.

cod.47

unrankSetNoEtiquetatMaxLength := proc(spec, MNT, taula, n, i, card, aux1, t) local j, auxil, auxil2, iaux1, iaux2, ialfa, ibeta, c, d, k; begin //El seu funcionament és totalment igual al del seu anàleg per als Powersets. if (n = 0) or (card = 0) then return(Epsilon); end_if; c := 0; k := 1; d := calculaDeltaSetRestrictedCard(MNT, taula, n, aux1, 0, k); while (c + d) <= i do c := c + d; k := k + 1; d := calculaDeltaSetRestrictedCard(MNT, taula, n, aux1, 0, k); end_while; return(unrankSetNoEtiquetatRestrictedCard(spec,MNT,taula,n,(i - c),k,aux1,t)); end_proc;

Page 123: Títol: Generació Ordenada d’Estructures Combinatòries en

PFC – Generació Ordenada d’Estructures Combinatòries en “MuPAD-Combinat”

123

Un cop vist el codi referent a l’unrank no etiquetat, podem passar a veure el seu equivalent

per a les classes etiquetades. Com abans, començarem veient la funció principal, la qual

també té una estructura condicional on, depenent del constructor que estiguem tractant,

s’invocarà una o altra funció d’unrank específica.

Ara bé, ens cal també saber en quin format retornarem les etiquetes. Les subfuncions

d’unrank retornen una llista de llistes, on cada subllista retornada per les subfuncions és al

seu torn el subetiquetatge corresponent al subobjecte generat. Per exemple, si l’unrank

retorna [[Z,Z,0],[Z,Z,1],2], aquest objecte es correspondria a l’arbre binari Prod(Prod(Z(1),

Z(4)), Prod(Z(3), Z(2))). La tercera component de cada subllista indica el rank de l’element a

agafar entre les ⎟⎟⎠

⎞⎜⎜⎝

⎛jn -particions possibles, on n és la talla de l’objecte total, i j és la talla de

l’objecte de la primera component. Així, seguint amb l’exemple anterior, a partir de [Z,Z,0],

obtindrem [Z(1),Z(2)] (volem la 0-èsima partició entre les ⎟⎟⎠

⎞⎜⎜⎝

⎛12 possibles). Per la seva banda,

[Z,Z,1] es converteix al seu torn en [Z(2),Z(1)]. I per tant, a partir de [[Z,Z,0],[Z,Z,1],2]

tenim la llista [[Z(1),Z(2)],[Z(2),Z(1)],2], a la qual podem aplicar de nou el procés tot

considerant la 2-èsima partició de ⎟⎟⎠

⎞⎜⎜⎝

⎛24 i obtenir (0-èsima, [Z(1), Z(2), Z(4), Z(3)]) (1-

èsima, [Z(1), Z(3), Z(4), Z(2)]) (2-èsima, [Z(1), Z(4), Z(3), Z(2)] ).

Així doncs, podríem dir que el procés d’etiquetatge consisteix en passar de l’etiqueta

retornada per l’unrank a una etiqueta en format més entenedor mitjançant un determinat

desenvolupament:

[[Z,Z,0],[Z,Z,1],2] [[Z(1),Z(2)],[Z(2),Z(1)],2] [Z(1), Z(4), Z(3), Z(2)]

cod.48

unrankEtiquetat:=proc(spec, MNT, taula, n, i, aux1) local const, aux; begin //Per al cas de l’unranking etiquetat, com ja hem dit abans, crearem l’objecte i l’etiqueta //separadament. Per això, en totes les funcions d’unrank etiquetat retornarem una taula de dos //elements: el primer, l’objecte, i el segon, l’etiqueta. aux := []; //Si en la banda dreta de la posició MNT de la taula no hi tenim cap constructor, farem una //crida recursiva cap a la pròpia funció però canviant el valor de MNT. if op(taula[MNT],0) = FAIL then return(unrankEtiquetat(spec,taula[MNT],taula,n,i,aux1)); else //En canvi, si sabem segur que hi ha un constructor... if op(taula[MNT],0) = Primitive then //En el cas que ens trobem el constructor Primitive, caldrà que ens assegurem primer de què ens //estan demanant per l’únic element que existeix. if i <> 0 then return(FAIL); else if n <> op(taula[MNT],1) then return(FAIL);

Page 124: Títol: Generació Ordenada d’Estructures Combinatòries en

Capítol IV – Unranking

124

else //Si tot és correcte, retornarem l’identificador que acompanya al constructor o, en cas de no //haver-ne, Epsilon. L’etiqueta que acompanyarà a un objecte de talla 0 sempre serà 0, i //l’etiqueta que acompanyarà a un objecte de talla 1 serà 1. if nops(taula[MNT]) = 1 then return(table(1 = Epsilon, 2 = 0)); else if n = 0 then return(table(1 = op(taula[MNT],2), 2 = 0)); else return(table(1 = op(taula[MNT],2), 2 = 1)); end_if; end_if; end_if; end_if; elif op(taula[MNT],0) = Alias then //Com abans, quan ens trobem amb el constructor Alias, cal analitzar per quin cas hi estem: //Prod, Sequence, Cycle o Set. if op(op(taula[MNT],2),3) = arrow then else //Si el segon paràmetre del constructor Alias està composat al seu temps per dos elements, cal //que esbrinem en quina situació ens trobem: l’alias d’un Producte; l’alias d’un BoxedProd; o //l’alias d’un Set/Sequence/Cycle. if nops(op(taula[MNT],2)) = 2 then if op(taula[op(taula[MNT],1)],0) = Prod then aux := unrankEtiquetat(spec,op(taula[MNT],1),taula,n,i,aux1); return(table(1 = op(op(taula[MNT],2),1)( op(aux[1])), 2 = aux[2])); elif op(taula[op(taula[MNT],1)],0) = BoxedProd then aux := unrankEtiquetat(spec,op(taula[MNT],1),taula,n,i,aux1); return(table(1 = op(op(taula[MNT],2),1)( op(aux[1])), 2 = aux[2])); else aux := unrankEtiquetat(spec,op(taula[MNT],1),taula,n,i,aux1); return(table(1 = op(op(taula[MNT],2),1)(aux[1]), 2 = aux[2])); end_if; else //Com en el cas no etiquetat, pot ser que ens trobem amb un Alias de la forma X = Alias(Y)... if nops(taula[MNT]) = 1 then aux := unrankEtiquetat(spec,op(taula[MNT],1),taula,n,i,aux1); return(table(1 = aux[1], 2 = aux[2])); else //O amb un Alias de la forma X = Alias(Y, op), amb la qual cosa haurem d’aplicar l’op... aux := unrankEtiquetat(spec,op(taula[MNT],1),taula,n,i,aux1); return(table(1 = op(op(taula[MNT],2),1)(aux[1]), 2 = aux[2])); end_if; end_if; end_if; //Si el constructor és Union, només cal invocar la subfunció pertinent. elif op(taula[MNT],0) = Union then return(unrankUnionEtiquetat(spec,MNT,taula,n,i,aux1)); //Per al constructor Prod, cal que diferenciem entre els casos d’ordre lexicogràfic i bustrofèdic. elif op(taula[MNT],0) = Prod then if rhs(op(spec,2)) then return(unrankProdEtiquetatBustrofedic(spec,MNT,taula,n,i,aux1));

Page 125: Títol: Generació Ordenada d’Estructures Combinatòries en

PFC – Generació Ordenada d’Estructures Combinatòries en “MuPAD-Combinat”

125

else return(unrankProdEtiquetatLexicografic(spec,MNT,taula,n,i,aux1)); end_if; //I finalment, els BoxedProds, casos en què també cal que diferenciem entre lexicogràfic i //bustrofèdic. elif op(taula[MNT],0) = BoxedProd then if rhs(op(spec,2)) then return(unrankBoxedProdEtiquetatBustrofedic(spec,MNT,taula,n,i,aux1)); else return(unrankBoxedProdEtiquetatLexicografic(spec,MNT,taula,n,i,aux1)); end_if; end_if; end_if; end_proc;

El següent codi és l’encarregat de realitzar l’unrank etiquetat per productes. L’algorisme base

és l’1, és a dir, el mateix que pel cas no etiquetat.

cod.49

unrankUnionEtiquetat:=proc(spec, MNT, taula, n, i, aux1) local auxil, aux2, aux3; begin auxil := aux1::count(n,op(taula[MNT],1)); aux2 := i - auxil; if aux2 < 0 then return(unrankEtiquetat(spec,op(taula[MNT],1),taula,n,i, aux1)); else return(unrankEtiquetat(spec,op(taula[MNT],2),taula,n,aux2, aux1)); end_if; end_proc;

Els algorismes per als Productes es troben com ja sabem, dividits en els casos de l’ordre

lexicogràfic i bustrofèdic. El primer que veurem serà l’equivalent a l’algorisme 14, és a dir,

per a l’ordre lexicogràfic. El funcionament per trobar l’objecte és el mateix que en el cas no

etiquetat, per tant, ens fixarem més en l’obtenció de l’etiquetatge.

cod.50

unrankProdEtiquetatLexicografic:=proc(spec, MNT, taula, n, i, aux1) local orig, equiv, aux2, aux3, aux4, aux5, auxil, c, j, d, sub1, sub2, l; begin //Com ja s’ha dit anteriorment, el que retornarem serà una taula de dues posicions: la primera //tindrà l’objecte, i la segona l’etiquetatge. c := 0; j := 0; aux2 := aux1::count(j,op(taula[MNT],1)); aux3 := aux1::count((n - j),op(taula[MNT],2)); d := aux2 * aux3; while (c + d) <= i do c := c + d;

Page 126: Títol: Generació Ordenada d’Estructures Combinatòries en

Capítol IV – Unranking

126

j := j + 1; aux2 := aux1::count(j,op(taula[MNT],1)); aux3 := aux1::count((n - j),op(taula[MNT],2)); auxil := combinat::chooseNK::count(n,j); d := auxil * aux2 * aux3; end_while; aux4 := i - c; auxil := combinat::chooseNK::count(n,j); aux5 := auxil * aux1::count((n - j),op(taula[MNT],2)); //Calculem el valor de la l tal i com ens marca l’algorisme 14. l := _mod((_mod(aux4,aux5)),auxil); //Generem els dos subojectes separadament. sub1 := unrankEtiquetat(spec,op(taula[MNT],1),taula,j,_div(aux4,aux5),aux1); sub2 := unrankEtiquetat(spec,op(taula[MNT],2),taula,(n - j), _div((_mod(aux4,aux5)),auxil),aux1); //El format d’etiqueta que generem consisteix en una llista de llistes, tal i com ja hem vist, on la l

//obtinguda és el rank de la ⎟⎟⎠

⎞⎜⎜⎝

⎛jn

partició.

if (j = 0) and ((n-j) = 0) then //Si els dos subobjectes són de mida 0, això vol dir que les dues etiquetes seran 0, i per tant, //l’etiqueta que haurem de tornar serà 0. return(table(1 = Prod(sub1[1],sub2[1]), 2 = 0)); elif (j = 0) and ((n-j) <> 0) then //Si el primer objecte és de mida 0 però el segon no, per tal d’eliminar el 0, retornarem l’etiqueta //del segon objecte. return(table(1 = Prod(sub1[1],sub2[1]), 2 = sub2[2])); elif (j <> 0) and ((n-j) = 0) then //Si el segon objecte és de mida 0 però el primer no, per tal d’eliminar el 0, retornarem l’etiqueta //del primer objecte. return(table(1 = Prod(sub1[1],sub2[1]), 2 = sub1[2])); end_if; //Si cap dels dos objectes és de mida zero, retornarem la composició de les dues etiquetes i el //valor de la l+1 (ja que els ranks d’etiquetatges comencen pel zero, i en canvi nosaltres volem //que comencin per 1). return(table(1 = Prod(sub1[1],sub2[1]), 2 = [sub1[2],sub2[2], (l+1)])); end_proc;

El codi equivalent a l’algorisme 15 presenta els mateixos canvis que el que acabem de veure

per al càlcul de les etiquetes.

cod.51

unrankProdEtiquetatBustrofedic:=proc(spec, MNT, taula, n, i, aux1) local orig, equiv, aux2, aux3, aux4, aux5, auxil, c, j, k, d, sub1, sub2, l; begin //El càlcul de l’objecte funciona d’igual manera al cas no etiquetat. c := 0; k := 0; j := 0; aux2 := aux1::count(j,op(taula[MNT],1)); aux3 := aux1::count((n - j),op(taula[MNT],2)); d := aux2 * aux3; while (c + d) <= i do c := c + d; k := k + 1; j := _div(k,2); auxil := combinat::chooseNK::count(n,j);

Page 127: Títol: Generació Ordenada d’Estructures Combinatòries en

PFC – Generació Ordenada d’Estructures Combinatòries en “MuPAD-Combinat”

127

if _mod(k,2) = 0 then aux2 := aux1::count(j,op(taula[MNT],1)); aux3 := aux1::count((n - j),op(taula[MNT],2)); else aux2 := aux1::count((n - j),op(taula[MNT],1)); aux3 := aux1::count(j,op(taula[MNT],2)); end_if; d := auxil * aux2 * aux3; end_while; if _mod(k,2) <> 0 then j := n - j; end_if; aux4 := i - c; auxil := combinat::chooseNK::count(n,j); aux5 := auxil * aux1::count((n - j),op(taula[MNT],2)); //El raonament per a l’etiquetatge és exactament igual que pel cas de l’ordre lexicogràfic. l := _mod((_mod(aux4,aux5)),auxil); sub1 := unrankEtiquetat(spec,op(taula[MNT],1),taula,j,_div(aux4,aux5),aux1); sub2 := unrankEtiquetat(spec,op(taula[MNT],2),taula,(n - j),_div((_mod(aux4,aux5)),auxil),aux1); if (j = 0) and ((n-j) = 0) then return(table(1 = Prod(sub1[1],sub2[1]), 2 = 0)); elif (j = 0) and ((n-j) <> 0) then return(table(1 = Prod(sub1[1],sub2[1]), 2 = sub2[2])); elif (j <> 0) and ((n-j) = 0) then return(table(1 = Prod(sub1[1],sub2[1]), 2 = sub1[2])); end_if; return(table(1 = Prod(sub1[1],sub2[1]), 2 = [sub1[2],sub2[2], (l+1)])); end_proc;

Els següents fragments de codi són els encarregats de tractar el cas del constructor

BoxedProd. Primer veurem la implementació de l’algorisme 16, és a dir, els BoxedProds per a

l’ordre lexicogràfic.

cod.52

unrankBoxedProdEtiquetatLexicografic:=proc(spec, MNT, taula, n, i, aux1) local orig, equiv, aux2, aux3, aux4, aux5, auxil, c, j, d, sub1, sub2, l; begin c := 0; j := 1; //El funcionament de l’algorisme és el mateix que en el cas dels Productes per ordre lexicogràfic //però els valors de la crida a chooseNK han de ser diferents. aux2 := aux1::count(j,op(taula[MNT],1)); aux3 := aux1::count((n - j),op(taula[MNT],2)); d := aux2 * aux3; while (c + d) <= i do c := c + d; j := j + 1; aux2 := aux1::count(j,op(taula[MNT],1)); aux3 := aux1::count((n - j),op(taula[MNT],2)); auxil := combinat::chooseNK::count((n-1),(j-1)); d := auxil * aux2 * aux3;

Page 128: Títol: Generació Ordenada d’Estructures Combinatòries en

Capítol IV – Unranking

128

end_while; aux4 := i - c; auxil := combinat::chooseNK::count((n-1),(j-1)); aux5 := auxil * aux1::count((n - j),op(taula[MNT],2)); //S’ha de realitzar el mateix procés per a la generació de l’etiqueta que ja s’ha vist en els casos //del producte. l := _mod((_mod(aux4,aux5)),auxil); sub1 := unrankEtiquetat(spec,op(taula[MNT],1),taula,j,_div(aux4,aux5),aux1); sub2 := unrankEtiquetat(spec,op(taula[MNT],2),taula,(n - j), _div((_mod(aux4,aux5)),auxil),aux1); if (j = 0) and ((n-j) = 0) then return(table(1 = BoxedProd(sub1[1],sub2[1]), 2 = 0)); elif (j = 0) and ((n-j) <> 0) then return(table(1 = BoxedProd(sub1[1],sub2[1]), 2 = sub2[2])); elif (j <> 0) and ((n-j) = 0) then return(table(1 = BoxedProd(sub1[1],sub2[1]), 2 = sub1[2])); end_if; return(table(1 = BoxedProd(sub1[1],sub2[1]), 2 = [sub1[2],sub2[2], (l+1)])); end_proc;

L’últim dels algorismes que ens queda veure és el 17, és a dir, l’unranking de BoxedProds

etiquetats per ordre bustrofèdic.

cod.53

unrankBoxedProdEtiquetatBustrofedic:=proc(spec, MNT, taula, n, i, aux1) local orig, equiv, aux2, aux3, aux4, aux5, auxil, c, j, k, d, sub1, sub2, l; begin c := 0; k := 0; j := _div(k,2);auxil := 1; //Com en el cas de l’ordre lexicogràfic, el codi equival al ja vist pels Productes amb ordre //bustrofèdic però variant els valors de la crida a chooseNK. aux2 := aux1::count(j,op(taula[MNT],1)); aux3 := aux1::count((n - j),op(taula[MNT],2)); d := aux2 * aux3; while (c + d) <= i do c := c + d; k := k + 1; j := _div(k,2); if _mod(k,2) = 0 then auxil := combinat::chooseNK::count((n-1),(j-1)); aux2 := aux1::count(j,op(taula[MNT],1)); aux3 := aux1::count((n - j),op(taula[MNT],2)); else auxil := combinat::chooseNK::count((n-1),j); aux2 := aux1::count((n - j),op(taula[MNT],1)); aux3 := aux1::count(j,op(taula[MNT],2)); end_if; d := auxil * aux2 * aux3; end_while; if _mod(k,2) <> 0 then j := n - j; end_if;

Page 129: Títol: Generació Ordenada d’Estructures Combinatòries en

PFC – Generació Ordenada d’Estructures Combinatòries en “MuPAD-Combinat”

129

aux4 := i - c; aux5 := auxil * aux1::count((n - j),op(taula[MNT],2)); l := _mod((_mod(aux4,aux5)),auxil); sub1 := unrankEtiquetat(spec,op(taula[MNT],1),taula,j,_div(aux4,aux5),aux1); sub2 := unrankEtiquetat(spec,op(taula[MNT],2),taula,(n - j),_div((_mod(aux4,aux5)),auxil),aux1); //El procés per a la generació de l’etiqueta és com sempre. if (j = 0) and ((n-j) = 0) then return(table(1 = BoxedProd(sub1[1],sub2[1]), 2 = 0)); elif (j = 0) and ((n-j) <> 0) then return(table(1 = BoxedProd(sub1[1],sub2[1]), 2 = sub2[2])); elif (j <> 0) and ((n-j) = 0) then return(table(1 = BoxedProd(sub1[1],sub2[1]), 2 = sub1[2])); end_if; return(table(1 = BoxedProd(sub1[1],sub2[1]), 2 = [sub1[2],sub2[2], (l+1)])); end_proc;

Els fragments de codi que veurem a continuació són aquells destinats a realitzar la

transformació de l’etiqueta obtinguda mitjançant l’unranking cap a un format més humà.

Donada la llista de llistes, el següent codi ataca els casos directes i, per aquells que no ho

són, invoca la funció de desenvolupament.

cod.54

etiq := proc(t) begin //Si la llista passada té tan sols un element i resulta ser un 1, estem etiquetant un Àtoms, i per, tant //retornem una llista amb l’etiqueta 1. if nops(t) = 1 and t = 1 then return([1]); //Si la llista té només un element i el seu valor és 0, estem etiquetant un Epsilon, els quals no //porten etiqueta i per tant, no retornem més que una llista buida. elif nops(t) = 1 and t = 0 then return([]); end_if; //Si els dos primers elements de la llista tenen una sol element de valor 1, aleshores estem en el //cas més senzill, on retornarem [1,2] o [2,1] depenent del valor de la tercera component. if op(t,1) = 1 and op(t,2) = 1 then if op(t,3) = 1 then return([1,2]); else return([2,1]); end_if; //Quan la primera o la segona component tinguin un 0 per valor, tindrem una cosa semblant a //[0,[X,X,X],0] ó [[X,X,X],0,0], és a dir, el rank també valdrà 0 i per tant, només tindrà importància //el resultat de la component diferent de zero. Així que invocarem la funció etiq sobre la //component que no sigui 0. elif op(t,1) = 0 then etiq(op(t,2)); elif op(t,2) = 0 then etiq(op(t,1)); //Si una component té valor 1 i l’altra diferent d’1, o les dues components no siguin 1, ens //trobarem en els casos en què cal desenvolupar les subllistes mitjançant l’operació ja descrita. //Per tant, invocarem la funció desenvolupa amb els paràmetres adequats. elif op(t,1) = 1 and op(t,2) <> 1 then return(desenvolupa(1,etiq(op(t,2)),op(t,3))); elif op(t,1) <> 1 and op(t,2) = 1 then return(desenvolupa(etiq(op(t,1)),1,op(t,3))); elif op(t,1) <> 1 and op(t,2) <> 1 then return(desenvolupa(etiq(op(t,1)),etiq(op(t,2)),op(t,3))); end_if; end_proc;

Page 130: Títol: Generació Ordenada d’Estructures Combinatòries en

Capítol IV – Unranking

130

La funció desenvolupa és l’encarregada de dur a terme l’operació que ja hem vist per anar

transformant les subllistes en l’etiqueta corresponent en funció del rank. Per poder dur a

terme aquesta funció ens ha fet falta implementar una funció auxiliar que no es trobava

entre les llibreries de MuPad: l’unrankChooseNK ([6], [7], [10], [11] i [13]), és a dir, donat

un rank r i dos valors n i j, trobar la r-èsima ⎟⎟⎠

⎞⎜⎜⎝

⎛jn -partició.

cod.55

desenvolupa := proc(a, b, c) local i, e, s, s2; begin //Primer obtenim el nombre total d’elements de la llista. if b = 1 then b := b + nops(a); else i := 1; while i <= nops(b) do b[i] := b[i] + nops(a); i := i + 1; end_while; end_if; //Obtenim una llista amb tots els elements de les diverses subllistes. e := [op(a), op(b)]; //Aconseguim els j primers elements de l’etiqueta, mitjançant la funció unrankChooseNK. s := unrankChooseNK(array(1..nops(a)), nops(e), nops(a), c, 1, 0); s2 := []; //A s2 guardem tots els elements de la llista total que no es trobin entre els j primers elements. i := 1; while i <= nops(e) do if contains(s,i) <> 0 then else s2 := append(s2, i); end_if; i := i + 1; end_while; //Concatenem els j primers elements amb els n-j elements de s2. s := [op(s), op(s2)]; s2 := []; i := 1; //Ara apliquem la reordenació de la segona part de la llista tenint en compte l’ordre induït per //les components inicials. while i <= nops(e) do s2 := append(s2, s[e[i]]); i := i + 1; end_while; //Finalment retornem l’etiqueta completament desenvolupada. return(s2); end_proc;

Per tal d’obtenir la comprensió total del codi que acabem de veure, a continuació es presenta

el codi desenvolupat per a la realització de l’unrank de la i-èsima ⎟⎟⎠

⎞⎜⎜⎝

⎛kn -partició.

cod.56

unrankChooseNK := proc(t, n, k, i: Type::PosInt, pe, laux) begin //En aquesta funció primer ens assegurem que el rank que ens han passat sigui possible //tenint en compte el nombre d’elements que es puguin generar amb la n i la j donades. Per //fer això, usarem la funció count que ens proporciona Mupad sobre els chooseNK.

Page 131: Títol: Generació Ordenada d’Estructures Combinatòries en

PFC – Generació Ordenada d’Estructures Combinatòries en “MuPAD-Combinat”

131

if combinat::chooseNK::count(n,k) < i then return(FAIL); else return([op(unrankChooseNKAuxil(t, n, k, (i-1), pe, laux),1..k)]); end_if; end_proc;

cod.57

unrankChooseNKAuxil := proc(t, n, k, i, pe, laux) local l, s, saux, j, m;option remember; begin //La seva estructura és molt semblant a les que ja hem vist per a les diverses funcions //d’unrank. Primerament ens cal trobar el valor de la variable l, és a dir, anirem mirant el //nombre de combinacions possibles que es poden anar fent a mida que incrementem el //valor de l i mantenint fixat un element (k-1), mentre no ens passem del rank i. l := 1; saux := 0; s := saux + combinat::chooseNK::count((n - 1), (k - 1)); while s <= i do l := l + 1; saux := s; if (k -1) < 0 then s := s + combinat::chooseNK::count((n - l), 0); else s := s + combinat::chooseNK::count((n - l), (k - 1)); end_if; end_while; //Assignem a la taula a la posició pe (que en la primera crida donarem per valor 1), la suma //de l més laux (que és el número col·locat anteriorment), per tal de tenir en compte el que ja //hem colocat. t[pe] := laux + l; //Si l’índex pe és més petit que el número de paràmetres de la taula t (és a dir, k), //continuem duent a terme unranksChooseNK. if pe < nops(t) then unrankChooseNKAuxil(t, (n - l), (k - 1), (i - saux), (pe + 1), (laux + l)); else return(t); end_if; end_proc;

Un cop ja hem obtingut l’etiqueta en format més humà i, tal i com ja hem dit, cal veure el

procés d’assignar l’etiqueta a l’objecte per produir la sortida desitjada per l’usuari.

cod.58

etiquetaObjecte := proc(spec, obj, etiq) local t1, t2; begin //Obtenim primer una llista d’Atoms per tal de què, quan ens topem amb un d’ells, sapiguem //que li hem d’assignar una etiqueta. t1 := obteAtoms(rhs(op(spec,4))); //Obtenim a continuació una llista d’Epsilons per tal de saber quins elements no hem d’etiquetar //quan ens trobem amb ells. t2 := obteEpsilons(rhs(op(spec,4))); //Finalment invoquem la funció d’etiquetatge, passant-li la llista d’àtoms, epsilons, l’objecte i //l’etiqueta. return(posaEtiqueta(t1,t2,obj, etiq)); end_proc;

cod.59

obteEpsilons := proc(taula) local i, t;

Page 132: Títol: Generació Ordenada d’Estructures Combinatòries en

Capítol IV – Unranking

132

begin //El funcionament d’aquesta funció és ben senzill. Primer, crea una taula amb l’element Epsilon, i //després repassa totes les entrades de la taula passada com a paràmetre i, quan es troba amb //el constructor Primitive amb valor 0, emmagatzema l’identificador que l’acompanya a la taula //resultat. És a dir, si es trobés amb X = Primitive(0, Red), guardaria Red a la taula com a //identificador d’Epsilon. i := 1; t := [Epsilon]; while i <= nops(taula) do if (op(rhs(op(taula,i)),0) = Primitive) and (op(rhs(op(taula,i)),1) = 0) then t := append(t, op(rhs(op(taula,i)),2)); end_if; i := i + 1; end_while; return(t); end_proc;

cod.60

obteAtoms := proc(taula) local i, t; begin //El funcionament d’aquesta funció és ben senzill. Primer, crea una taula buida, i després //repassa totes les entrades de la taula passada com a paràmetre i, quan es troba amb el //constructor Primitive amb valor 1, emmagatzema l’identificador que l’acompanya a la taula //resultat. És a dir, si es trobés amb X = Primitive(1,Blue), guardaria Blue a la taula com a //identificador d’Àtom. i := 1; t := []; while i <= nops(taula) do if (op(rhs(op(taula,i)),0) = Primitive) and (op(rhs(op(taula,i)),1) = 1) then t := append(t, op(rhs(op(taula,i)),2)); end_if; i := i + 1; end_while; return(t); end_proc; cod.61

posaEtiqueta := proc(tau1, tau2, obj, etiq) local i, j, t, t1; begin //La funció d’etiquetatge és una funció recursiva que es basa en enviar crides a etiquetar les //subparts de l’objecte. El cas base ens el trobarem quan l’objecte tingui mida 1 i no vagi //acompanyat de cap constructor. if (nops(obj) = 1) and (op(obj,0) = FAIL) then //Si l’element que conforma l’objecte apareix en la taula d’àtoms, aleshores l’hem d’etiquetar. //Com que quan arribem a aquest punt la taula etiq conté tan sols un element (el valor de //l’etiqueta a assignar a aquest identificador), retornem un objecte en format id(val_etiq). if contains(tau2, obj) = 0 then return(obj(op(etiq))); //Si l’element apareix en la taula d’epsilons, no l’hem d’etiquetar i per tant, simplement retornem //l’objecte directament. else return(obj); end_if; else //Si no ens trobem davant d’un objecte de talla 1 o és perquè l’acompanya un constructor, per //cada un dels elements que componen l’objecte, enviem una crida a comptaAtoms que ens //diu quants àtoms té aquell subobjecte. Aleshores, invoquem la funció posaEtiqueta enviant-li el //subobjecte i el nombre d’etiquetes que li corresponen (segons el nombre d’àtoms). Com que //mirem els elements de l’objecte ordenadament i a més, l’etiqueta està calculada i ordenada

Page 133: Títol: Generació Ordenada d’Estructures Combinatòries en

PFC – Generació Ordenada d’Estructures Combinatòries en “MuPAD-Combinat”

133

//en aquest mateix ordre, no ens hem de preocupar d’estar enviant-li una etiqueta incorrecta al //subobjecte. i := 1; t := []; t1 := etiq; while(i <= nops(obj)) do j := comptaAtoms(tau1, op(obj,i)); t := append(t, posaEtiqueta(tau1,tau2,op(obj,i),t1[1..j])); t1 := t1[(j+1)..-1]; i := i + 1; end_while; //Finalment, retornem l’objecte calculat, tenint present d’assignar el constructor de l’objecte //inicial altra vegada. return(op(obj,0)(op(t))); end_if; end_proc; cod.62

comptaAtoms := proc(taula, obj) local i, j; begin //En aquesta funció, recorrem l’objecte recursivament, descobrint si, els elements que ens //trobem individualment, són o no àtoms. //El cas base es compleix si l’objecte és de mida 1... if nops(obj) = 1 then //Si l’objecte no apareix en la taula d’àtoms, retornem un 0 ja que es tracta d’un epsilon. if contains(taula,obj) = 0 then return(0); else //Altrament estem davant d’un àtom, i per tant, retornem un 1. return(1); end_if; else //Si l’objecte no té mida 1, aleshores cal recórrer totes les seves components i fer crides a //comptaAtoms per cada una d’elles i anar acumulant el resultat retornat. i := 0; j := 1; while(j <= nops(obj)) do i := i + comptaAtoms(taula, op(obj, j)); j := j + 1; end_while; return(i); end_if; end_proc;

4 Anàlisi del Cost

Per tal d’investigar la complexitat dels algorismes d’unranking, la mesura del cost que

considerarem és el nombre d’operacions aritmètiques. Assumim que les cardinalitats de les

classes, obtingudes mitjançant la funció Count, es troben emmagatzemades en taules

precalculades de mida ( )nO enters, i no tindrem en compte en els anàlisis el temps emprat

per aquest preprocés (que és ( )2nO ).

Page 134: Títol: Generació Ordenada d’Estructures Combinatòries en

Capítol IV – Unranking

134

La conversió d’una especificació no estàndard en la seva corresponent especificació

estàndard és independent de n, i només es realitza una vegada, així que aquesta contribució

tampoc es tindrà en compte.

Així, la contribució principal al cost dels algorismes d’unranking prové dels bucles usats per

determinar la mida de la primera component en el cas dels Productes i BoxedProds, i la seva

naturalesa recursiva. Els següents dos teoremes exposen la complexitat del pitjor cas de

realitzar l’unranking d’objectes de mida n, per l’ordre lexicogràfic i l’ordre bustrofèdic,

respectivament.

Teorema 1. La complexitat del temps en el pitjor cas de realitzar l’unranking pels objectes

de mida n en qualsevol classe admissible A (classes que tan sols impliquen els operadors

unions disjuntes, productes estàndard, seqüències, powersets i sets) usant l’ordre

lexicogràfic és ( )2nO operadors aritmètics.

Prova. Considerem l’arbre d’anàlisi associat a l’unranking d’un objecte de mida n. Un arbre

com aquest té una mida proporcional a n i la seva aritat és 2≤ , amb cada un dels seus

nodes associat a una crida recursiva a la funció d’unranking. El cost no recursiu associat a

cada un dels nodes és com a màxim lineal a la mida de l’objecte produït com a resultat

d’aquesta crida, això és, lineal al la mida del subarbre amb arrel aquest node. Per tant, el

pitjor cas de realitzar un unranking d’un objecte de mida n és proporcional a la longitud del

camí del pitjor cas d’un arbre de mida ( )nO , el qual és ( )2nO .

Teorema 2. La complexitat del temps en el pitjor cas de realitzar l’unranking pels objectes

de mida n en qualsevol classe admissible A usant l’ordre bustrofèdic és ( )nnO log

operadors aritmètics.

Prova. El nombre d’iteracions per determinar la mida de α en un producte bustrofèdic

( )βα , és ( )( )1,min2 +⋅ βα . El mateix val per als BoxedProds. Les operacions aritmètiques

a fora del bucle que determina la mida j de la primera component en els productes i en els

BoxedProds contribuirà en un terme lineal al cost total per uns motius equivalent als donats

a la prova del teorema anterior. Així, la contribució principal en el pitjor cas de l’unranking

satisfà una recurrència de la forma

( ) ( ) ( ) ( )( )knkcknUkUnU −⋅+−+= ,minmax ,

Per alguna constant c, la solució de la qual és ( )nnO log .

A continuació podem veure un conjunt de taules i gràfics en què podrem observar el temps

total (en milisegons) d’execució de la nostra funció d’unrank i de la proporcionada per

MuPAD. També s’adjunta una gràfica comparativa dels resultats per tal de fer-se una idea

més visual.

Page 135: Títol: Generació Ordenada d’Estructures Combinatòries en

PFC – Generació Ordenada d’Estructures Combinatòries en “MuPAD-Combinat”

135

S’han realitzat 1100 crides per la nostra funció d’unrank i 1100 més a la funció unrank de

MuPAD, amb valors aleatoris per al rank (generats mitjançant la funció random

proporcionada per MuPAD) entre 1 i el nombre màxim d’elements de mida n de la classe.

Per cada taula es detalla un seguit d’informació que dóna una idea de l’entorn en què s’ha

produït l’execució.

Page 136: Títol: Generació Ordenada d’Estructures Combinatòries en

Capítol IV – Unranking

136

Arbres Binaris: B = Union(Z, Prod(B,B))

• No Etiquetats.

• Ordre Lexicogràfic.

• ( )nnn Ο+2π

Mida (n) MuPad Jordi 25 7,12 1,99 50 18,81 4,94 75 33,27 8,8 100 50,83 13,47 125 78,84 20,02 150 120,03 31,31

• No Etiquetats.

• Ordre Bustrofèdic.

• ( )nn logΟ

Mida (n) MuPad Jordi 25 4,8 2,4 50 10 5,01 75 20,4 8 100 30 11 125 38 14,02 150 42,3 18,8

• Etiquetats.

• Ordre Lexicogràfic.

• ( )nnn Ο+2π

Mida (n) MuPad Jordi 25 14,07 9,53 50 37,56 25,56 75 68,61 52,21 100 91,3 78,72 125 113,68 92,36 150 150,7 128,81

Arbres binàris no etiquetats en ordre lexicogràfic

020406080

100120140

25 50 75 100 125 150

Mida

Mili

sego

ns

MuPadJordi

Arbres binàris no etiquetats en ordre bustrofèdic

0

10

20

30

40

50

25 50 75 100 125 150

Mida

Mili

sego

ns

MuPadJordi

Arbres Binàris etiquetats en ordre lexicogràfic

020406080

100120140160

25 50 75 100 125 150

Mida

Mili

sego

ns

MuPadJordi

Page 137: Títol: Generació Ordenada d’Estructures Combinatòries en

PFC – Generació Ordenada d’Estructures Combinatòries en “MuPAD-Combinat”

137

• Etiquetats.

• Ordre Bustrofèdic.

• ( )nn logΟ

Mida (n) MuPad Jordi 25 7,89 6,54 50 19,21 22,15 75 32,74 48,71 100 64,35 104,53 125 87,04 143,08 150 113,78 148,15

Functional Graphs: F = Set(Cycle(T)), T = Prod(Z, Set(T))

• Etiquetats.

• Ordre Lexicogràfic.

• ( )nnn Ο+23

Mida (n) MuPad Jordi 25 20,09 9,41 50 46,78 28,05 75 77,82 56,27 100 114,11 69,14 125 152,68 131,67 150 195,91 144,18

• Etiquetats.

• Ordre Bustrofèdic.

• ( )nnn Ο+23

Mida (n) MuPad Jordi 25 16,64 9,54 50 36,88 26,25 75 59,64 53,5 100 64,21 69,67 125 112,19 121,76 150 141,89 134,5

Arbres binàris etiquetats en ordre bustrofèdic

020406080

100120140160

25 50 75 100 125 150

Mida

Mili

sego

ns

MuPadJordi

Functional Graphs en ordre lexicogràfic

0

50

100

150

200

250

25 50 75 100 125 150

Mida

Mili

sego

ns

MuPadJordi

Functional Graphs en ordre bustrofèdic

020406080

100120140160

25 50 75 100 125 150

Mida

Mili

sego

ns

MuPadJordi

Page 138: Títol: Generació Ordenada d’Estructures Combinatòries en

Capítol IV – Unranking

138

4.1 Sortides generades

A continuació anirem generant diversos exemples per veure la major part de les

funcionalitats que cobreix el codi vist en l’apartat anterior.

Capçalera funció funcioUnrank(spec, size, rank)

Spec Objecte de tipus especificació estàndard. Size Enter (diferent de 0) que indica la mida dels objectes a generar.

Rank Enter (entre 1 i el nombre d'objectes de mida size en la classe) que indica la posició de l'objecte a generar en la classe.

1. Generem tots els arbres binaris no etiquetats en ordre lexicogràfic de mida 4.

k := {B=Union(Z,Prod(B,B)) };

bn := generaEspecificacioEstandard(k, FALSE, FALSE);

funcioLlistar(bn, 4);

[Prod(Z, Prod(Z, Prod(Z, Z))), Prod(Z, Prod(Prod(Z, Z), Z)), Prod(Prod(Z, Z), Prod(Z, Z)), Prod(Prod(Z, Prod(Z,

Z)), Z), Prod(Prod(Prod(Z, Z), Z), Z)]

2. Generem tots els arbres binaris no etiquetats en ordre bustrofèdic de mida 4.

k := {B=Union(Z,Prod(B,B)) };

bn := generaEspecificacioEstandard(k, FALSE, TRUE);

funcioLlistar(bn, 4);

[Prod(Z, Prod(Z, Prod(Z, Z))), Prod(Z, Prod(Prod(Z, Z), Z)), Prod(Prod(Z, Prod(Z, Z)), Z), Prod(Prod(Prod(Z, Z),

Z), Z), Prod(Prod(Z, Z), Prod(Z, Z))]

3. Generem tots els arbres binaris etiquetats en ordre lexicogràfic de mida 3.

k := {B=Union(Z,Prod(B,B)) };

bn := generaEspecificacioEstandard(k, TRUE,FALSE);

funcioLlistar(bn, 3);

[Prod(Z(1), Prod(Z(2), Z(3))), Prod(Z(2), Prod(Z(1), Z(3))), Prod(Z(3), Prod(Z(1), Z(2))), Prod(Z(1), Prod(Z(3),

Z(2))), Prod(Z(2), Prod(Z(3), Z(1))), Prod(Z(3), Prod(Z(2), Z(1))), Prod(Prod(Z(1), Z(2)), Z(3)), Prod(Prod(Z(1),

Z(3)), Z(2)), Prod(Prod(Z(2), Z(3)), Z(1)), Prod(Prod(Z(2), Z(1)), Z(3)), Prod(Prod(Z(3), Z(1)), Z(2)),

Prod(Prod(Z(3), Z(2)), Z(1))]

4. Generem totes les Seqüències associades als arbres binaris no etiquetats en ordre

lexicogràfic de mida 3.

k := {S = Sequence(B), B=Union(Z,Prod(B,B)) };

bn := generaEspecificacioEstandard(k, FALSE,FALSE);

funcioLlistar(bn, 3);

[Sequence(Z, Z, Z, Epsilon), Sequence(Z, Prod(Z, Z), Epsilon), Sequence(Prod(Z, Z), Z, Epsilon),

Sequence(Prod(Z, Prod(Z, Z)), Epsilon), Sequence(Prod(Prod(Z, Z), Z), Epsilon)]

Page 139: Títol: Generació Ordenada d’Estructures Combinatòries en

PFC – Generació Ordenada d’Estructures Combinatòries en “MuPAD-Combinat”

139

5. Generem totes les Seqüències associades als arbres binaris etiquetats en ordre

lexicogràfic de mida 3.

k := {S = Sequence(B), B=Union(Z,Prod(B,B)) };

bn := generaEspecificacioEstandard(k, TRUE,FALSE);

funcioLlistar(bn, 3);

[Sequence(Z(1), Z(2), Z(3), Epsilon), Sequence(Z(2), Z(1), Z(3), Epsilon), Sequence(Z(3), Z(1), Z(2), Epsilon),

Sequence(Z(1), Z(3), Z(2), Epsilon), Sequence(Z(2), Z(3), Z(1), Epsilon), Sequence(Z(3), Z(2), Z(1), Epsilon),

Sequence(Z(1), Prod(Z(2), Z(3)), Epsilon), Sequence(Z(2), Prod(Z(1), Z(3)), Epsilon), Sequence(Z(3),

Prod(Z(1), Z(2)), Epsilon), Sequence(Z(1), Prod(Z(3), Z(2)), Epsilon), Sequence(Z(2), Prod(Z(3), Z(1)),

Epsilon), Sequence(Z(3), Prod(Z(2), Z(1)), Epsilon), Sequence(Prod(Z(1), Z(2)), Z(3), Epsilon),

Sequence(Prod(Z(1), Z(3)), Z(2), Epsilon), Sequence(Prod(Z(2), Z(3)), Z(1), Epsilon), Sequence(Prod(Z(2),

Z(1)), Z(3), Epsilon), Sequence(Prod(Z(3), Z(1)), Z(2), Epsilon), Sequence(Prod(Z(3), Z(2)), Z(1), Epsilon),

Sequence(Prod(Z(1), Prod(Z(2), Z(3))), Epsilon), Sequence(Prod(Z(2), Prod(Z(1), Z(3))), Epsilon),

Sequence(Prod(Z(3), Prod(Z(1), Z(2))), Epsilon), Sequence(Prod(Z(1), Prod(Z(3), Z(2))), Epsilon),

Sequence(Prod(Z(2), Prod(Z(3), Z(1))), Epsilon), Sequence(Prod(Z(3), Prod(Z(2), Z(1))), Epsilon),

Sequence(Prod(Prod(Z(1), Z(2)), Z(3)), Epsilon), Sequence(Prod(Prod(Z(1), Z(3)), Z(2)), Epsilon),

Sequence(Prod(Prod(Z(2), Z(3)), Z(1)), Epsilon), Sequence(Prod(Prod(Z(2), Z(1)), Z(3)), Epsilon),

Sequence(Prod(Prod(Z(3), Z(1)), Z(2)), Epsilon), Sequence(Prod(Prod(Z(3), Z(2)), Z(1)), Epsilon)]

6. Generem totes les Seqüències associades als arbres binaris no etiquetats en ordre

lexicogràfic de mida 3, amb cardinalitat igual a 2.

k := {S = Sequence(B, Length = 2), B=Union(Z,Prod(B,B)) };

bn := generaEspecificacioEstandard(k, FALSE,FALSE);

funcioLlistar(bn, 3);

[Sequence(Z, Prod(Z, Z), Epsilon), Sequence(Prod(Z, Z), Z, Epsilon)]

7. Generem totes les Seqüències associades als arbres binaris no etiquetats en ordre

lexicogràfic de mida 3, amb cardinalitat major o igual a 2.

k := {S = Sequence(B, MinLength = 2), B=Union(Z,Prod(B,B)) };

bn := generaEspecificacioEstandard(k, FALSE,FALSE);

funcioLlistar(bn, 3);

[Sequence(Z, Z, Z, Epsilon), Sequence(Z, Prod(Z, Z), Epsilon), Sequence(Prod(Z, Z), Z, Epsilon)]

8. Generem totes les Seqüències associades als arbres binaris no etiquetats en ordre

lexicogràfic de mida 3, amb cardinalitat menor o igual a 2.

k := {S = Sequence(B, MinLength = 2), B=Union(Z,Prod(B,B)) };

bn := generaEspecificacioEstandard(k, FALSE,FALSE);

funcioLlistar(bn, 3);

[Sequence(Prod(Z, Prod(Z, Z)), Epsilon), Sequence(Prod(Prod(Z, Z), Z), Epsilon), Sequence(Z, Prod(Z, Z),

Epsilon), Sequence(Prod(Z, Z), Z, Epsilon)]

9. Generem tots els Sets associats als arbres binaris no etiquetats en ordre lexicogràfic de

mida 3.

k := {S = Set (B), B=Union(Z,Prod(B,B)) };

bn := generaEspecificacioEstandard(k, FALSE,FALSE);

funcioLlistar(bn, 3);

Page 140: Títol: Generació Ordenada d’Estructures Combinatòries en

Capítol IV – Unranking

140

[Set(Z, Prod(Z, Z), Epsilon), Set(Z, Z, Z, Epsilon), Set(Prod(Z, Prod(Z, Z)), Epsilon), Set(Prod(Prod(Z, Z), Z),

Epsilon)]

10. Generem tots els Powersets associats als arbres binaris no etiquetats en ordre

lexicogràfic de mida 3.

k := {S = Powerset (B), B=Union(Z,Prod(B,B)) };

bn := generaEspecificacioEstandard(k, FALSE,FALSE);

funcioLlistar(bn, 3);

[Powerset(Z, Prod(Z, Z), Epsilon), Powerset(Prod(Z, Prod(Z, Z)), Epsilon), Powerset(Prod(Prod(Z, Z), Z),

Epsilon)]

11. Generem tots els Sets associats als arbres binaris etiquetats en ordre lexicogràfic de

mida 3.

k := {S = Set (B), B=Union(Z,Prod(B,B)) };

bn := generaEspecificacioEstandard(k, TRUE,FALSE);

funcioLlistar(bn, 3);

[Set(Z(1), Z(2), Z(3), Epsilon), Set(Z(1), Prod(Z(2), Z(3)), Epsilon), Set(Z(1), Prod(Z(3), Z(2)), Epsilon),

Set(Prod(Z(1), Z(2)), Z(3), Epsilon), Set(Prod(Z(1), Z(3)), Z(2), Epsilon), Set(Prod(Z(2), Z(1)), Z(3), Epsilon),

Set(Prod(Z(3), Z(1)), Z(2), Epsilon), Set(Prod(Z(1), Prod(Z(2), Z(3))), Epsilon), Set(Prod(Z(2), Prod(Z(1), Z(3))),

Epsilon), Set(Prod(Z(3), Prod(Z(1), Z(2))), Epsilon), Set(Prod(Z(1), Prod(Z(3), Z(2))), Epsilon), Set(Prod(Z(2),

Prod(Z(3), Z(1))), Epsilon), Set(Prod(Z(3), Prod(Z(2), Z(1))), Epsilon), Set(Prod(Prod(Z(1), Z(2)), Z(3)), Epsilon),

Set(Prod(Prod(Z(1), Z(3)), Z(2)), Epsilon), Set(Prod(Prod(Z(2), Z(3)), Z(1)), Epsilon), Set(Prod(Prod(Z(2), Z(1)),

Z(3)), Epsilon), Set(Prod(Prod(Z(3), Z(1)), Z(2)), Epsilon), Set(Prod(Prod(Z(3), Z(2)), Z(1)), Epsilon)]

12. Generem tots els Cycles associats als arbres binaris etiquetats en ordre lexicogràfic de

mida 3.

k := {S = Cycle (B), B=Union(Z,Prod(B,B)) };

bn := generaEspecificacioEstandard(k, TRUE,FALSE);

funcioLlistar(bn, 3);

[Cycle(Z(1), Z(2), Z(3), Epsilon), Cycle(Z(1), Z(3), Z(2), Epsilon), Cycle(Z(1), Prod(Z(2), Z(3)), Epsilon),

Cycle(Z(1), Prod(Z(3), Z(2)), Epsilon), Cycle(Prod(Z(1), Z(2)), Z(3), Epsilon), Cycle(Prod(Z(1), Z(3)), Z(2),

Epsilon), Cycle(Prod(Z(2), Z(1)), Z(3), Epsilon), Cycle(Prod(Z(3), Z(1)), Z(2), Epsilon), Cycle(Prod(Z(1),

Prod(Z(2), Z(3))), Epsilon), Cycle(Prod(Z(2), Prod(Z(1), Z(3))), Epsilon), Cycle(Prod(Z(3), Prod(Z(1), Z(2))),

Epsilon), Cycle(Prod(Z(1), Prod(Z(3), Z(2))), Epsilon), Cycle(Prod(Z(2), Prod(Z(3), Z(1))), Epsilon),

Cycle(Prod(Z(3), Prod(Z(2), Z(1))), Epsilon), Cycle(Prod(Prod(Z(1), Z(2)), Z(3)), Epsilon),

Cycle(Prod(Prod(Z(1), Z(3)), Z(2)), Epsilon), Cycle(Prod(Prod(Z(2), Z(3)), Z(1)), Epsilon),

Cycle(Prod(Prod(Z(2), Z(1)), Z(3)), Epsilon), Cycle(Prod(Prod(Z(3), Z(1)), Z(2)), Epsilon),

Cycle(Prod(Prod(Z(3), Z(2)), Z(1)), Epsilon)]

Page 141: Títol: Generació Ordenada d’Estructures Combinatòries en
Page 142: Títol: Generació Ordenada d’Estructures Combinatòries en

Capítol V

Ranking

Page 143: Títol: Generació Ordenada d’Estructures Combinatòries en

Índex del capítol

1 INTRODUCCIÓ................................................................................................. 144

2 ESTUDI DE LA FUNCIÓ DE RANKING........................................................ 144 2.1 Ranking de classes etiquetades..............................................................................................147 2.2 Ranking de classes no etiquetades.........................................................................................151

3 IMPLEMENTACIÓ DEL RANKING .............................................................. 152

4 ANÀLISI DEL COST ........................................................................................ 164

Page 144: Títol: Generació Ordenada d’Estructures Combinatòries en

Capítol V –Ranking

144

1 Introducció

Ara que ja s’ha vist el tractament de l’unranking, anem a considerar el problema invers: el

ranking. Donada l’especificació d’una classe combinatòria i un objecte de mida n pertanyent

a aquesta classe, el problema del ranking es converteix en calcular el rank de l’objecte, és a

dir, el nombre d’objectes de mida n de la classe especificada que són més petits que el

nostre objecte (d’acord amb algun ordre prèviament fixat). Particularment, i aquest ordre

coincideix amb el que s’ha usat per l’unranking aleshores tenim que

( )( ) αα =,,, ARanknAUnrank i ( )( ) iinAUnrankARank =,,, per qualsevol nAnA ∈α,, i

nai <≤0 .

En el segon apartat d’aquest capítol detallarem els algorismes de ranking existents per

aquells constructors que vulguem tractar que, en el nostre cas, no seran tots. Concretament

ens centrarem en els constructors Union, Prod i Sequence.

En el tercer apartat es presenta el codi implementat en MuPAD per a resoldre el problema

del ranking.

En l’últim apartat es mostra un petit estudi del cost dels nostres algorismes. Emperò en

aquesta ocasió no podrem comparar els resultats amb els obtinguts en MuPAD, ja que aquest

sistema no ofereix aquesta funcionalitat.

Cal notar que, com ja sabem pel que s’ha vist anteriorment en altres capítols, la

descomposició d’un objecte a partir d’una especificació no és única. És a dir, partint de la

mateixa especificació, es pot arribar al mateix resultat seguint diversos camins. Això fa que

el resultat del ranking no sigui únic. Per tant, s’ha decidit que en els casos que això passi,

per construcció, el resultat serà el primer que trobi la funció.

2 Estudi de la funció de Ranking

La major part del contingut d’aquest apartat s’ha extret de les referència [12].

El primer que ens cal saber per poder atacar amb èxit el problema del ranking és, donat un

objecte α i una classe A volem saber si l’objecte pertany a aquesta classe o no5. Per a fer

això necessitem una funció anomenada is_a. Aquesta funció realitza crides recursives pels

subobjectes dels quals està format un objecte. Per exemple, donat un objecte etiquetat

5 Per ser més precís, el que volem comprovar és si la representació de l’objecte es pot derivar de l‘especificació de la classe.

Page 145: Títol: Generació Ordenada d’Estructures Combinatòries en

PFC – Generació Ordenada d’Estructures Combinatòries en “MuPAD-Combinat”

145

l,,βα i una classe BA∗ és necessari comprovar que α pertany a A , β pertany a B i

que el l -èsim etiquetatge té un rank correcte.

Existeixen dues versions per a aquesta funció, una per al cas etiquetat i l’altra per al no

etiquetat. Veiem primer la del cas etiquetat.

Algorisme 18. Funció is_A per classes etiquetades

is_A(C ,γ )

si ( εγ = i { }ε=C ) ó ( Z=γ i { }ZC = ) llavors retorna CERT

sino si εγ = i ( ( )ASequenceC = ó ( )ASetC = ) llavors retorna CERT

sino si BAC += llavors retorna ( ( )γ,_ AAis ) ó ( ( )γ,_ BAis )

sino si BAC ∗= i l,,βαγ = llavors

retorna ( ( )α,_ AAis i ( )β,_ BAis i ⎟⎟⎠

⎞⎜⎜⎝

⎛<≤

αγ

l0 )

sino si AC = □* B i =α □ l,,βα llavors

retorna ( ( )α,_ AAis i ( )β,_ BAis i ⎟⎟⎠

⎞⎜⎜⎝

⎛−−

<≤11

0αγ

l )

sino si ( )ASequenceC = llavors retorna ( )γ,_ CAAis ∗

sino si ( )ASetC = llavors retorna AAis (_ □ ),γC∗

sino si ( )ACycleC = llavors retorna AAis (_ □ )),( γASequence∗

sino retorna FALS

fsi

Per a les classes etiquetades existeixen diversos casos depenent de si A és la classe ε , una

classe atòmica, una unió, un producte particional o un boxedProd, una seqüència, un set o

un cicle. Segons els isomorfismes vistos en el capítol 2, s’estableix el vist en l’algorisme 1.

A continuació passem a veure l’algorisme equivalent per a les classes no etiquetades.

Algorisme 19. Funció is_A per classes no etiquetades

is_A(C ,γ )

si ( εγ = i { }ε=C ) ó ( Z=γ i { }ZC = ) llavors retorna CERT

sino si εγ = i ( ( )ASequenceC = ó ( )APowersetC = ó ( )ASetC = ) llavors

Page 146: Títol: Generació Ordenada d’Estructures Combinatòries en

Capítol V –Ranking

146

retorna CERT

sino si BAC += llavors retorna ( ( )γ,_ AAis ) ó ( ( )γ,_ BAis )

sino si BAC ×= i βαγ ,= llavors

retorna ( ( )α,_ AAis i ( )β,_ BAis )

sino si ( )ASequenceC = llavors retorna ( )( )γ,_ ASequenceAAis ×

sino si ( ( )APowersetC = ó ( )ASetC = ) i βαγ ,= llavors

k := #components en α

j := mida de les components iα de KK kk αααα ,,, 11 −=

// { }kjA∈α ó { }{ }k

jA∈α

per i desde 1 fins k fer

si no ( )iAAis α,_ llavors retorna FALS

fsi

fper

retorna ( )β,_ CAis

sino retorna FALS

fsi

Per al cas no etiquetat, tenim un algorisme molt similar però sense etiquetes, i tenint en

compte que cal realitzar una descomposició pels Powersets i Sets.

Donat un objecte α i una classe A , la funció is_A necessita verificar que cadascun dels

subobjectes d’α pertanyen a la corresponent subclasse o no. Així, la funció is_A acaba quan

o bé un subojecte no pertany a la subclasse específica o bé quan tots els subobjectes han

estat correctament comprovats. Per exemple, si volem comprovar si l’objecte Prod(Z,

Prod(Z, Z)) pertany s B = Union(Z, Prod(B,B)) necessitem comprovar si Z pertany a B i

Prod(Z,Z) pertany a Prod(B,B), i anar fent.

Així doncs, es veu clar que el cost és com a màxim lineal en relació a la mida de l’objecte

donat. Per altra banda, si A∈α , necessitarem examinar tots els àtoms i per tant, el cost

serà realment lineal.

Teorema 4. Donat un objecte α d’una classe A , es pot comprovar si α pertany a A o no

en ( )αO passos. En el pitjor cas, el cost és ( )αθ .

Ara que ja som capaços de dir si un objecte pertany a una determinada classe, ja estem

preparats per veure els algorismes per realitzar el ranking depenent de cada constructor

concret.

Page 147: Títol: Generació Ordenada d’Estructures Combinatòries en

PFC – Generació Ordenada d’Estructures Combinatòries en “MuPAD-Combinat”

147

Com ja hem dit abans, només ens centrarem en l’unranking per a Unions, Prods i Sequences.

I donat que les Sequences es defineixen mitjançant Unions i Prods (per l’isomorfisme que ja

coneixem), el ranking és soluciona recursivament de les solucions que tenim per a les Unions

i els Prods.

2.1 Ranking de classes etiquetades

L’algorisme per a les Unions BA+ tan sols necessita comprovar si l’objecte considerat

pertany a A ó B i, aleshores, realitzar el ranking en la classe apropiada.

Algorisme 20. Ranking per Unions Disjuntes

Rank( α,BA+ )

si ( )α,_ AAis llavors ( )α,ARank

sino ( ) ( )αα ,, BRankACount +

fsi

Ara considerarem el ranking dels Productes Particionals en ordre lexicogràfic i PF. Si la mida

de α en l’objecte l,,βα és j, aleshores això significa que com a mínim

11110 110 +−−− ⋅⋅⎟⎟⎠

⎞⎜⎜⎝

⎛−

++⋅⋅⎟⎟⎠

⎞⎜⎜⎝

⎛+⋅⋅⎟⎟

⎞⎜⎜⎝

⎛jnjnn ba

jn

ban

ban

L

Objectes són més petits que el donat d’acord amb l’ordre lexicogràfic. Aleshores necessitem

determinar quants objectes de mida n la primera component dels quals té mida j, són també

més petits que l’objecte donat. Aquests són tots els elements en

( ) ( ) ( )jn

rjjnjjnj BBB −

−−− ∗++∗+∗ 110 αααα L

amb αr el rank de α en ( ) ( ) ( ) ( ){ }KK ,,,,, 110 αα αααα rj

rjjjjA −= i ( ) ( ) ααα α =r

ji

j p per tota

αri <≤0 . Hi ha com a mínim jnbr

jn

−⋅⋅⎟⎟⎠

⎞⎜⎜⎝

⎛α

d’aquests objectes. De manera similar, també

necessitem determinar quants objectes de ( )

jnr

j B −∗αα són més petits que l’objecte donat.

Aquests són tots els elements en

( ) ( ) ( ) ( ) ( ) ( )110 −−−− ∗++∗+∗ βααα βαβαβα r

jnr

jjnr

jjnr

j L

amb βr el rank de β en ( ) ( ) ( ) ( ){ }KK ,,,,, 110 ββ ββββ rjn

rjnjnjnjnB −−

−−−− = i ( ) ( ) βββ β =−−r

jni

jn p per

tota βri <≤0 . Hi ha βrj

n⋅⎟⎟⎠

⎞⎜⎜⎝

⎛ d’aquests objectes. Finalment, necessitem tenir en compte el

rank lr de la (n,j)-partició. Així, el rank buscat l,,βα és

Page 148: Títol: Generació Ordenada d’Estructures Combinatòries en

Capítol V –Ranking

148

∑−

=−− +⋅⎟⎟

⎞⎜⎜⎝

⎛+⋅⋅⎟⎟

⎞⎜⎜⎝

⎛+⋅⋅⎟⎟

⎞⎜⎜⎝

⎛1

0

,j

kljnknk rr

jn

brjn

bakn

βα

on j és la talla de α , αr és el rank de α en jA , βr és el rank de β en jnB − i lr és el

rank de l’etiquetatge (que assumim que coincideix amb l ). Així doncs, podem veure en

l’algorisme 4 com realitzaríem el ranking per a un producte etiquetat.

Algorisme 21. Ranking etiquetat per Productes (Lexicogràfic)

Rank( lBA ,,, βα∗ )

j := α ; n := l,,βα

'r := ( ) ( )∑−

=⎟⎟⎠

⎞⎜⎜⎝

⎛⋅−⋅

1

0

,,j

k kn

knBCountkACount

αr := ( )α,ARank ; βr := ( )β,BRank

retorna ( ) ljn

rjn

jnBCountrr +⎟⎟⎠

⎞⎜⎜⎝

⎛⋅+⎟⎟

⎞⎜⎜⎝

⎛⋅−⋅+ βα ,'

Aquest és l’algorisme bàsic. Ara bé, en el nostre cas, haurem d’aplicar una petita modificació

a aquest, ja que els objectes que nosaltres rebrem com a entrades de l’usuari portaran

l’etiquetatge en format “humà”. És a dir, una etiqueta no serà una llista de subllistes amb els

corresponents ranks de les etiquetes, sinó que serà una única llista ja desenvolupada. Per

tant, la versió de l’algorisme que nosaltres usarem tindrà un petit canvi com es mostra en

l’algorisme 22.

Algorisme 22. Ranking etiquetat per Productes (Lexicogràfic) (Versió 2)

Rank( βα ,,BA∗ )

j := α ; n := βα ,

'r := ( ) ( )∑−

=⎟⎟⎠

⎞⎜⎜⎝

⎛⋅−⋅

1

0

,,j

k kn

knBCountkACount

αr := ( )( )αcanònicARank , ; βr

:= ( )( )βcanònicBRank ,

//Realitzem els corresponents rankings a partir dels canònics de α i β .

( ) ( )( )βα etiquetaetiquetaLabrankrl ,_:=

//Recuperem el rank de l’etiqueta mitjançant la funció rank_Lab.

retorna ( ) lrjn

rjn

jnBCountrr +⎟⎟⎠

⎞⎜⎜⎝

⎛⋅+⎟⎟

⎞⎜⎜⎝

⎛⋅−⋅+ βα ,'

Page 149: Títol: Generació Ordenada d’Estructures Combinatòries en

PFC – Generació Ordenada d’Estructures Combinatòries en “MuPAD-Combinat”

149

La funció ( )αcanònic reetiqueta l’objecte α mantenint l’ordre de les etiquetes induïdes per

α però amb valors de 1 a α .

Utilitzarem també la funció rank_Lab per calcular el rank de l’etiquetatge corresponent a un

producte de dos objectes etiquetats. La funció retorna el rank de la partició etiquetada

corresponent a les etiquetes de α i de β (que es calculen en la funció etiqueta ).

Cal recordar que, per dos objectes etiquetats α i β de mida j i n-j respectivament, βα ∗

és el conjunt de ⎟⎟⎠

⎞⎜⎜⎝

⎛jn objectes etiquetats que obtenim reetiquetant els àtoms del parell

( )βα , d’acord amb cada una de les (n, j)-particions. Donats dos objectes etiquetats 1γ i 2γ

de βα ∗ , recordem que també 21 γγ p si i només si el conjunt d’etiquetes de la primera

component de 1γ en ordre ascendent és lexicogràficament més petit que el conjunt

d’etiquetes de la primera component de 2γ també en ordre ascendent. Per determinar el

rank d’un objecte γ de βα ∗ donat en la forma =γt Prod ( )βα tt , , necessitem doncs

considerar el conjunt d’etiquetes de la primera component de γt , és a dir, les etiquetes que

apareixen en el terme αt , en ordre ascendent i aplicar qualsevol algorisme de ranking de

αt -conjunts a partir de γt elements. Cal fer notar que l’algorisme 23 de rank_Lab que es

mostra a continuació, treballa amb la premissa que els primers ⎟⎟⎠

⎞⎜⎜⎝

−−+

11

α

βα

ttt

objectes de

βα ∗ tenen l’etiqueta més petita en la primer component.

Algorisme 23. Funció rank_Lab

Rank_Lab( βα tt , )

S := ( )αtordena

n := βα tt + ; j := αt ; r := 0; S[0] := 0

per i desde 1 fins S fer

si S[i - 1] + 1 ≤ S[i] – 1 llavors

per k desde S[i – 1] + 1 fins S[i] – 1 fer

r := ⎟⎟⎠

⎞⎜⎜⎝

⎛−−

+ijkn

r

fper

fsi

Page 150: Títol: Generació Ordenada d’Estructures Combinatòries en

Capítol V –Ranking

150

fper

retorna r

Com en el cas del producte en ordre lexicogràfic, existeix una versió “bàsica” del ranking pel

producte en ordre bustrofèdic, el qual és una mica més complicat.

Algorisme 24. Ranking etiquetat per Productes (Bustrofèdic)

Rank( lBA ,,, βα∗ )

j := α ; n := l,,βα

si j ≤ n – j llavors

'r := ( ) ( ) ( ) ( )∑−

=⎟⎟⎠

⎞⎜⎜⎝

⎛⎟⎟⎠

⎞⎜⎜⎝

⎛−

⋅⋅−+⎟⎟⎠

⎞⎜⎜⎝

⎛⋅−⋅

1

0,,,,

j

k knn

kBCountknACountkn

knBCountkACount

sino

'r := ( ) ( ) ( ) ( )∑−−

=⎟⎟⎠

⎞⎜⎜⎝

⎛⎟⎟⎠

⎞⎜⎜⎝

⎛−

⋅⋅−+⎟⎟⎠

⎞⎜⎜⎝

⎛⋅−⋅

1

0,,,,

jn

k knn

kBCountknACountkn

knBCountkACount

'r := ( ) ( ) ⎟⎟⎠

⎞⎜⎜⎝

⎛−

⋅⋅−+jn

njBCountjnACountr ,,'

fsi

αr := ( )α,ARank ; βr := ( )β,BRank

retorna ( ) ljn

rjn

jnBCountrr +⎟⎟⎠

⎞⎜⎜⎝

⎛⋅+⎟⎟

⎞⎜⎜⎝

⎛⋅−⋅+ βα ,'

Ara vegem la versió que farem servir nosaltres que, com abans, canvia la manera com

obtenim el rank per l’etiqueta. Novament usarem les funcions canònic , etiqueta i Labrank _ .

Algorisme 25. Ranking etiquetat per Productes (Bustrofèdic) (Versió 2)

Rank( βα ,,BA∗ )

j := α ; n := βα ,

si j ≤ n – j llavors

'r := ( ) ( ) ( ) ( )∑−

=⎟⎟⎠

⎞⎜⎜⎝

⎛⎟⎟⎠

⎞⎜⎜⎝

⎛−

⋅⋅−+⎟⎟⎠

⎞⎜⎜⎝

⎛⋅−⋅

1

0,,,,

j

k knn

kBCountknACountkn

knBCountkACount

sino

'r := ( ) ( ) ( ) ( )∑−−

=⎟⎟⎠

⎞⎜⎜⎝

⎛⎟⎟⎠

⎞⎜⎜⎝

⎛−

⋅⋅−+⎟⎟⎠

⎞⎜⎜⎝

⎛⋅−⋅

1

0,,,,

jn

l lnn

lBCountlnACountln

lnBCountlACount

'r := ( ) ( ) ⎟⎟⎠

⎞⎜⎜⎝

⎛−

⋅⋅−+jn

njBCountjnACountr ,,'

Page 151: Títol: Generació Ordenada d’Estructures Combinatòries en

PFC – Generació Ordenada d’Estructures Combinatòries en “MuPAD-Combinat”

151

fsi

αr := ( )( )αcanònicARank , ; βr := ( )( )βcanònicBRank ,

( ) ( )( )βα etiquetaetiquetaLabrankrl ,_:=

retorna ( ) lrjn

rjn

jnBCountrr +⎟⎟⎠

⎞⎜⎜⎝

⎛⋅+⎟⎟

⎞⎜⎜⎝

⎛⋅−⋅+ βα ,'

Com a una nota per tancar el ranking en el cas etiquetat, només dir que si volguéssim

implementar també el ranking pels BoxedProds, l’algorisme és igual que pels Prods però

usant el coeficient binomial ⎟⎟⎠

⎞⎜⎜⎝

⎛−−

11

jn

en comptes de ⎟⎟⎠

⎞⎜⎜⎝

⎛jn

.

2.2 Ranking de classes no etiquetades

Per a les classes no etiquetades, el comportament de les Unions és exactament el mateix

que hem vist en l’algorisme 20 de l’apartat anterior.

De la mateixa manera que en els Productes Particionals, el ranking dels Productes Cartesians

calcula la mida de la primera component, i els ranks de les seves components.

Algorisme 26. Ranking no etiquetat per Productes (Lexicogràfic)

Rank( βα ,,BA× )

j := α ; n := βα ,

'r := ( ) ( )∑−

=

−⋅1

0,,

j

kknBCountkACount

αr := ( )α,ARank ; βr := ( )β,BRank

retorna ( ) βα rjnBCountrr +−⋅+ ,'

De manera molt similar, el ranking en el cas dels productes en ordre bustrofèdic es comporta

com el seu equivalent etiquetat, però sense la combinatòria i el càlcul del rank de l’etiqueta.

Algorisme 27. Ranking no etiquetat per Productes (Bustrofèdic)

Rank( βα ,,BA∗ )

j := α ; n := βα ,

si j ≤ n – j llavors

Page 152: Títol: Generació Ordenada d’Estructures Combinatòries en

Capítol V –Ranking

152

'r := ( ) ( ) ( ) ( )( )∑−

=

⋅−+−⋅1

0,,,,

j

kkBCountknACountknBCountkACount

sino

'r := ( ) ( ) ( ) ( )( )∑−−

=

⋅−+−⋅1

0,,,,

jn

llBCountlnACountlnBCountlACount

'r := ( ) ( )jBCountjnACountr ,,' ⋅−+

fsi

αr := ( )α,ARank ; βr := ( )β,BRank

retorna ( ) βα rjnBCountrr +−⋅+ ,'

3 Implementació del Ranking

La idea bàsica del ranking consisteix primer en esbrinar si estem tractant amb classes

etiquetades o no i, després, tenir una funció de tipus condicional que invoqui la subfunció de

ranking pertinent a cada constructor.

La primera funció que veurem és la principal, i rep com a paràmetres els clàssics del

problema del ranking, és a dir, l’especificació principal, la classe a la que pertany l’objecte

del qual volem el rank i l’objecte pròpiament dit.

cod.63 funcioRank := proc(spec, class, obj) local aux, i, j; option remember; begin //Primer obtenim una llista amb els àtoms i epsilons que podrien aparèixer en l’objecte segons //l’especificació passada com a paràmetre. i := obteAtoms(rhs(op(spec,4))); j := obteEpsilons(rhs(op(spec,4))); //Obtenim també l’especificació equivalent en MuPAD per quan ens faci falta invocar la funció //count més endavant. aux := especEquivalent(rhs(op(spec,4)),rhs(op(spec,1))); //Com en el cas de l’unranking, per als algorismes teòrics vistos, el rank va entre 0 al nombre //total d’objectes – 1. Com que això no ens interessa, sumarem un 1 al resultat retornat per les //funcions de rank. if rhs(op(spec,1)) then //Si l’especificació és etiquetada invoquem la funció ranking per al cas etiquetat. return(rankingEtiquetat(rhs(op(spec,4)), class, obj, i, j, aux, rhs(op(spec,2)))+1); else //Altrament, invoquem la funció ranking per al cas no etiquetat. return(rankingNoEtiquetat(rhs(op(spec,4)), class, obj, i, j, aux, rhs(op(spec,2)))+1); end_if; end_proc;

Page 153: Títol: Generació Ordenada d’Estructures Combinatòries en

PFC – Generació Ordenada d’Estructures Combinatòries en “MuPAD-Combinat”

153

En el següent codi veiem la funció de ranking per al cas no etiquetat. Com ja hem dit,

consisteix en una estructura condicional que actua d’una o altra forma segons el constructor

amb que es trobi. També cobreix els casos bàsics de les classes atòmiques o epsilons.

cod.64 rankingNoEtiquetat := proc(t, MNT, obj, atoms, epsilons, aux, bous) option remember; begin //Si el constructor amb què ens trobem és Primitive... if op(t[MNT],0) = Primitive then //Si l’acompanya un 0 com a primer element estem en una classe epsilon. if op(t[MNT],1) = 0 then //Si l’objecte és igual a l’identificador que acompanya al constructor Primitive, aleshores hem de retornar el rank 0, ja que aquestes classes només tenen un element. if op(t[MNT],2) = obj then return(0); else return(); end_if; else //Si estem tractant amb una classe atòmica el comportament és exactament igual que el que //acabem de veure. if op(t[MNT],2) = obj then return(0); else return(); end_if; end_if; elif op(t[MNT],0) = Union then //Si el constructor és Union invoquem a la funció d’Union pertinent. return(rankUnionNoEtiquetat(t, MNT, obj, atoms, epsilons, aux, bous)); elif op(t[MNT],0) = Prod then if bous then //Si el constructor és Prod i l’ordre que tenim a l’especificació és bustrofèdic invoquem a la //subfunció específica de producte bustrofèdic. return(rankProdNoEtiquetatBous(t, MNT, obj, atoms, epsilons, aux, bous)); else //Altrament invoquem a la subfunció de producte lexicogràfic. return(rankProdNoEtiquetatLexico(t, MNT, obj, atoms, epsilons, aux, bous)); end_if; elif op(t[MNT],0) = Alias then //Si el constructor es Alias, cal que mirem quin és el segon element que acompanya al //constructor. if op(t[MNT],2) = op then //Si l’acompanya un op, realitzem una nova crida a rankingNoEtiquetat però passant com a //classe a la que pertany l’objecte el primer paràmetre que acompanya al constructor Alias. return(rankingNoEtiquetat(t, op(t[MNT],1), obj, atoms, epsilons, aux, bous)); else if op(op(t[MNT],2),1) = Sequence then //Si es tracta d’una Alias on hi apareix Sequence, aleshores invoquem la subfunció pertinent. return(rankSeqNoEtiquetat(t, MNT, obj, atoms, epsilons, aux, bous)); end_if; end_if; end_if; end_proc;

A continuació, es presenta l’adaptació de l’algorisme 20 de ranking per a Unions Disjuntes.

Page 154: Títol: Generació Ordenada d’Estructures Combinatòries en

Capítol V –Ranking

154

cod.65 rankUnionNoEtiquetat := proc(t, MNT, obj, atoms, epsilons, aux, bous) local auxil; option remember; begin //El funcionament en aquest cas, és exactament equivalent al vist en l’algorisme teòric. if isANoEtiquetat(t, op(t[MNT],1), obj, atoms, epsilons, aux) then return(rankingNoEtiquetat(t, op(t[MNT],1), obj, atoms, epsilons, aux, bous)); else //Obtenim el nombre d’àtoms de l’objecte. auxil := comptaAtoms(atoms, obj); return((aux::count(auxil, op(t[MNT],1)))+(rankingNoEtiquetat(t, op(t[MNT],2), obj, atoms, epsilons, aux, bous))); end_if; end_proc;

El següent fragment de codi implementa l’algorisme 27, és a dir, el ranking per Productes en

ordre Lexicogràfic.

cod.66 rankProdNoEtiquetatLexico := proc(t, MNT, obj, atoms, epsilons, aux, bous) local j, n, r, ralfa, rbeta; option remember; begin //La implementació no ha sofert canvis respecte a l’algorisme teòric. //Fem servir la opció comptaAtoms per recuperar el nombre d’àtoms totals del primer //element del producte i el nombre d’àtoms totals de l’objecte. j := comptaAtoms(atoms, op(obj,1)); n := comptaAtoms(atoms, obj); r := 0; for l from 0 to (j-1) do r := r + (aux::count(l, op(t[MNT],1)) * aux::count((n-l), op(t[MNT],2))); end_for; ralfa := rankingNoEtiquetat(t, op(t[MNT],1), op(obj,1), atoms, epsilons, aux, bous, midaObj); rbeta := rankingNoEtiquetat(t, op(t[MNT],2), op(obj,2), atoms, epsilons, aux, bous, midaObj); return(r+(ralfa * (aux::count((n-j),op(t[MNT],2))))+rbeta); end_proc;

L’adaptació de l’algorisme 27, ranking de Productes en ordre Bustrofèdic, tampoc no ha

sofert canvis durant el procés.

cod.67 rankProdNoEtiquetatBous := proc(t, MNT, obj, atoms, epsilons, aux, bous) local j, n, r, ralfa, rbeta; option remember; begin //Com en els altres casos no etiquetats, l’adaptació ha estat directa en aquest cas. j := comptaAtoms(atoms, op(obj,1)); n := comptaAtoms(atoms, obj); r := 0; if j <= (n - j) then for l from 0 to (j-1) do r := r + ((aux::count(l, op(t[MNT],1)) * aux::count((n-l), op(t[MNT],2))) + (aux::count((n - l), op(t[MNT],1)) * aux::count(l, op(t[MNT],2)))); end_for;

Page 155: Títol: Generació Ordenada d’Estructures Combinatòries en

PFC – Generació Ordenada d’Estructures Combinatòries en “MuPAD-Combinat”

155

else for l from 0 to (n - j-1) do r := r + ((aux::count(l, op(t[MNT],1)) * aux::count((n-l), op(t[MNT],2))) + (aux::count((n - l), op(t[MNT],1)) * aux::count(l, op(t[MNT],2)))); end_for; r := r + (aux::count((n - j), op(t[MNT],1)) * aux::count(j, op(t[MNT],2))); end_if; ralfa := rankingNoEtiquetat(t, op(t[MNT],1), op(obj,1), atoms, epsilons, aux, bous, midaObj); rbeta := rankingNoEtiquetat(t, op(t[MNT],2), op(obj,2), atoms, epsilons, aux, bous, midaObj); return(r+(ralfa * (aux::count((n-j),op(t[MNT],2))))+rbeta); end_proc;

A continuació veurem el codi corresponent al ranking de les Seqüències. Aquest codi no té

equivalent teòric, però és senzill veure que fa. En primer lloc, mirem si cada una de les

components de la Seqüència pertany a la classe sobre la que es conforma la Seqüència,

altrament no caldria que seguíssim. Si tot va bé, aleshores, basant-nos en l’isomorfisme de

les Seqüències, generem un Producte amb totes les components de l’objecte que ens hagin

passat i, aleshores, recuperem el rank d’aquest producte.

cod.68 rankSeqNoEtiquetat := proc(t, MNT, obj, atoms, epsilons, aux, bous) local i, b, s, auxil, auxil1, auxil2, auxil3; option remember; begin //Primer, fem servir un conjunt d’instruccions per tal de poder recuperar de la taula de //l’especificació quina és la classe sobre la que es conformen les Seqüències. Això s’ha de fer //així degut al format que s’ha donat al desenvolupament de les Seqüències en la funció //generador d’especificacions estàndard. auxil := []; auxil1 := op(t[MNT],1); auxil1 := coerce(auxil1,DOM_STRING); auxil3 := length(auxil1); auxil1 := auxil1[15..auxil3]; auxil2 := text2expr(auxil1); s := "NonTerminalSeq"; //Un cop aquí, ja sabem quin és l’identificador de la posició de la taula que conté la classe //associada a la Seqüència. i := 1; b := FALSE; //Per cada una de les components de la Seqüència, preguntem a is_A si es pot generar a //partir de la classe associada a la nostra Seqüència. while (i <= nops(obj)) do if op(obj,i) = Epsilon then //Epsilon sempre ha de formar part de les Seqüències. El booleà b ens servirà per tal de què, //si l’usuari no ha pensat a posar la Epsilon en l’objecte que ens ha passat, li puguem afegir //nosaltres. La presència de l’Epsilon és imprescindible ja que sinó, en calcular el rank final //de la Seqüència, no seria el correcte. b := TRUE; else if isANoEtiquetat(t, op(t[text2expr(s.(auxil2+3))],1), op(obj,i), atoms, epsilons, aux) then else return(FAIL); end_if; end_if; //Anem guardant les components de la Seqüència per tal de poder-les fer servir per crear el //producte total de les components. auxil := append(auxil,op(obj,i)); i := i + 1;

Page 156: Títol: Generació Ordenada d’Estructures Combinatòries en

Capítol V –Ranking

156

end_while; //Si l’usuari s’ha oblidat de posar la Epsilon, nosaltres li afegim. if b then else auxil := append(auxil,Epsilon); end_if; //Generem el producte de totes les components de la Seqüència. i := generaProd(auxil); //Retornem el rank del producte calculat. return(rankingNoEtiquetat(t, text2expr(s.(auxil2+3)), i, atoms, epsilons, aux, bous, midaObj)); end_proc;

La funció per generar el producte de les components és recursiva, i va generant Productes

binaris mitjançant crides a si mateixa.

cod.69 generaProd := proc(auxil) option remember; begin //Quan només tinguem dues components, retornem el producte entre elles. if nops(auxil) = 2 then return(Prod(op(auxil,1), op(auxil,2))); else //Si tenim més de dues components, retornem el producte entre la primera d’elles i el //resultat d’una crida a generaProd amb totes les components menys la primera. return(Prod(op(auxil,1),generaProd(auxil[2..nops(auxil)]))); end_if; end_proc;

Finalment, per tancar el conjunt de funcions sobre classes no etiquetades, veurem el codi

equivalent a l’algorisme 19, és a dir, is_A per a classe no etiquetades. Com en la majoria de

casos del ranking, s’ha pogut transcriure gairebé literalment l’algorisme.

cod.70 isANoEtiquetat := proc(t, MNT, obj, atoms, epsilons, aux) local aux1, aux2, aux3; option remember; begin //La implementació d’aquest codi és gairebé igual a l’algorisme. Tan sols ha calgut vigilar //amb l’accés a la informació de la taula en alguns casos (especialment amb el constructor //Alias, per tal de descobrir a quin constructor acompanyava). //Si l’objecte pertany a la llista d’epsilons o àtoms, i la classe es construeix amb Primitive, //hem de retornar un CERT. if (((contains(epsilons, obj)<>0) and (op(t[MNT],0) = Primitive) and (op(t[MNT],1) = 0)) or (((contains(atoms, obj)<>0) and (op(t[MNT],0) = Primitive) and (op(t[MNT],1) = 1)))) then return(TRUE); //Si l’objecte pertany a la llista d’epsilons i estem tractant una Seqüència, un Set o un //Powerset, també hem de retornar un CERT. elif (contains(epsilons, obj)<>0) and ((op( op(t[MNT],2),1 ) = Sequence) or (op(t[MNT],0) = Powerset) or (op(t[MNT],0) = Set)) then return(TRUE); //Si la classe és una Union, hem de mirar si l’objecte pertany a una de les dues classe de la //Unió. elif op(t[MNT],0) = Union then

Page 157: Títol: Generació Ordenada d’Estructures Combinatòries en

PFC – Generació Ordenada d’Estructures Combinatòries en “MuPAD-Combinat”

157

if isANoEtiquetat(t, op(t[MNT],1), obj, atoms, epsilons, aux) then return(TRUE); else return((isANoEtiquetat(t, op(t[MNT],2), obj, atoms, epsilons, aux))); end_if; //Si la classe és un Prod, aleshores hem de mirar que l’objecte pertanyi a les dues classes //del producte. elif op(t[MNT],0) = Prod then if (isANoEtiquetat(t, op(t[MNT],1), op(obj,1), atoms, epsilons, aux)) then return((isANoEtiquetat(t, op(t[MNT],2), op(obj,2), atoms, epsilons, aux))); else return(FALSE); end_if; //Si la classe és una Seqüència i l’objecte no és Epsilon, aleshores hem de mirar que //l’objecte pertanyi a la classe associada a la Seqüència. elif (op( op(t[MNT],2),1 ) = Sequence) then aux1 := op(t[MNT],1); aux3 := length(aux1); aux1 := aux[15..aux3]; aux2 := text2expr(aux1); return(isANoEtiquetat(t, op(t["NonTerminalSeq".(aux2+3)],1), obj, atoms, epsilons, aux)); //En el nostre cas, no tractarem més constructors. Emperò, si no fos així, aquí caldria tractar //els seus casos específics. else return(FALSE); end_if; end_proc;

L’estructura del ranking etiquetat és exactament igual a la del cas no etiquetat, així que els

comentaris seran mínims. La funció principal té estructura condicional i invoca una funció o

altra depenent del constructor de la classe tractada.

cod.71 rankingEtiquetat := proc(t, MNT, obj, atoms, epsilons, aux, bous) option remember; begin //El codi és exactament equivalent a la versió no etiquetada. Tan sols varia en el fet de què //els objectes ara porten etiquetes, i per tant, s’haurà d’usar la funció op per separar els //àtoms de les seves etiquetes. Per exemple, per obtenir l’àtom de l’objecte Z(1), faríem //op(Z(1),0), que retornaria Z. if op(t[MNT],0) = Primitive then //Tractem els casos del constructor Primitive com abans, comparant l’àtom de l’objecte amb //l’identificador associat al constructor. if op(t[MNT],1) = 0 then if op(t[MNT],2) = op(obj,0) then return(0); else return(); end_if; else if op(t[MNT],2) = op(obj,0) then return(0); else return(); end_if; end_if; //Per la resta de constructors, s’invoca la subfunció pertinent. elif op(t[MNT],0) = Union then

Page 158: Títol: Generació Ordenada d’Estructures Combinatòries en

Capítol V –Ranking

158

return(rankUnionEtiquetat(t, MNT, obj, atoms, epsilons, aux, bous)); elif op(t[MNT],0) = Prod then if bous then return(rankProdEtiquetatBous(t, MNT, obj, atoms, epsilons, aux, bous)); else return(rankProdEtiquetatLexico(t, MNT, obj, atoms, epsilons, aux, bous)); end_if; elif op(t[MNT],0) = Alias then if op(t[MNT],2) = op then return(rankingEtiquetat(t, op(t[MNT],1), obj, atoms, epsilons, aux, bous)); else if op(op(t[MNT],2),1) = Sequence then return(rankSeqEtiquetat(t, MNT, obj, atoms, epsilons, aux, bous)); end_if; end_if; end_if; end_proc;

Com ja hem dit en l’apartat 2 del present capítol, l’algorisme 20 de ranking per a Unions

Disjuntes val tant pels dos casos, etiquetats i no etiquetats.

cod.72 rankUnionEtiquetat := proc(t, MNT, obj, atoms, epsilons, aux, bous) local auxil; option remember; begin if isAEtiquetat(t, op(t[MNT],1), obj, atoms, epsilons, aux) then return(rankingEtiquetat(t, op(t[MNT],1), obj, atoms, epsilons, aux, bous)); else auxil := recuperaObj(obj, atoms, epsilons); return((aux::count(comptaAtoms(atoms, auxil), op(t[MNT],1)))+(rankingEtiquetat(t, op(t[MNT],2), obj, atoms, epsilons, aux, bous))); end_if; end_proc;

Mostrem a continuació el codi equivalent a l’algorisme 22, és a dir, la segona versió per al

ranking de productes en ordre lexicogràfic.

cod.73 rankProdEtiquetatLexico := proc(t, MNT, obj, atoms, epsilons, aux, bous) local j, n, r, ralfa, rbeta, rl, cana, canb, auxil, etiqa, etiqb; option remember; begin //Com que la funció implementada de comptatge d’àtoms només val per a objectes no //etiquetats, primer cal invocar una petita funció auxiliar que ens retorni l’objecte sense les //seves pertinents etiquetes. auxil := recuperaObj(obj, atoms, epsilons); j := comptaAtoms(atoms, op(auxil,1)); n := comptaAtoms(atoms, auxil); r := 0; for l from 0 to (j-1) do r := r + ((aux::count(l, op(t[MNT],1)) * aux::count((n-l), op(t[MNT],2))) * combinat::chooseNK::count(n,l)); end_for;

Page 159: Títol: Generació Ordenada d’Estructures Combinatòries en

PFC – Generació Ordenada d’Estructures Combinatòries en “MuPAD-Combinat”

159

//Fins aquí hem procedit normalment segons l’algorisme teòric. Ara, es veuran els canvis que //es podien observar en la versió 2 per tal de cobrir les diferències en el tractament de les //etiquetes. Recuperem les etiquetes dels dos subobjectes del producte. etiqa := [obteEtiq(atoms, epsilons, op(obj,1))]; etiqb := [obteEtiq(atoms, epsilons, op(obj,2))]; //Generem els objectes canònics dels dos subobjectes del producte. cana := canonic(op(obj,1), etiqa, atoms, epsilons, n); canb := canonic(op(obj,2), etiqb, atoms, epsilons, n); //Calculem els valors de ralfa i rbeta mitjançant la invocació de les funcions de ranking sobre //els dos suobjectes del producte. ralfa := rankingEtiquetat(t, op(t[MNT],1), cana, atoms, epsilons, aux, bous); rbeta := rankingEtiquetat(t, op(t[MNT],2), canb, atoms, epsilons, aux, bous); //Calculem el rank de l’etiquetatge mitjançant la funció rankLab que ja coneixem. rl := rankLab(etiqa, etiqb); //Finalment, calculem el rank de l’objecte normalment. return(r+(ralfa * ((aux::count((n-j),op(t[MNT],2))))*combinat::chooseNK::count(n,j))+(rbeta*combinat::chooseNK::count(n,j))+rl); end_proc;

El funcionament del ranking per al producte en ordre lexicogràfic segueix l’algorisme 25, i els

seus canvis són equivalents als que acabem de veure en el codi anterior.

cod.74 rankProdEtiquetatBous := proc(t, MNT, obj, atoms, epsilons, aux, bous) local j, n, r, ralfa, rbeta, rl, cana, canb, auxil, etiqa, etiqb; option remember; begin j := comptaAtoms(atoms, op(obj,1)); n := comptaAtoms(atoms, obj); r := 0; if j <= (n - j) then for l from 0 to (j-1) do r := r + (((aux::count(l, op(t[MNT],1)) * aux::count((n-l), op(t[MNT],2)))*combinat::chooseNK::count(n,l)) + ((aux::count((n - l), op(t[MNT],1)) * aux::count(l, op(t[MNT],2)))*combinat::chooseNK::count(n, (n-l)))); end_for; else for l from 0 to (n - j - 1) do r := r + (((aux::count(l, op(t[MNT],1)) * aux::count((n-l), op(t[MNT],2)))*combinat::chooseNK::count(n,l)) + ((aux::count((n - l), op(t[MNT],1)) * aux::count(l, op(t[MNT],2)))*combinat::chooseNK::count(n,(n-l)))); end_for; r := r + ((aux::count((n - j), op(t[MNT],1)) * aux::count(j, op(t[MNT],2)))*combinat::chooseNK::count(n, (n-j))); end_if; etiqa := [obteEtiq(atoms, epsilons, op(obj,1))]; etiqb := [obteEtiq(atoms, epsilons, op(obj,2))]; cana := canonic(op(obj,1), etiqa, atoms, epsilons); canb := canonic(op(obj,2), etiqb, atoms, epsilons); ralfa := rankingEtiquetat(t, op(t[MNT],1), cana, atoms, epsilons, aux, bous); rbeta := rankingEtiquetat(t, op(t[MNT],2), canb, atoms, epsilons, aux, bous); rl := rankLab(etiqa, etiqb);

Page 160: Títol: Generació Ordenada d’Estructures Combinatòries en

Capítol V –Ranking

160

return(r+(ralfa * ((aux::count((n-j),op(t[MNT],2))))*combinat::chooseNK::count(n,j))+(rbeta*combinat::chooseNK::count(n,j))+rl); end_proc;

Per obtenir un objecte equivalent però canònic (és a dir, el mateix objecte però amb les

etiquetes amb valor entre 1 i #d’àtoms de l’objecte i col·locades seguint l’ordre original),

usem la funció auxiliar canònic. Per exemple, suposem que desde l’objecte Prod(Prod(Z(2),

Z(4)), Prod(Z(5), Prod(Z(3), Z(1)))), s’invoca la funció canònic sobre cada una de les seves

components. En un moment determinat es voldrà calcular canònic(Prod(Z(5), Prod(Z(3),

Z(1))), [5,3,1], [Z], [Epsilon], 5). Aleshores, la traça de les seves variables seria:

• etiq := [5,3,1]

• aux1 := [1,3,5]

• aux2 := [0,0,0,0,0]

• aux2 := [1,0,1,0,1]

• aux2 := [1,0,2,0,3]

• aux3 := [3,2,1]

I finalment faríem servir aux3 per etiquetar Prod(Z,Prod(Z,Z)).

cod.75 canonic := proc(obj, etiq, atoms, epsilons, n) local aux1, aux2, aux3, i, j; option remember; begin //Guardem en una variable les etiquetes originals ordenades creixentment. aux1 := sort(etiq); i := 1; //Creem una taula auxiliar de longitud igual a la mida de l’objecte original amb totes les //seves posicions a 0. while i <= n do aux2[i] := 0; i := i + 1; end_while; i := 1; //Posem a 1 les posicions de la taula auxiliar que corresponguin als índexs que tinguin per //valor una de les etiquetes originals de l’objecte. while i <= nops(aux1) do aux2[aux1[i]] := 1; i := i + 1; end_while; i := 1; j := 1; //Substituïm en la taula auxiliar el valor de la posició per el seu valor canònic. while i <= n do if aux2[i] = 1 then aux2[i] := j; j := j + 1; end_if; i := i + 1; end_while; i := 1; aux3 := [];

Page 161: Títol: Generació Ordenada d’Estructures Combinatòries en

PFC – Generació Ordenada d’Estructures Combinatòries en “MuPAD-Combinat”

161

//Recuperem les etiquetes de la taula auxiliar segons l’ordre de l’etiquetatge original (el no //ordenat). while i <= nops(aux1) do aux3 := append(aux3,aux2[etiq[i]]); i := i + 1; end_while; //Finalment, recuperem l’objecte sense etiquetar, i el reetiquetem amb les etiquetes //canòniques. aux2 := recuperaObj(obj, atoms, epsilons); return(posaEtiqueta(atoms, epsilons, aux2, aux3)); end_proc;

Amb la següent funció auxiliar, recuperem un objecte sense el seu etiquetatge, és a dir,

l’equivalent no etiquetat d’un objecte etiquetat.

cod.76 recuperaObj := proc(obj, atoms, epsilons) local i, t; option remember; begin //Si l’objecte és un epsilon, aleshores no l’acompanya cap etiqueta i l’hem de retornar igual. if contains(epsilons, obj)<>0 then return(obj); elif contains(atoms, op(obj,0))<>0 then //Si l’objecte és un àtom, aleshores hem de retornar-lo igual però sense l’etiqueta. return(op(obj,0)); else //Si l’objecte no és ni àtom ni epsilon, vol dir que està acompanyat d’algun constructor. //Aleshores, el que fem és que, per cada component de l’objecte, recuperem el seu //equivalent no etiquetat i, finalment, el retornem tenint en compte d’adjuntar també el //constructor. i := 1; t := []; while i <= nops(obj) do t := append(t, recuperaObj(op(obj,i), atoms, epsilons) ); i := i + 1; end_while; return(op(obj,0)(op(t))); end_if; end_proc;

El funcionament de rankLab és exactament igual al seu equivalent teòric de l’algorisme 23.

cod.77 rankLab := proc(etiq1, etiq2) local aux, s, n, i, j, r, k; option remember; begin aux := sort(etiq1); j := nops(etiq1); n := j + nops(etiq2); r := 0; s[0] := 0; i := 1; while i <= j do s[i] := aux[i]; i := i + 1; end_while; for i from 1 to (j) do if (s[(i-1)] + 1) <= (s[i] - 1) then

Page 162: Títol: Generació Ordenada d’Estructures Combinatòries en

Capítol V –Ranking

162

for k from (s[(i-1)] + 1) to (s[i] - 1) do r := r + (combinat::chooseNK::count((n-k),(j-i))); end_for; end_if; end_for; return(r); end_proc;

Ara, veurem un codi necessari per recuperar les etiquetes d’un objecte donat.

cod.78 obteEtiq := proc(atoms, epsilons, obj) begin //El codi funciona mitjançant crides recursives a si mateix. Els casos base són quan trobem //un epsilon (cas en què no retornarem res) o un àtom (retornarem l’etiqueta que //acompanya l’identificador d’àtom). if contains(epsilons, obj)<>0 then return(); elif contains(atoms, op(obj,0))<>0 then return(op(obj,1)); else return(obteEtiq(atoms, epsilons, op(obj,1)), obteEtiq(atoms, epsilons, op(obj,2..nops(obj)))); end_if; end_proc;

El següent fragment de codi no té equivalent teòric, i funciona igual que el seu anàleg per al

cas no etiquetat. És l’encarregat de realitzar el ranking per a les Seqüències.

cod.79 rankSeqEtiquetat := proc(t, MNT, obj, atoms, epsilons, aux, bous) local i, b, s, auxil, auxil1, auxil2, auxil3; option remember; begin auxil := []; auxil1 := op(t[MNT],1); auxil1 := coerce(auxil1,DOM_STRING); auxil3 := length(auxil1); auxil1 := auxil1[15..auxil3]; auxil2 := text2expr(auxil1); s := "NonTerminalSeq"; i := 1; b := FALSE; while (i <= nops(obj)) do if op(obj,i) = Epsilon then b := TRUE; else if isAEtiquetat(t, op(t[text2expr(s.(auxil2+3))],1), op(obj,i), atoms, epsilons, aux) then else return(FAIL); end_if; end_if; auxil := append(auxil,op(obj,i)); i := i + 1; end_while; if b then else auxil := append(auxil,Epsilon);

Page 163: Títol: Generació Ordenada d’Estructures Combinatòries en

PFC – Generació Ordenada d’Estructures Combinatòries en “MuPAD-Combinat”

163

end_if; i := generaProd(auxil); return(rankingEtiquetat(t, text2expr(s.(auxil2+3)), i, atoms, epsilons, aux, bous, midaObj)); end_proc;

Finalment, ja podem passar a veure la implementació de l’algorisme 18. El funcionament és

exactament igual al seu equivalent teòric però, s’ha fet una petita modificació: donat que el

nostre tractament per a les etiquetes és una mica diferent, s’ha suprimit del condicional que

fa referència al producte la condició referent al rank de l’etiqueta, ja que això es comprova

per si sol en la funció rankLab. Així, no cal fer cap més comentari sobre aquesta funció, que

realitza exactament les mateixes tasques que el seu anàleg no etiquetat, però parant atenció

de separa correctament els objectes de les seves etiquetes.

cod.80 isAEtiquetat := proc(t, MNT, obj, atoms, epsilons, aux) local aux1, aux2, aux3; option remember; begin if (((contains(epsilons, obj)<>0) and (op(t[MNT],0) = Primitive) and (op(t[MNT],1) = 0)) or (((contains(atoms, op(obj,0))<>0) and (op(t[MNT],0) = Primitive) and (op(t[MNT],1) = 1)))) then return(TRUE); elif (contains(epsilons, obj)<>0) and ((op( op(t[MNT],2),1 ) = Sequence) or (op(t[MNT],0) = Powerset) or (op(t[MNT],0) = Set)) then return(TRUE); elif op(t[MNT],0) = Union then if isAEtiquetat(t, op(t[MNT],1), obj, atoms, epsilons, aux) then return(TRUE); else return((isAEtiquetat(t, op(t[MNT],2), obj, atoms, epsilons, aux))); end_if; elif op(t[MNT],0) = Prod then if (isAEtiquetat(t, op(t[MNT],1), op(obj,1), atoms, epsilons, aux)) then return((isAEtiquetat(t, op(t[MNT],2), op(obj,2), atoms, epsilons, aux))); else return(FALSE); end_if; elif (op( op(t[MNT],2),1 ) = Sequence) then aux1 := op(t[MNT],1); aux3 := length(aux1); aux1 := aux[15..aux3]; aux2 := text2expr(aux1); return(isAEtiquetat(t, op(t["NonTerminalSeq".(aux2+3)],1), obj, atoms, epsilons, aux)); else return(FALSE); end_if; end_proc;

Page 164: Títol: Generació Ordenada d’Estructures Combinatòries en

Capítol V –Ranking

164

4 Anàlisi del Cost

Si assumim que el cost de la funció is_A és constant aleshores és clar que el cost del ranking

té el mateix comportament que el cost de l’unranking, ja que l’algorisme de ranking té el

mateix comportament que la seva contrapartida per l’unranking. Això es resumeix en el

següent teorema.

Teorema 4. Si el cost de la funció ( )α,_ AAis és constant, la complexitat (tan en el pitjor

cas com en el cas mig) de realitzar el ranking d’objectes d’ A és del mateix ordre de

magnitud que la complexitat de l’unranking per a aquesta classe.

Això significa que els teoremes vistos en el capítol anterior per a l’unranking etiquetat i no

etiquetat també són vàlids per al cas del ranking.

A continuació veurem els resultats obtinguts en milisegons, després de realitzar el ranking

sobre 1100 objectes generats a l’atzar (mitjançant la funció random de MuPAD i la nostra

funcioUnrank) en diverses situacions.

Arbres Binaris: B = Union(Z, Prod(B,B))

• No Etiquetats.

• Ordre Lexicogràfic.

Mida (n)

Jordi Ranking

MuPAD Unrank

Jordi Unrank

25 1,86 7,12 1,99 50 2,99 18,81 4,94 75 8,23 33,27 8,8 100 14,27 50,83 13,47 125 20,15 78,84 20,02 150 28,27 120,03 31,31

• No Etiquetats.

• Ordre Bustrofèdic.

Mida (n)

Jordi Ranking

MuPAD Unrank

Jordi Unrank

25 2,48 4,8 2,4 50 3,96 10 5,01 75 7,2 20,4 8 100 9,75 30 11 125 13,65 38 14,02 150 18,18 42,3 18,8

Ranking Arbres Binaris no etiquetats en ordre lexicogràfic

020406080

100120140

25 50 75 100 125 150

Mida

Mili

sego

ns Jordi RankingMuPADJordi Unranking

Ranking Arbres Binaris no etiquetats en ordre bustrofèdic

0

10

20

30

40

50

1 2 3 4 5 6

Mida

Mili

sego

ns Jordi RankingMuPADJordi Unranking

Page 165: Títol: Generació Ordenada d’Estructures Combinatòries en

PFC – Generació Ordenada d’Estructures Combinatòries en “MuPAD-Combinat”

165

Pel cas etiquetat tot el cost se l’emporta el càlcul de l’etiquetatge i estem a l’espera de

millorar l’algorisme corresponent (o, si més no, fer una cerca bibliogràfica més exhaustiva

per obtenir noves fonts amb codis més eficients).

4.1 Sortides generades

A continuació anirem generant diversos exemples per veure la major part de les

funcionalitats que cobreix el codi vist en l’apartat anterior.

Capçalera funció funcioRank(spec, class, obj)

spec Objecte de tipus especificació estàndard. class Identificador de la classe a la que pertany l'objecte.

obj Objecte (en el format de les sortides de la funcioUnrank) sobre el qual volem obtenir el rank.

1. Entre tots els 14 objectes de mida 5 en els arbres binaris no etiquetats, demanem el

rank del segon.

k := {B=Union(Z,Prod(B,B)) };

bn := generaEspecificacioEstandard(k, FALSE,FALSE);

funcioRank(bn, B, Prod(Z,Prod(Z,Prod(Prod(Z,Z),Z))));

2

2. Entre tots els 120 objectes de mida 4 en els arbres binaris etiquetats, demanem el rank

del 113è.

k := {B=Union(Z,Prod(B,B)) };

bn := generaEspecificacioEstandard(k, TRUE,FALSE);

funcioRank(bn, B, Prod(Prod(Prod(Z(3), Z(1)), Z(2)), Z(4)));

113

3. Entre tots els 14 objectes de mida 4 en les Seqüències associades als arbres binaris no

etiquetats, demanem el rank del quart.

k := {S=Sequence(B), B=Union(Z,Prod(B,B)) };

bn := generaEspecificacioEstandard(k, FALSE,FALSE);

funcioRank(bn, S, Sequence(Z, Prod(Z, Prod(Z, Z)), Epsilon));

4

4. Entre tots els 336 objectes de mida 4 en els arbres binaris etiquetats, demanem el rank

del 334è.

k := {S=Sequence(B), B=Union(Z,Prod(B,B)) };

bn := generaEspecificacioEstandard(k, TRUE,FALSE);

funcioRank(bn, S, Sequence(Prod(Prod(Prod(Z(4), Z(2)), Z(1)), Z(3)), Epsilon));

334

Page 166: Títol: Generació Ordenada d’Estructures Combinatòries en
Page 167: Títol: Generació Ordenada d’Estructures Combinatòries en

Capítol VI

Balanç i Conclusions

Page 168: Títol: Generació Ordenada d’Estructures Combinatòries en

Índex del capítol

1 OBJECTIUS COBERTS ................................................................................... 169

2 CONCLUSIONS................................................................................................. 169

3 FEINA FUTURA ................................................................................................ 170

Page 169: Títol: Generació Ordenada d’Estructures Combinatòries en

PFC – Generació Ordenada d’Estructures Combinatòries en “MuPAD-Combinat”

169

1 Objectius Coberts

En aquest projecte hem estudiat i implementat en MuPAD els diversos algorismes existents

per al ranking i l’unranking d’estructures combinatòries.

Dels objectius que s’han plantejat en el primer capítol podem veure que:

• Hem pogut realitzar un complet estudi dels algorismes existents d’unranking i hem

generat un codi capaç de resoldre aquest problema en MuPAD. Aquest era l’objectiu

primari del present projecte.

• Hem pogut realitzar un estudi dels algorismes bàsics de ranking i hem generat un

codi capaç de resoldre aquest problema (per a alguns casos) en MuPAD. Amb el que

s’ha vist, s’han assentat les bases per a poder desenvolupar més endavant una

solució completa per a aquest problema.

• En el capítol dedicat a l’unranking hem vist una solució per a la generació exhaustiva

i la generació aleatòria basada en els algorismes d’unranking. Amb el temps destinat

al projecte, no hem tingut temps d’estudiar solucions més eficients.

2 Conclusions

Amb el desenvolupament del codi presentat, hem aportat noves utilitats (recolzades sobre

una ferma teoria) als futurs usuaris de MuPAD. Ara bé, cal remarcar que la tasca no ha estat

precisament senzilla. Primer, ha calgut creat un codi per a obtenir especificacions estàndard i

familiaritzar-nos amb l’entorn de programació proporcionat per MuPAD. Aquest procés

d’adaptació ha estat estrictament necessari ja que, en un principi, no es tenia cap mena de

coneixement de l’entorn MuPAD, i el conjunt del projecte es veia inabastable.

També ha calgut desenvolupar algorismes addicionals en aquelles situacions en què la teoria

no era del tot precisa o deixava marges, com ara els algorismes per realitzar l’unranking de

les (n, j)-particions o la transformació de l’etiquetatge des de les llistes de subllistes a un

format més humà. Algunes de les noves funcions implementades han sorgit com una

necessitat en descobrir que no es trobaven a les llibreries de MuPAD i per tant, han consumit

un temps per al qual no s’havia comptat.

Ha resultat especialment interessant realitzar un anàlisi del cost i el temps de les nostres

solucions en comparació amb els resultats obtinguts en MuPAD per a les mateixes entrades,

ja que així s’ha pogut arribar a la conclusió que els algorismes implementats són

competitius.

Page 170: Títol: Generació Ordenada d’Estructures Combinatòries en

Capítol VI – Balanç i Conclusions

170

3 Feina Futura

De cara a les possibles tasques a desenvolupar en un futur, es poden resumir en els

següents tres punts:

• Acabar d’implementar els algorismes de ranking per tal de cobrir tots els possibles

constructors amb què ens puguem trobar i presentar així una solució completa

(encara que no única, com ja s’ha comentat en el capítol destinat al ranking).

• Implementar una solució eficient per a la generació exhaustiva. Tot i que en el

present document s’ha vist una possible solució a aquest problema mitjançant l’ús de

la funció d’unrank, existeixen algorismes basats en iteradors que resulten molt més

eficients per a la resolució d’aquest problema. Existeix una detallada teoria per fer

front a aquest problema.

• Implementar una sortida visual per als outputs generats pel packet MuPAD-

Combinat, fent així molt més comprensibles visualment els resultats obtinguts. Un

clar exemple podrien ser els arbres binaris:

Prod(Z,Prod(Prod(Z,Z),Prod(Z,Prod(Z,Z))))

• Realitzar un estudi d’eficiència formal de les funcions de rank i unrank per tal de

poder incloure el codi implementat en futures versions del paquet MuPAD-Combinat.

Page 171: Títol: Generació Ordenada d’Estructures Combinatòries en
Page 172: Títol: Generació Ordenada d’Estructures Combinatòries en

Referències

Page 173: Títol: Generació Ordenada d’Estructures Combinatòries en

PFC – Generació Ordenada d’Estructures Combinatòries en “MuPAD-Combinat”

173

Referències

[1] C.Creutzig i W. Oevel. MuPAD Tutorial, English Edition. Springer-Verlag, 2004.

[2] M. Majewski. MuPAD Pro Computing Essentials. Springer-Verlag, 2004.

[3] R. Cases i L. Màrquez. Lenguajes, gramáticas y autómatas. Edicions UPC, 2001.

[4] P. Flajolet, P. Zimmermann i B. Van Cutsem. A calculus for the random generation of

combinatorial structures. Theorical Computer Science, 1994.

[5] P. Flajolet i J. S. Vitter. Average-case Analysis of Algorithms and Data Structures. North-

Holland, 1990.

[6] R. Kemp. Generating words lexicographically: An average-case analysis. Acta

Informatica, 1998.

[7] D. L. Kreher i D. R. Stinson, Combinatorial Algorithms: Generation, Enumeration and

Search. CRC Press LLC, 1999.

[8] C. Martínez i X. Molinero. Unranking of labelled combinatorial structures. En D. Krob, A.

A. A. Mikhalev, i A. V. Mikhalev, editors, Formal Power Series and Algebraic Combinatorics:

12th International Conference; Procedings / FPSAC’00. Springer-Verlag, 2000.

[9] C. Martínez i X. Molinero. A generic approach for the unranking of labelled combinatorial

classes. Random Structures & Algorithms, 2001.

[10] A. Nijenhius i H. S. Wilf. Combinatorial Algorithms: For Computers and Calculators.

Academic Press, Inc., 1978.

[11] E. M. Reingold, J. Nievergelt, i N. Deo. Combinatorial Algorithms: Theory and Practice.

Prentice-Hall, Englewood Cliffs, NJ, 1977.

[12] X. Molinero. Ordered Generation of Classes of Combinatorial Structures. Tesi doctoral

presentada al Programa de Doctorat de Matemàtica Aplicada de la UPC, Barcelona, 2005.

[13] Combinatoria. URL: http://www.hiru.com/matematika/matematika_05300.html

[14] MuPAD-Combinat. URL: http://mupad-combinat.sourceforge.net

[15] MuPAD. URL: http://www.mupad.org

[16] Context-free grammar. URL: http://en.wikipedia.org/wiki/Context-free_grammar

[17] Chomsky normal form. URL: http://en.wikipedia.org/wiki/Chomsky_normal_form