Combinatorics mathematicians here, a challenging problem I wasn't able to find an answer to.

Ok, via coding, I found that one of my math-related link is where orders actually matters. And I would like to know the case for this when order does not matter.

Here’s the problem at hand.
You have this string - “chincherinchee”
You must select 5 chars from it.
How many possible ways you can select chars without order mattering?
The answer is 31.

Know: “chincherinchee” has 6 letters. “chiner” is all the letters. So, last index possible is 5.

And with code, I was able to confirm that the answer is 31:

Point 30 is the 31th pixel.

But, I do not know how to solve this problem and I googled everywhere for this.

And here’s the printed result of indexes instead of chars (the letter r is the last index):

0,0,0,1,1
0,0,0,1,2
0,0,0,1,3
0,0,0,1,4
0,0,0,1,5
0,0,1,1,1
0,0,1,1,2
0,0,1,1,3
0,0,1,1,4
0,0,1,1,5
0,1,1,1,2
0,1,1,1,3
0,1,1,1,4
0,1,1,1,5
1,1,1,2,2
1,1,1,2,3
1,1,1,2,4
1,1,1,2,5
1,1,2,2,3
1,1,2,2,4
1,1,2,2,5
1,2,2,3,3
1,2,2,3,4
1,2,2,3,5
2,2,3,3,4
2,2,3,3,5
2,3,3,4,4
2,3,3,4,5
3,3,4,4,4
3,3,4,4,5
3,4,4,4,5

EDIT: My assumption may be wrong as well.

I tested with “000111222333” string, and I can select 4. Yet, 0,1,2,3 is not found within my code.

You can’t express this value from just the length of the source and the length of the target, if this is what you are after, because for instance cehinrrrrrrrrrrr contains the same letters but will yield fewer distinct combinations. In other words the answer depends on the count of each letter.

1 Like

If you select 5 characters, these could also be cccee. So, at first you must select 5 characters out of 14 (c1 c2 c3 h1 h2 h3 i1 i2 n1 n2 e1 e2 e3 r) this is 14! / 5!(14- 5)!.
I think then you have to divide this by permutations of the characters, 3! for c,h,e and 2! for n 1! for r.
In total:
14! / 5!(14- 5)!3!3!3!2!1!

87178291200 / (120 * 362880 * 6 * 6 * 6 * 2 * 1) = 556.

But I’m not quite sure - these lessons are a long time gone…

I did try some Python(*):

#! /usr/bin/python3

from collections import Counter

outputLen=5
chars=list(Counter(sorted("chincherinchee")).items());


def generate(stringSoFar,charsSoFar):
    remain=outputLen-len(stringSoFar) # Normally always >0
    char,count=charsSoFar[0]
    
    if len(charsSoFar)>1:  # Not last character
        for i in range(min(count,remain)+1):
            s=stringSoFar+char*i
            if len(s)==outputLen:
                yield s
                break
            for combo in generate(s,charsSoFar[1:]):
                yield combo
    elif count>=remain: # last char, only one possible solution
        yield stringSoFar+char*remain

rawCombos=0    # Count ho wmany we generate
nodupes=set() # For de-duplication
for combo in generate("",chars):
    rawCombos+=1
    nodupes.add(combo)
    print(combo)

print(rawCombos,len(nodupes)) # If equal we can hope that there are no dupes

And it finds 138 combinations (run the code to see which)

