Pannyx

devel

Request #07


% cdp
~/devel/proto
% pp aej-qlist_for_array_of_subtype_of_int.adb aej-qlist_for_array_of_subtype_of_int.ads
with Ada.Text_IO;
with Aej.Daejana;
package body Aej.Qlist_For_Array_Of_Subtype_Of_Int is

use Ada; use Text_IO;
use Aej; use Daejana;

use type Int_T;

function New_Qlist (N : Enum_T) return Qlist_T is begin
      return new Qlist_St'(N, null, null); end New_Qlist;

procedure Enqueue (Q : Qlist_T; A : Array_T) is
   B : Qlist_Node_T; P : Qlist_Node_T;

begin
   P := new Qlist_Node_St'(Q.N, A, null);
   B := Q.Last;
   Q.Last := P;
   if B = null then
      Q.First := P;
   else
      B.Next := P;
   end if;
   return;

end Enqueue;

function Dequeue (Q : Qlist_T) return Array_T is
   B : Qlist_Node_T; P : Qlist_Node_T;

begin
   B := Q.First;
   if B = null then Ouch; return Array_T'(1 .. 0 => 0); end if;

   if B.Next = null then
      Q.Last := null;
   end if;
   Q.First := B.Next;
   return B.Item;

end Dequeue;

procedure Delete_Qlist (Q : in out Qlist_T) is begin if Q = null then Ouch; raise Constraint_Error; end if;
      declare A : Array_T(1 .. Q.N); begin while To_First(Q) /= null loop A := Dequeue(Q); end loop; end;
      Q := null; return; end Delete_Qlist;

procedure Delete_Perms (Q : in out Qlist_T) is begin
      Delete_Qlist(Q); return; end Delete_Perms;

function To_First (Q : Qlist_T) return Qlist_Node_T is begin
      return Q.First; end To_First;

procedure To_Next (P : in out Qlist_Node_T) is begin
      P := P.Next; return; end To_Next;

function Item (P : Qlist_Node_T) return Array_T is begin
      return P.Item; end Item;

end Aej.Qlist_For_Array_Of_Subtype_Of_Int;
with Ada.Text_IO;
with Aej.Daejana;
generic

   type Item_T is range <>;
   type Array_T is array (Index_T range <>) of Item_T;

package Aej.Qlist_For_Array_Of_Subtype_Of_Int is

use Ada; use Text_IO;
use Aej; use Daejana;

type Qlist_Node_St (N : Enum_T) is private;
type Qlist_Node_T is access all Qlist_Node_St;

type Qlist_St is private;
type Qlist_T is access all Qlist_St;

function New_Qlist (N : Enum_T) return Qlist_T;
procedure Delete_Qlist (Q : in out Qlist_T);

function To_First (Q : Qlist_T) return Qlist_Node_T;
procedure To_Next (P : in out Qlist_Node_T);
function Item (P : Qlist_Node_T) return Array_T;

procedure Enqueue (Q : Qlist_T; A : Array_T);
function Dequeue (Q : Qlist_T) return Array_T;

private

   type Qlist_Node_St (N : Enum_T) is record
      Item : Array_T(1 .. N);
      Next : Qlist_Node_T;
   end record;

   type Qlist_St is record
      N : Enum_T;
      First : Qlist_Node_T;
      Last : Qlist_Node_T;
   end record;

end Aej.Qlist_For_Array_Of_Subtype_Of_Int;
% pp aej-perms.adb aej-perms.ads
with Ada.Text_IO;
with Aej.Daejana;
with Aej.Qlist_For_Array_Of_Subtype_Of_Int;
package body Aej.Perms is

use Ada; use Text_IO;
use Aej; use Daejana;

use type Int_T;

use Qlist_Of_Int_Array;

