Instructie

In dit gedeelte maken we een voorbeeldproject aan, waarin enkele van de meest belangrijke eigenschappen van Rocs worden gebruikt. Het doel is een graaf en een script te maken voor een eenvoudig 2-benaderingsalgoritme voor het "minimum vertex cover"- probleem. Dit houdt in het zoeken naar de kleinste deelverzameling C van de knopen van de graaf, zodat elke kant van de graaf met tenminste een knoop van C is verbonden. Het is bekend dat dit probleem "NP-hard" is, en we willen laten zien hoe we een benadering met een factor 2 kunnen vinden door een overeenkomst in de bestaande graaf te zoeken (in het volgende gebruiken we de gebruikelijke termen in graafalgoritmes: graaf is de gegevensstructuur, knopen zijn de gegevenselementen, kanten zijn de pijlen). (Noot vertaler: ik handhaaf vele Engelse benamingen, ten eerste om de gebruiker van deze tekst in de gelegenheid te stellen om naar deze namen te googlen, en ten tweede omdat ik van de meeste niet de Nederlandse naam (als die er is) ken, of kan vinden).

Ons doel is de overeenkomst zichtbaar te maken tussen de overeenkomende en de "minimum vertex cover". Hiervoor moeten we twee kanttypen specificeren, een voor het tonen van de overeenkomende kanten, en een voor de gewone kanten. En verder twee knooptypen, die gebruikt worden voor het onderscheid tussen knopen in C en knopen die niet tot C behoren.

Een graaf genereren

Voor het aanmaken van de graaf is in Rocs een hulpmiddel aanwezig waarmee grafen kunnen worden aangemaakt. We gaan naar het menu GraafdocumentHulpmiddelenGraaf aanmaken. Hier genereren we een Willekeurige graaf, met 30 knopen, 90 kanten en met het zaadje 1 (het zaadje is de startwaarde voor het genereren van willekeurige getallen; meerdere keren dit zelfde zaadje gebruiken resulteert in dezelfde, en dus reproduceerbare grafen).

De elementtypen genereren

Met Elementtypen maken we een tweede knooptype aan en een tweede kanttype. Voor beide nieuwe typen openen we de eigenschappendialoog met respectievelijk de knoppen Eigenschappen en zetten de ID's op 2. Verder wijzigen we de kleuren van elementen van de beide nieuwe typen (om ze van de standaardtypen te onderscheiden). Tenslotte maken we alle kanttypen bidirectioneel en de ID's van de standaardtypen 1.

Het algoritme

Tenslotte moeten we het benaderingsalgoritme implementeren. Hiervoor gebruiken we het volgende:

for (var i=0; i < Document.nodes.length; i++) {
    Document.nodes[i].type = 1;
}
for (var i=0; i < Document.edges.length; i++) {
    Document.edges[i].type = 1;
}

var E = Document.edges(); // verzameling onverwerkte kanten
var C = new Array();      // overeenkomende kanten
while (E.length 
> 0) {
    var e = E[0];         // we nemen eerste kant e={u,v}
    var u = e.from();
    var v = e.to();
    e.type = 2;           // maak kant overeenkomend
    E.shift();            // verwijder e (bijv. E[0]) uit kantenlijst
    C.push(u);            // u aan C toevoegen
    C.push(v);            // v aan C toevoegen

    // u,v als knopen in C markeren
    u.type = 2;
    v.type = 2;

    // uit E alle kanten verwijderen die verbonden zijn met u of v
    var aanliggend = u.edges();
    for (var i=0; i < aanliggend.length; i++) {
        var index = E.indexOf(aanliggend[i]); // de index bepalen
        if (index != -1) {
            E.splice(index, 1); // het verwijderen indien gevonden
        }
    }
    var aanliggend = v.edges();
    for (var i=0; i < aanliggend.length; i++) {
        var index = E.indexOf(adjacent[i]); // de index bepalen
        if (index != -1) {
            E.splice(index, 1); // het verwijderen indien gevonden
        }
    }
}
Console.log("Vertex Cover bevat " + C.length + " knopen.");

Het algoritme uitvoeren

Het algoritme kunnen we starten met de knop Uitvoeren in het controlepaneel voor scripts.