Mathematically, you have 4 ways to add C,E,H (0,1,2,3), 3 to add I,N (0,1,2) and 2 to add R (0,1), so `44433*2=1152 combinations (but these have all possible lengths, and the fixed final length constrains the possibilities further)

(*) Warning, code uses recursive generators, done by trained professionals, do not try to replicate at home!

2 Likes

Thanks, this confirms my suspicion that I was operating on a wrong assumption. I was able to generate all of the combinations I want. See this picture:

Yes, that is 138x1x1x5 image.

This is my G’MIC Code:

#@cli rep_rde_combinations: selected_count,item_0_count>=1,item_1_count>=1...,_axis={x,y,z}
#@cli : Generates all possible combinations of repeated distinct elements of different counts, and the total number of elements is equal to the selected_count.
#@cli :
#@cli : Default values: '_axis=x'
+rep_rde_combinations:
check "isint($1,1)"

if isnum($-1)
 items_counts=${2--1}
 axis=0
else
 check "inrange(_'$-1',_'x',_'z',1,1)"
 items_counts=${2--2}
 axis={_'$-1'-_'x'}
fi

check "items_counts=["$items_counts"];
       ( sum( isint(items_counts,1) ) == size(items_counts) ) && ($1 <= sum(items_counts) );"

number_of_possible_combinations=${_rep_rde_selected_comb_count\ $1,$items_counts}

if $number_of_possible_combinations>(1<<24) error exc_combin_size:$number_of_possible_combinations fi

out_dim={v=vector(#3,1);v[$axis]=$number_of_possible_combinations;v}

$out_dim,$1,>"begin(
        items_count=["$items_counts"];
        const number_of_sets_of_items=size(items_count);
        const last_item_pos=number_of_sets_of_items-1;

        result_vector=end_vector=vector(#$1);
        const size_result_vector=size(result_vector);
        const last_result_vector_pos=size_result_vector-1;
        const start_compare_pos=last_result_vector_pos-1;

        inserted_current_element_count=temp_pos=0;
        repeat(size_result_vector,pos,
            result_vector[pos]=temp_pos;
            if(++inserted_current_element_count==items_count[temp_pos],
                ++temp_pos;
                inserted_current_element_count=0;
            );
        );

        pos=last_result_vector_pos;
        temp_pos=last_item_pos;
        inserted_current_element_count=0;
        repeat(size_result_vector,
            end_vector[pos--]=temp_pos;
            if(++inserted_current_element_count==items_count[temp_pos],
                --temp_pos;
                inserted_current_element_count=0;
            );
        );

        --result_vector[last_result_vector_pos];
    );
    if(++result_vector[last_result_vector_pos]==number_of_sets_of_items,
        compare_pos=start_compare_pos;
        do(
            if(result_vector[compare_pos]!=end_vector[compare_pos],break(););
            --compare_pos;
        ,compare_pos>=0);
        selected_item=result_vector[compare_pos]+1;
        inserted_current_element_count=0;
        do(
            result_vector[compare_pos++]=selected_item;
            if(++inserted_current_element_count==items_count[selected_item],
                ++selected_item;
                inserted_current_element_count=0;
            );
        ,compare_pos<size_result_vector);
    );
    result_vector;"
_rep_rde_selected_comb_count:
eval "
 limits=[${2--1}];

 const number_of_letters=size(limits);

 const stick=$1+number_of_letters-1;
 const stone=number_of_letters-1;
 const dec_stick=stick-1;

 count_of_possible_string_combination=perm(stone,stick,0);
 if(count_of_possible_string_combination>(1<<53),run('error_count'););
 subtract_vector=dec_stick-limits;

 repeat(number_of_letters,k,
  count_of_possible_string_combination-=perm(stone,subtract_vector[k],0);
 );

 count_of_possible_string_combination;
 limits=sort(limits);

 duplicates_count=0;
 old_value=nan;
 check_duplicates=1;

 repeat(number_of_letters,k,
  limits[k]==old_value?(
   if(check_duplicates,++duplicates_count;check_duplicates=0;);
  ):(check_duplicates=1;);
  old_value=limits[k];
 );

 count_of_possible_string_combination+duplicates_count;"

EDIT: It appears that the math in the first link is wrong for 4 chars case, but the size of combinations is very close. Hmmm…

This screenshot demonstrate what I’m seeing:

And using the Python code by provided @Ofnuts. The count of generated combinations is the same as the one in the G’MIC code. But, the number of pixels is greater than the count of generated combination. Hence, why you see the nan value pixel.

I think the problem is the Stick and Stone method only works in cases without multiple repetitions. And I haven’t found an answer to the case with multiple repetitions.

Ok, I found this - combinatorics - Combination with repeated elements - Mathematics Stack Exchange

Another person said, I should multiply within brackets, and find the Xn coefficient. That’s going to be, uh, difficult to code.

That’s going to be, uh, difficult to code.

Come on, it’s all multiplications and additions :innocent: The problem is understanding which.

This confirm my hunch that there were additions somewhere though (the prime decomposition of the number of combinations sometimes yields somewhat large primes that aren’t related to the initial data).

Well, I will just cheat and use this code - Multiply two polynomials - GeeksforGeeks .

And I did it!

C:\Users\Reptorian>gmic _rep_rde_selected_comb_count 5,3,3,2,2,3,1
[gmic]./ Start G'MIC interpreter (v.3.4.1).
[gmic]./ Display image [0] = '[unnamed]'.
[0] = '[unnamed]':
  size = (15,1,1,1) [60 b of float32].
  data = (1,6,20,48,90,138,177,192,177,138,90,48,20,6,1).
  min = 1, max = 192, mean = 76.8, std = 71.1228, coords_min = (0,0,0,0), coords_max = (7,0,0,0).

All of these are the correct number of combinations for array size of N!

138 is the correct number, and with a modification to array size in @Ofnuts code, you will find 90, and 177 too!

1 Like