Permutations with repetitions

From Rosetta Code
Revision as of 06:52, 27 March 2015 by Grondilu (talk | contribs) (Undo revision 201070 by Grondilu (talk) nah, not clear, sorry)
Permutations with repetitions is a draft programming task. It is not yet considered ready to be promoted as a complete task, for reasons that should be found in its talk page.

Generate a sequence of permutations of n elements drawn from choice of k values.

This sequence will have elements, unless the program decides to terminate early.

Do not store all the intermediate values of the sequence, rather generate them as required, and pass the intermediate result to a deciding routine for combinations selection and/or early generator termination.

For example: When "cracking" a "combination" lock a sequence is required, but the sequence is terminated once a successful "combination" is found. This case is a good example of where it is not required to store all the intermediate permutations.

See Also:

The number of samples of size k from n objects.

With   combinations and permutations   generation tasks.

Order Unimportant Order Important
Without replacement
Task: Combinations Task: Permutations
With replacement
Task: Combinations with repetitions Task: Permutations with repetitions

ALGOL 68

Works with: ALGOL 68 version Revision 1 - one minor extension to language used - PRAGMA READ, similar to C's #include directive.
Works with: ALGOL 68G version Any - tested with release algol68g-2.6.

File: prelude_permutations_with_repetitions.a68<lang algol68># -*- coding: utf-8 -*- #

MODE PERMELEMLIST = FLEX[0]PERMELEM; MODE PERMELEMLISTYIELD = PROC(PERMELEMLIST)VOID;

PROC perm gen elemlist = (FLEX[]PERMELEMLIST master, PERMELEMLISTYIELD yield)VOID:(

 [LWB master:UPB master]INT counter;
 [LWB master:UPB master]PERMELEM out;
 FOR i FROM LWB counter TO UPB counter DO
   INT c = counter[i] := LWB master[i];
   out[i] := master[i][c]
 OD;
 yield(out);
 WHILE TRUE DO
   INT next i := LWB counter;
   counter[next i] +:= 1;
   FOR i FROM LWB counter TO UPB counter WHILE counter[i]>UPB master[i] DO
     INT c = counter[i] := LWB master[i];
     out[i] := master[i][c];
     next i := i + 1;
     IF next i > UPB counter THEN done FI;
     counter[next i] +:= 1
   OD;
   INT c = counter[next i];
   out[next i] := master[next i][c];
   yield(out)
 OD;
 done: SKIP

);

SKIP</lang>File: test_permutations_with_repetitions.a68<lang algol68>#!/usr/bin/a68g --script #

  1. -*- coding: utf-8 -*- #

MODE PERMELEM = STRING; PR READ "prelude_permutations_with_repetitions.a68" PR;

INT lead actor = 1, co star = 2; PERMELEMLIST actors list = ("Chris Ciaffa", "Keith Urban","Tom Cruise",

                           "Katie Holmes","Mimi Rogers","Nicole Kidman");

FLEX[0]PERMELEMLIST combination := (actors list, actors list, actors list, actors list);