function New_Perms (N : Enum_T) return Qlist_T is

   Q : Qlist_T;

   procedure Qadd (A : Array_T; B : Array_T) is

   begin
      if B'Length < 2 then Enqueue(Q, A & B); return; end if;

      for K in B'Range loop
         Qadd(A & Array_T'(1 => B(K)), B(B'First .. K - 1) & B(K + 1 .. B'Last));
      end loop;
      return;

   end Qadd;

   B : Array_T(1 .. N);

begin
   Q := New_Qlist(N);
   if N < 1 then return Q; end if;

   if N < 2 then Enqueue(Q, Array_T'(1 => 1)); return Q; end if;

   for K in B'Range loop B(K) := Item_T( K); end loop;
   Qadd(Array_T'(1 .. 0 => <>), B);
   return Q;

end New_Perms;

procedure Delete_Perms (Q : in out Qlist_T) is begin
      Delete_Qlist(Q); return; end Delete_Perms;

end Aej.Perms;
with Ada.Text_IO;
with Aej.Daejana;
with Aej.Qlist_For_Array_Of_Subtype_Of_Int;
generic

   type Item_T is range <>;
   type Array_T is array (Index_T range <>) of Item_T;

package Aej.Perms is

use Ada; use Text_IO;
use Aej; use Daejana;

package Qlist_Of_Int_Array is new Qlist_For_Array_Of_Subtype_Of_Int(Item_T, Array_T);

subtype Qlist_Node_St is Qlist_Of_Int_Array.Qlist_Node_St;
subtype Qlist_Node_T is Qlist_Of_Int_Array.Qlist_Node_T;

subtype Qlist_St is Qlist_Of_Int_Array.Qlist_St;
subtype Qlist_T is Qlist_Of_Int_Array.Qlist_T;

function New_Perms (N : Enum_T) return Qlist_T;
procedure Delete_Perms (Q : in out Qlist_T);

function To_First (Q : Qlist_T) return Qlist_Node_T renames Qlist_Of_Int_Array.To_First;
procedure To_Next (P : in out Qlist_Node_T) renames Qlist_Of_Int_Array.To_Next;
function Item (P : Qlist_Node_T) return Array_T renames Qlist_Of_Int_Array.Item;

function Dequeue (Q : Qlist_T) return Array_T renames Qlist_Of_Int_Array.Dequeue;

end Aej.Perms;
% cdm
~/devel/sleek
% pp perms_m.adb
with Ada.Characters.Handling;
with Ada.Command_Line;
with Ada.Exceptions;
with Ada.Text_IO;
with Aej.Daejana;
with Aej.Perms;
procedure Perms_M is

use Ada; use Text_IO;
use Aej; use Daejana;

use Int_IO;
use type Int_T;

function From_String (S : String) return Enum_T is
   J : Enum_T; N : Enum_T;

begin
   N := 0; J := 1;
   while J < S'Length + 1 loop
      exit when not Characters.Handling.Is_Digit(S(Integer( J)));

      N := N * 10 + Enum_T( Character'Pos(S(Integer( J)))) - 48;
      J := J + 1;
   end loop;

   return N;

end From_String;

type Int_Array_T is array (Index_T range <>) of Int_T;
package Pp is new Perms(Int_T, Int_Array_T); use Pp;

use type Qlist_Node_T;

Q : Qlist_T;
P : Qlist_Node_T;
J : Int_T;
N : Enum_T;

begin
   Command_Line.Set_Exit_Status(Command_Line.Success);
   New_Line;

   N := (if 0 < Command_Line.Argument_Count then From_String(Command_Line.Argument(1)) else 4);

   declare
      A : Int_Array_T(1 .. N);

   begin
      Q := New_Perms(N);

--    Put("("); New_Line;
--    P := To_First(Q);
--    while P /= null loop
--       Put("   [");
--       A := Item(P);
--       for K in A'Range loop
--          Put(A(K), Width => 2);
--       end loop;
--       Put(" ],"); New_Line;
--       To_Next(P);
--    end loop;
--    Put(");"); New_Line;
--    New_Line;

      Put("("); New_Line;
      while To_First(Q) /= null loop
         Put("   [");
         A := Dequeue(Q);
         for K in A'Range loop
            Put(A(K), Width => 2);
         end loop;
         Put(" ],"); New_Line;
      end loop;
      Put(");"); New_Line;

      Delete_Perms(Q);
   end;
   New_Line;
   return;

exception
   when E : others =>
      New_Line(Standard_Error);
      New_Line(Standard_Error);
      Put(Standard_Error, "** ");
      Put(Standard_Error, Exceptions.Exception_Name(E));
      Put(Standard_Error, "! (");
      Put(Standard_Error, Exceptions.Exception_Message(E));
      Put(Standard_Error, ")");
      New_Line(Standard_Error);
      New_Line;
      Command_Line.Set_Exit_Status(Command_Line.Failure);

end Perms_M;
% abr perms_m

(
   [ 1 2 3 4 ],
   [ 1 2 4 3 ],
   [ 1 3 2 4 ],
   [ 1 3 4 2 ],
   [ 1 4 2 3 ],
   [ 1 4 3 2 ],
   [ 2 1 3 4 ],
   [ 2 1 4 3 ],
   [ 2 3 1 4 ],
   [ 2 3 4 1 ],
   [ 2 4 1 3 ],
   [ 2 4 3 1 ],
   [ 3 1 2 4 ],
   [ 3 1 4 2 ],
   [ 3 2 1 4 ],
   [ 3 2 4 1 ],
   [ 3 4 1 2 ],
   [ 3 4 2 1 ],
   [ 4 1 2 3 ],
   [ 4 1 3 2 ],
   [ 4 2 1 3 ],
   [ 4 2 3 1 ],
   [ 4 3 1 2 ],
   [ 4 3 2 1 ],
);

% cda
~/devel/proto/aej
% pp qlist_int_chunk.c qlist_int_chunk.h
#define QLIST_INT_CHUNK_C
#include <qlist_int_chunk.h>

qlist_int_chunk_t new_qlist_int_chunk (int_t n) { qlist_int_chunk_t q;
      if (( q = malloc(sizeof(qlist_int_chunk_st))) == NULL) { ouch(); return NULL; }
      q->n_items = n; q->first = NULL; q->last = NULL; return q; }

void
delete_qlist_int_chunk (qlist_int_chunk_t * q)
{

   if (* q == NULL) { return; }

   while (!( qlist_int_chunk_to_first(* q) == NULL)) {
      qlist_int_chunk_dequeue(* q);
   }
   free(* q); * q = NULL;
   return;

}

qlist_int_chunk_node_t qlist_int_chunk_to_first (qlist_int_chunk_t q) {
      return q->first; }

qlist_int_chunk_node_t qlist_int_chunk_to_last (qlist_int_chunk_t q) {
      return q->last; }

qlist_int_chunk_node_t qlist_int_chunk_to_next (qlist_int_chunk_node_t p) {
      return p->next; }

int_t * qlist_int_chunk_access (qlist_int_chunk_node_t p) {
      return p->v; }

void
qlist_int_chunk_enqueue (qlist_int_chunk_t q, int_t * v)
{
   int_t k; qlist_int_chunk_node_t b; qlist_int_chunk_node_t p;

   if (( p = malloc(sizeof (qlist_int_chunk_node_st) + sizeof (int_t) * q->n_items)) == NULL) { ouch(); return; }

   p->next = NULL; if (!( v == NULL)) { k = 0; while (k < q->n_items) { p->v[k] = v[k]; k += 1; } }
   b = q->last;
   q->last = p;
   if (b == NULL) {
      q->first = p;
   }
   else {
      b->next = p;
   }
   return;

}

void
qlist_int_chunk_dequeue (qlist_int_chunk_t q)
{
   qlist_int_chunk_node_t b;

   b = q->first;
   if (b == NULL) { ouch(); return; }

   if (b->next == NULL) {
      q->last = NULL;
   }
   q->first = b->next;
   free(b);
   return;

}

// qlist_int_chunk.c
#ifndef QLIST_INT_CHUNK_H
#define QLIST_INT_CHUNK_H
#include <daejana.h>

struct qlist_int_chunk_node_struct;
typedef struct qlist_int_chunk_node_struct * qlist_int_chunk_node_t;
typedef struct qlist_int_chunk_node_struct {
   qlist_int_chunk_node_t next;
   int_t v [];
} qlist_int_chunk_node_st;

typedef struct qlist_int_chunk_struct {
   int_t n_items;
   qlist_int_chunk_node_t first;
   qlist_int_chunk_node_t last;
} qlist_int_chunk_st, * qlist_int_chunk_t;

#ifndef QLIST_INT_CHUNK_C
#endif

qlist_int_chunk_t new_qlist_int_chunk (int_t);
void delete_qlist_int_chunk (qlist_int_chunk_t *);

qlist_int_chunk_node_t qlist_int_chunk_to_first (qlist_int_chunk_t);
qlist_int_chunk_node_t qlist_int_chunk_to_last (qlist_int_chunk_t);
qlist_int_chunk_node_t qlist_int_chunk_to_next (qlist_int_chunk_node_t);
int_t * qlist_int_chunk_access (qlist_int_chunk_node_t);

void qlist_int_chunk_enqueue (qlist_int_chunk_t, int_t *);
void qlist_int_chunk_dequeue (qlist_int_chunk_t);

#endif
// qlist_int_chunk.h
% pp perms.c perms.h
#include <perms.h>

static void new_perms_aux (qlist_int_chunk_t, int_t, int_t *, int_t, int_t *, int_t *);


static void
new_perms_aux (qlist_int_chunk_t q, int_t m, int_t r [], int_t n, int_t s [], int_t * p)
{
   int_t j; int_t k; int_t l; int_t * v;

   if (n < 1) {
      qlist_int_chunk_enqueue(q, r);  // v[0..m-1] ← r[0..m-1]
      * p += 1;
      return;
   }
   {
      int_t a [m + 1];
      int_t b [n - 1];

      k = 0; while (k < m) { a[k] = r[k]; k += 1; }  // a[0..m-1] ← r[0..m-1]
      l = 0;
      while (l < n) {
         a[m] = s[l];  // a[m] ← s[l], l := 0..n-1
/*
         k = 0;
         j = 0;
         while (j < n) {
            if (!(a[m] == s[j])) {
               b[k] = s[j];  // b[k] ← t[j], k,j := 0..n-1, if not a[m] = s[j]
               k += 1;
            }
            j += 1;
         }
*/
         if (l < 1) {
            new_perms_aux(q, m + 1, a, n - 1, & s [1], p);
         }
         else if (l < n - 1) {
            memcpy(b, s, l * sizeof (int_t)); memcpy(& b [l], & s [l + 1], (n - 1 - l) * sizeof (int_t));
            new_perms_aux(q, m + 1, a, n - 1, b, p);
         }
         else {
            new_perms_aux(q, m + 1, a, n - 1, s, p);
         }
         l += 1;
      }
   }
   return;

}

void new_perms (int_t n, qlist_int_chunk_t * q, int_t * p)
{
   int_t k;

   if (n < 1) { * q = NULL; return; }

   * q = new_qlist_int_chunk(n);
   {
      int_t s [n];

      k = 0;
      while (k < n) {
         s[k] = k + 1;
         k += 1;
      }
      * p = 0;
      new_perms_aux(* q, 0, NULL, n, s, p);
   }
   return;

}

void
delete_perms (qlist_int_chunk_t * q) {
      delete_qlist_int_chunk(q);
      return; }

// perms.c
#ifndef PERMS_H
#define PERMS_H
#include <daejana.h>
#include <qlist_int_chunk.h>

#ifndef PERMS_C
#endif

void new_perms (int_t, qlist_int_chunk_t *, int_t *);
void delete_perms (qlist_int_chunk_t *);

#endif
// perms.h
% cds
~/devel/sleek
% pp perms_m.c
#include <chars.h>
#include <perms.h>


#define S_ITEMS "n_items"
#define N_PAD 8192
char s_pad [N_PAD];

static qlist_int_chunk_t q;
static qlist_int_chunk_node_t p;


int
main (int argc, char * argv [])
{
   int_t n_items; int_t k; char * s; char c;
   int_t * v;

   error_flag = false;
   printf("\n");
   if (argc < 2) {
      snprintf(s_pad, N_PAD, "%s : %s\x08", S_ITEMS, s_ellipsis); fputs(s_pad, stdout); fflush(stdout);
      while ((c = getchar()) == ' ' || c == '\t' || c == '\n') { if (c == '\n') { n_items = 0; fputs("\x1b[1A", stdout); goto L1; } }
      k = 0; while (!( c == '\n')) { s_pad[k] = c; c = getchar(); k += 1; } s_pad[k] = '\0';
      n_items = atoll(s_pad);
      fputs("\x1b[1A", stdout);
   }
   else {
      s = argv[1];
      k = 0; while ((c = s[k]) == ' ' || c == '\t') { k += 1; }
      if ('0' < c && c < '9' + 1) {
         n_items = atoll(&s[k]);
      }
      else if (c == '0') {
         if (s[k+1] == 'x' || s[k+1] == 'X') { n_items = strtoll(&s[k], NULL, 16); } else { n_items = 0; if (!( c == '\0' || c == ' ' || c ==
   ↪ '\t')) { ouch(); } }
      }
      else {
         n_items = 0; ouch();
      }
   }
L1:
   if (n_items == 0) { n_items = 4; }
   printf("%s %s %lld\n", S_ITEMS, s_left, n_items);
   printf("\n");

   printf("(\n");
   new_perms(n_items, &q, &k);
   if (!( q == NULL)) {
      while (!( ( p = qlist_int_chunk_to_first(q)) == NULL)) {
         v = qlist_int_chunk_access(p);
         printf("   [");
         k = 0;
         while (k < n_items) {
            printf(" %lld,", v[k]);
            k += 1;
         }
         printf(" ];\n");
         qlist_int_chunk_dequeue(q);
      }
      delete_perms(& q);
   }
   printf(")\n");

   printf("\n");
   if (error_flag) { exit(EXIT_FAILURE); }

   return EXIT_SUCCESS;

}

// perms_m.c
% cmk perms_m chars qlist_int_chunk perms
% ./perms_m 1

n_items ← 1

(
   [ 1, ];
)

% ./perms_m 2

n_items ← 2

(
   [ 1, 2, ];
   [ 2, 1, ];
)

% ./perms_m

n_items ← 3

(
   [ 1, 2, 3, ];
   [ 1, 3, 2, ];
   [ 2, 1, 3, ];
   [ 2, 3, 1, ];
   [ 3, 1, 2, ];
   [ 3, 2, 1, ];
)

% make clean
% pp perms_m.rkt
#lang racket/base

(require aej/daejana aej/qlist)

(define (perms n)
   (let (
         (q (make-qlist))
      )

      (define (aux s t)
         (let (
               (t-l (vector-length t))
            )
            (if… (< t-l 1) (then
               (ql-enqueue q s)
            )
            (else
               (let (
                     (s-l (vector-length s))
                  )
                  (let (
                        (a (make-vector (+ s-l 1)))
                        (b (make-vector (- t-l 1)))
                     )
                     (let loop ((k 0)) (if… (< k s-l) (then (vector-set! a k (vector-ref s k)) (loop (+ k 1)))))
                     (let loop (
                           (l 0)
                        )
                        (if… (< l t-l) (then
                           (let (
                                 (k (vector-ref t l))
                              )
                              (vector-set! a s-l k)
                              (let loop (
                                    (ll 0)
                                    (j 0)
                                 )
                                 (if… (< ll t-l) (then
                                    (let (
                                          (x (vector-ref t ll))
                                       )
                                       (if… (eqv? k x) (then
                                          (loop (+ ll 1) j)
                                       )
                                       (else
                                          (vector-set! b j x)
                                          (loop (+ ll 1) (+ j 1))
                                       ))
                                    )
                                 ))
                              )
                           )
                           (aux a b)
                           (loop (+ l 1))
                        ))
                     )
                  )
               )
            ))
         )
      )

      (let (
            (b (make-vector n))
         )
         (let loop ((k 0)) (if… (< k n) (then (vector-set! b k (+ k 1)) (loop (+ k 1)))))
         (aux '#() b)
         q
      )
   )
)

((lambda (n)
      (newline)
      (let (
            (q (perms n))
         )
         (display "(") (newline)
         (let loop (
            )
            (if… (not (ql-empty? q)) (then
               (display "   [")
               (let (
                     (a (ql-dequeue q))
                  )
                  (let loop (
                        (k 0)
                     )
                     (if… (< k (vector-length a)) (then
                        (display " ") (display (vector-ref a k)) (display ";")
                        (loop (+ k 1))
                     ))
                  )
               )
               (display " ];") (newline)
               (loop)
            ))
         )
         (display ")") (newline)
      )
      (newline)
      (exit exit-state)
   ) (let (
            (v (current-command-line-arguments))
         )
         (let (
               (n (if… (< 0 (vector-length v)) (then
                     (or (string->number (vector-ref v 0)) 0)
                  )
                  (else
                     0
                  ))
               )
            )
            (if… (< n 1) (then
               (ouch!)
            ))
            n
         )
      )
)

;* perms_m.rkt
% racket perms_m.rkt 3

(
   [ 1; 2; 3; ];
   [ 1; 3; 2; ];
   [ 2; 1; 3; ];
   [ 2; 3; 1; ];
   [ 3; 1; 2; ];
   [ 3; 2; 1; ];
)

% pp perms_m.ml
#mod_use "aej/daejana.ml" ;; open Daejana

let perms n =
   let rec aux q r b =
      if Array.length b < 1 then
         Queue.add r q
      else
(*
         for l = 0 to Array.length b - 1 do (
            let a = Array.append r (Array.make 1 b.(l))
            and t = Array.make (Array.length b - 1) 0 in
               for k = 0 to l - 1 do t.(k) <- b.(k) done ;
               if l < Array.length b - 1 then
                  for k = l to Array.length b - 2 do t.(k) <- b.(k + 1) done
               ;
               aux q a t
         ) done
*)
         for l = 0 to Array.length b - 1 do
            let a = Array.append r (Array.make 1 b.(l)) in
               aux q a (
                  if l < 1 then
                     Array.sub b 1 (Array.length b - 1)
                  else if l < Array.length b - 1 then
                     Array.append (Array.sub b 0 l) (Array.sub b (l + 1) (Array.length b - 1 - l))
                  else
                     Array.sub b 0 (Array.length b - 1)
               )
         done
   in
      let q = Queue.create ()
      and a = Array.make 0 0
      and b = Array.init n (fun k -> k + 1) in (
         aux q a b ;
         q
      )

let _ =
   print_newline () ;
   let n = if 1 < Array.length Sys.argv then int_of_string Sys.argv.(1) else 0 in (
      print_string "(" ; print_newline () ;
      if 0 < n then
         let q = perms n in
            Queue.iter (fun a ->
               print_string "   [" ;
               Array.iter (fun t -> print_string " " ; print_int t ; print_string "," ) a ;
               print_string " ];" ; print_newline () ;
            ) q
   ) ;
   print_string ")" ; print_newline () ;
   print_newline () ;
   ignore ()

(* perms_m.ml *)
% ocaml perms_m.ml 4

(
   [ 1, 2, 3, 4, ];
   [ 1, 2, 4, 3, ];
   [ 1, 3, 2, 4, ];
   [ 1, 3, 4, 2, ];
   [ 1, 4, 2, 3, ];
   [ 1, 4, 3, 2, ];
   [ 2, 1, 3, 4, ];
   [ 2, 1, 4, 3, ];
   [ 2, 3, 1, 4, ];
   [ 2, 3, 4, 1, ];
   [ 2, 4, 1, 3, ];
   [ 2, 4, 3, 1, ];
   [ 3, 1, 2, 4, ];
   [ 3, 1, 4, 2, ];
   [ 3, 2, 1, 4, ];
   [ 3, 2, 4, 1, ];
   [ 3, 4, 1, 2, ];
   [ 3, 4, 2, 1, ];
   [ 4, 1, 2, 3, ];
   [ 4, 1, 3, 2, ];
   [ 4, 2, 1, 3, ];
   [ 4, 2, 3, 1, ];
   [ 4, 3, 1, 2, ];
   [ 4, 3, 2, 1, ];
)

%