FORMAT partner fmt = $g"; "$; test:(

  1. FOR PERMELEMELEM candidate in # perm gen elemlist(combination #) DO (#,
    1. (PERMELEMLIST candidate)VOID: (
   printf((partner fmt,candidate));
   IF candidate[lead actor] = "Keith Urban" AND candidate[co star]="Nicole Kidman" OR
      candidate[co star] = "Keith Urban" AND candidate[lead actor]="Nicole Kidman" THEN
     print((" => Sunday + Faith as extras", new line)); # children #
     done
   FI;
   print(new line)
  1. OD #));
 done: SKIP

)</lang>Output:

Chris Ciaffa; Chris Ciaffa; Chris Ciaffa; Chris Ciaffa; 
Keith Urban; Chris Ciaffa; Chris Ciaffa; Chris Ciaffa; 
Tom Cruise; Chris Ciaffa; Chris Ciaffa; Chris Ciaffa; 
Katie Holmes; Chris Ciaffa; Chris Ciaffa; Chris Ciaffa; 
Mimi Rogers; Chris Ciaffa; Chris Ciaffa; Chris Ciaffa; 
Nicole Kidman; Chris Ciaffa; Chris Ciaffa; Chris Ciaffa; 
Chris Ciaffa; Keith Urban; Chris Ciaffa; Chris Ciaffa; 
Keith Urban; Keith Urban; Chris Ciaffa; Chris Ciaffa; 
Tom Cruise; Keith Urban; Chris Ciaffa; Chris Ciaffa; 
Katie Holmes; Keith Urban; Chris Ciaffa; Chris Ciaffa; 
Mimi Rogers; Keith Urban; Chris Ciaffa; Chris Ciaffa; 
Nicole Kidman; Keith Urban; Chris Ciaffa; Chris Ciaffa;  => Sunday + Faith as extras

AutoHotkey

Use the function from http://rosettacode.org/wiki/Permutations#Alternate_Version with opt=1 <lang ahk>P(n,k="",opt=0,delim="",str="") { ; generate all n choose k permutations lexicographically ;1..n = range, or delimited list, or string to parse ; to process with a different min index, pass a delimited list, e.g. "0`n1`n2" ;k = length of result ;opt 0 = no repetitions ;opt 1 = with repetitions ;opt 2 = run for 1..k ;opt 3 = run for 1..k with repetitions ;str = string to prepend (used internally) ;returns delimited string, error message, or (if k > n) a blank string i:=0 If !InStr(n,"`n") If n in 2,3,4,5,6,7,8,9 Loop, %n% n := A_Index = 1 ? A_Index : n "`n" A_Index Else Loop, Parse, n, %delim% n := A_Index = 1 ? A_LoopField : n "`n" A_LoopField If (k = "") RegExReplace(n,"`n","",k), k++ If k is not Digit Return "k must be a digit." If opt not in 0,1,2,3 Return "opt invalid." If k = 0 Return str Else Loop, Parse, n, `n If (!InStr(str,A_LoopField) || opt & 1) s .= (!i++ ? (opt & 2 ? str "`n" : "") : "`n" ) . P(n,k-1,opt,delim,str . A_LoopField . delim) Return s }</lang>

Erlang

<lang Erlang>-module(permute). -export([permute/1]).

permute(L) -> permute(L,length(L)). permute([],_) -> [[]]; permute(_,0) -> [[]]; permute(L,I) -> [[X|Y] || X<-L, Y<-permute(L,I-1)].</lang>

D

opApply Version

Translation of: Scala

<lang d>import std.array;

struct PermutationsWithRepetitions(T) {

   const T[] data;
   const int n;
   int opApply(int delegate(ref T[]) dg) {
       int result;
       T[] aux;
       if (n == 1) {
           foreach (el; data) {
               aux = [el];
               result = dg(aux);
               if (result) goto END;
           }
       } else {
           foreach (el; data) {
               foreach (p; PermutationsWithRepetitions(data, n - 1)) {
                   aux = el ~ p;
                   result = dg(aux);
                   if (result) goto END;
               }
           }
       }
       END:
       return result;
   }

}

auto permutationsWithRepetitions(T)(T[] data, in int n) pure nothrow in {

   assert(!data.empty && n > 0);

} body {

   return PermutationsWithRepetitions!T(data, n);

}

void main() {

   import std.stdio, std.array;
   [1, 2, 3].permutationsWithRepetitions(2).array.writeln;

}</lang>

Output:
[[1, 1], [1, 2], [1, 3], [2, 1], [2, 2], [2, 3], [3, 1], [3, 2], [3, 3]]

Generator Range Version

Translation of: Scala

<lang d>import std.stdio, std.array, std.concurrency;

Generator!(T[]) permutationsWithRepetitions(T)(T[] data, in uint n) in {

   assert(!data.empty && n > 0);

} body {

   return new typeof(return)({
       if (n == 1) {
           foreach (el; data)
               yield([el]);
       } else {
           foreach (el; data)
               foreach (perm; permutationsWithRepetitions(data, n - 1))
                   yield(el ~ perm);
       }
   });

}

void main() {

   [1, 2, 3].permutationsWithRepetitions(2).writeln;

}</lang> The output is the same.

Go

<lang go>package main

import "fmt"

var (

   n      = 3
   values = []string{"A", "B", "C", "D"}
   k      = len(values)
   decide = func(p []string) bool {
       return p[0] == "B" && p[1] == "C"
   }

)

func main() {

   pn := make([]int, n)
   p := make([]string, n)
   for {
       // generate permutaton
       for i, x := range pn {
           p[i] = values[x]
       }
       // show progress
       fmt.Println(p)
       // pass to deciding function
       if decide(p) {
           return // terminate early
       }
       // increment permutation number
       for i := 0; ; {
           pn[i]++
           if pn[i] < k {
               break
           }
           pn[i] = 0
           i++
           if i == n {
               return // all permutations generated
           }
       }
   }

}</lang>

Output:
[A A A]
[B A A]
[C A A]
[D A A]
[A B A]
[B B A]
[C B A]
[D B A]
[A C A]
[B C A]

Haskell

<lang haskell>import Control.Monad (replicateM)

main = mapM_ print (replicateM 2 [1,2,3])</lang>

Output:
[1,1]
[1,2]
[1,3]
[2,1]
[2,2]
[2,3]
[3,1]
[3,2]
[3,3]

J

Position in the sequence is an integer from i.n^k, for example:

<lang j> i.3^2 0 1 2 3 4 5 6 7 8</lang>

The sequence itself is expressed using (k#n)#: position, for example:

<lang j> (2#3)#:i.3^2 0 0 0 1 0 2 1 0 1 1 1 2 2 0 2 1 2 2</lang>

Partial sequences belong in a context where they are relevant and the sheer number of such possibilities make it inadvisable to generalize outside of those contexts. But anything that can generate integers will do. For example:

<lang j> (2#3)#:3 4 5 1 0 1 1 1 2</lang>

We might express this as a verb

<lang j>perm=: # #: i.@^~</lang>

with example use:

<lang j> 2 perm 3 0 0 0 1 0 2 1 0 ...</lang>

but the structural requirements of this task (passing intermediate results "when needed") mean that we are not looking for a word that does it all, but are instead looking for components that we can assemble in other contexts. This means that the language primitives are what's needed here.

Java

Works with: Java version 8

<lang java>import java.util.function.Predicate;

public class PermutationsWithRepetitions {

   public static void main(String[] args) {
       char[] chars = {'a', 'b', 'c', 'd'};
       // looking for bba
       permute(chars, 3, i -> i[0] == 1 && i[1] == 1 && i[2] == 0);
   }
   static void permute(char[] a, int k, Predicate<int[]> decider) {
       int n = a.length;
       if (k < 1 || k > n)
           throw new IllegalArgumentException("Illegal number of positions.");
       int[] indexes = new int[n];
       int total = (int) Math.pow(n, k);
       while (total-- > 0) {
           for (int i = 0; i < n - (n - k); i++)
               System.out.print(a[indexes[i]]);
           System.out.println();
           if (decider.test(indexes))
               break;
           for (int i = 0; i < n; i++) {
               if (indexes[i] >= n - 1) {
                   indexes[i] = 0;
               } else {
                   indexes[i]++;
                   break;
               }
           }
       }
   }

}</lang>

Output:

aaa
baa
caa
daa
aba
bba

Mathematica

<lang mathematica>Tuples[{1, 2, 3}, 2]</lang>

Output:
{{1, 1}, {1, 2}, {1, 3}, {2, 1}, {2, 2}, {2, 3}, {3, 1}, {3, 2}, {3, 3}}

Perl

<lang perl>use Algorithm::Combinatorics qw/tuples_with_repetition/; print join(" ", map { "[@$_]" } tuples_with_repetition([qw/A B C/],2)), "\n";</lang>

Output:
[A A] [A B] [A C] [B A] [B B] [B C] [C A] [C B] [C C]

Solving the crack problem: <lang perl>use Algorithm::Combinatorics qw/tuples_with_repetition/; my $iter = tuples_with_repetition([qw/A C K R/], 5); my $tries = 0; while (my $p = $iter->next) {

 $tries++;
 die "Found the combination after $tries tries!\n" if join("",@$p) eq "CRACK";

}</lang>

Output:
Found the combination after 455 tries!

Perl 6

Works with: rakudo version 2013-05-02

List operators such as X are naturally lazy in Perl 6. <lang perl6>my $k = <a b c>; my $n = 2;

.say for [X]($k xx $n).tree;</lang>

Output:
a a
a b
a c
b a
b b
b c
c a
c b
c c

Here is an other approach, counting all possibilities in base :

<lang perl6>my @k = <a b c>; my $n = 2; say @k[.polymod(+@k xx ($n-1))] for ^@k**$n</lang>

Output:
a a
b a
c a
a b
b b
c b
a c
b c
c c

PicoLisp

<lang PicoLisp>(de permrep (N Lst)

  (if (=0 N)
     (cons NIL)
     (mapcan
        '((X)
           (mapcar '((Y) (cons Y X)) Lst) )
        (permrep (dec N) Lst) ) ) )</lang>

Python

<lang python>from itertools import product

  1. check permutations until we find the word 'crack'

for x in product('ACRK', repeat=5):

   w = .join(x)
   print w
   if w.lower() == 'crack': break</lang>

REXX

version 1

<lang rexx>/*REXX program generates all permutations with repeats of N objects.*/ parse arg things bunch inbetweenChars names

     /* inbetweenChars  (optional)   defaults to a  [null].            */
     /*          names  (optional)   defaults to digits (and letters). */

call permRsets things,bunch,inbetweenChars,names exit /*stick a fork in it, we're done.*/ /*──────────────────────────────────.PERMRSET subroutine────────────────*/ .permRset: procedure expose (list); parse arg ? if ?>y then do; _=@.1; do j=2 to y; _=_||between||@.j; end; say _; end

      else do q=1  for x              /*build permutation recursively. */
           @.?=$.q;      call .permRset ?+1
           end    /*q*/

return /*──────────────────────────────────PERMRSETS subroutine────────────────*/ permRsets: procedure; parse arg x,y,between,uSyms /*X things Y at a time*/ @.=; sep= /*X can't be > length(@0abcs). */ @abc = 'abcdefghijklmnopqrstuvwxyz'; @abcU=@abc; upper @abcU @abcS = @abcU || @abc; @0abcS=123456789 || @abcS

 do k=1  for x                        /*build a list of (perm) symbols.*/
 _=p(word(uSyms,k)  p(substr(@0abcS,k,1) k))   /*get|generate a symbol.*/
 if length(_)\==1  then sep='_'       /*if not 1st char, then use sep. */
 $.k=_                                /*append it to the symbol list.  */
 end   /*k*/

if between== then between=sep /*use the appropriate separator. */ list='$. @. between x y' call .permRset 1 return /*──────────────────────────────────P subroutine (Pick one)─────────────*/ p: return word(arg(1),1)</lang> output when using the input of: 3 2

11
12
13
21
22
23
31
32
33

output when using the input of: 3 2 , bat fox cow

bat,bat
bat,fox
bat,cow
fox,bat
fox,fox
fox,cow
cow,bat
cow,fox
cow,cow

version 2 (using Interpret)

Note: this REXX version will cause Regina REXX to fail (crash) if the expression to be INTERPRETed is too large (byte-wise).
PC/REXX and Personal REXX also fail, but for a smaller expression.
Please specify limitations. One could add: If length(a)>implementation_dependent_limit Then
  Say 'too large for this Rexx version'
Also note that the output isn't the same as REXX version 1 when the 1st argument is two digits or more, i.e.:   11   2 <lang rexx>/* REXX ***************************************************************

  • Arguments and output as in REXX version 1 (for the samples shown there)
  • For other elements (such as 11 2), please specify a separator
  • Translating 10, 11, etc. to A, B etc. is left to the reader
  • 12.05.2013 Walter Pachl
  • 12-05-2013 Walter Pachl take care of bunch<=0 and other oddities
                                                                                                                                            • /

Parse Arg things bunch sep names If datatype(things,'W') & datatype(bunch,'W') Then

 Nop

Else

 Call exit 'First two arguments must be integers >0'

If things= Then n=3; Else n=things If bunch= Then m=2; Else m=bunch If things<=0 Then Call exit 'specify a positive number of things' If bunch<=0 Then Call exit 'no permutations with' bunch 'elements!'

Select

 When sep= Then ss='
 When datatype(sep)='NUM' Then ss='copies(' ',sep)'
 Otherwise ss='sep'
 End

Do i=1 To n

 If names<> Then
   Parse Var names e.i names
 Else
   e.i=i
 End

a='p=0;'; Do i=1 To m; a=a||'Do p'i'=1 To n;'; End a=a||'ol=e.p1'

         Do i=2 To m; a=a||'||'ss'||e.p'i; End

a=a||'; say ol; p=p+1;'

         Do i=1 To m; a=a||'end;'; End

a=a||'Say' p 'permutations' /* Say a */ Interpret a</lang>

version 3

This is a very simplistic version that is limited to nine things.
It essentially just executes a DO loop and ignores any permutation out of range,
this is very wasteful of CPU processing time when using larger bunches.
This version isn't ready for prime time. <lang rexx>/*REXX pgm generates all permutations with repeats of N objects (< 10).*/ parse arg things bunch .; z=things**bunch; good=left(1234567890,things) t=0

         do j=copies(1, bunch)  until t==z
         if verify(j,good)\==0  then iterate
         t=t+1
         say j
         end   /*j*/
                                      /*stick a fork in it, we're done.*/</lang>

output when the input is: 3 2

11
12
13
21
22
23
31
32
33

Scala

<lang scala>package permutationsRep

object PermutationsRepTest extends Application {

 /**
  * Calculates all permutations taking n elements of the input List, 
  * with repetitions. 
  * Precondition: input.length > 0 && n > 0
  */
 def permutationsWithRepetitions[T](input : List[T], n : Int) : List[List[T]] = {
   require(input.length > 0 && n > 0)
   n match {
     case 1 => for (el <- input) yield List(el)
     case _ => for (el <- input; perm <- permutationsWithRepetitions(input, n - 1)) yield el :: perm
   }
 }   
 println(permutationsWithRepetitions(List(1, 2, 3), 2))

}</lang>

Output:
List(List(1, 1), List(1, 2), List(1, 3), List(2, 1), List(2, 2), List(2, 3), List(3, 1), List(3, 2), List(3, 3))

Racket

As a sequence

First we define a procedure that defines the sequence of the permutations. <lang Racket>#lang racket (define (permutations-with-repetitions/proc size items)

 (define items-vector (list->vector items))
 (define num (length items))
 (define (pos->element pos)
   (reverse
    (for/list ([p (in-vector pos)])
     (vector-ref items-vector p))))
 (define (next-pos pos) 
   (let ([ret (make-vector size #f)])
     (for/fold ([carry 1]) ((i (in-range size)))
       (let ([tmp (+ (vector-ref pos i) carry)])
         (if (= tmp num)
           (begin 
             (vector-set! ret i 0)
             #;carry 1)
           (begin 
             (vector-set! ret i tmp)
             #;carry 0))))
     ret))
 (define initial-pos (vector->immutable-vector (make-vector size 0)))
 (define last-pos (vector->immutable-vector (make-vector size (sub1 num))))
 (define (continue-after-pos+val? pos val)
   (not (equal? pos last-pos)))
 
 (make-do-sequence (lambda () 
                     (values pos->element
                             next-pos
                             initial-pos
                             #f
                             #f
                             continue-after-pos+val?))))
                             

(sequence->list (permutations-with-repetitions/proc 2 '(1 2 3)))</lang>

Output:
'((1 1) (1 2) (1 3) (2 1) (2 2) (2 3) (3 1) (3 2) (3 3))

As a sequence with for clause support

Now we define a more general version that can be used efficiently in as a for clause. In other uses it falls back to the sequence implementation. <lang Racket>(require (for-syntax racket))

(define-sequence-syntax in-permutations-with-repetitions

 (lambda () #'permutations-with-repetitions/proc) 
 (lambda (stx) 
   (syntax-case stx () 
     [[(element) (_  size/ex items/ex)] 
      #'[(element) 
         (:do-in ([(size) size/ex]
                  [(items) items/ex]
                  [(items-vector) (list->vector items/ex)]
                  [(num) (length items/ex)]
                  [(last-pos) (make-vector size/ex (sub1 (length items/ex)))]) 
                 (void)
                 ([pos (make-vector size 0)]) 
                 #t
                 ([(element) (reverse
                              (for/list ([p (in-vector pos)])
                               (vector-ref items-vector p)))]) 
                 #t
                 (not (equal? pos last-pos)) 
                 [(let ([ret (make-vector size #f)])
                    (for/fold ([carry 1]) ((i (in-range size)))
                      (let ([tmp (+ (vector-ref pos i) carry)])
                        (if (= tmp num)
                          (begin 
                            (vector-set! ret i 0)
                            #;carry 1)
                          (begin 
                            (vector-set! ret i tmp)
                            #;carry 0))))
                    ret)])]])))


(for/list ([element (in-permutations-with-repetitions 2 '(1 2 3))])

 element)

(sequence->list (in-permutations-with-repetitions 2 '(1 2 3)))</lang>

Output:
'((1 1) (1 2) (1 3) (2 1) (2 2) (2 3) (3 1) (3 2) (3 3))
'((1 1) (1 2) (1 3) (2 1) (2 2) (2 3) (3 1) (3 2) (3 3))

Ruby

This is built in (Array#repeated_permutation): <lang ruby>rp = [1,2,3].repeated_permutation(2) # an enumerator (generator) p rp.to_a #=>[[1, 1], [1, 2], [1, 3], [2, 1], [2, 2], [2, 3], [3, 1], [3, 2], [3, 3]]

  1. yield permutations until their sum happens to exceed 4, then quit:

p rp.take_while{|(a, b)| a + b < 5} #=>[[1, 1], [1, 2], [1, 3], [2, 1], [2, 2]]</lang>

Tcl

Version without additional libraries

Works with: Tcl version 8.6
Translation of: Scala

<lang tcl>package require Tcl 8.6

  1. Utility function to make procedures that define generators

proc generator {name arguments body} {

   set body [list try $body on ok {} {return -code break}]
   set lambda [list $arguments "yield \[info coroutine\];$body"]
   proc $name args "tailcall \

coroutine gen_\[incr ::generate_ctr\] apply [list $lambda] {*}\$args" }

  1. How to generate permutations with repetitions

generator permutationsWithRepetitions {input n} {

   if {[llength $input] == 0 || $n < 1} {error "bad arguments"}
   if {![incr n -1]} {

foreach el $input { yield [list $el] }

   } else {

foreach el $input { set g [permutationsWithRepetitions $input $n] while 1 { yield [list $el {*}[$g]] } }

   }

}

  1. Demonstrate usage

set g [permutationsWithRepetitions {1 2 3} 2] while 1 {puts [$g]}</lang>

Alternate version with extra library package

Library: Tcllib (Package: generator)
Works with: Tcl version 8.6

<lang tcl>package require Tcl 8.6 package require generator

  1. How to generate permutations with repetitions

generator define permutationsWithRepetitions {input n} {

   if {[llength $input] == 0 || $n < 1} {error "bad arguments"}
   if {![incr n -1]} {

foreach el $input { generator yield [list $el] }

   } else {

foreach el $input { set g [permutationsWithRepetitions $input $n] while 1 { generator yield [list $el {*}[$g]] } }

   }

}

  1. Demonstrate usage

generator foreach val [permutationsWithRepetitions {1 2 3} 2] {

   puts $val

}</lang>