Primenary Strings

27

1

A Primenary (binary-prime) string is one which, when written as a binary grid, every row and column has a prime total.

That's quite a vague explanation, so let's break it down with a worked example...


For this example we'll use the string bunny:

First, find the ASCII code point of each character and its binary representation:

Char | ASCII | Binary

b      98      1100010
u      117     1110101
n      110     1101110
n      110     1101110
y      121     1111001

Take these binary values, from top to bottom, and arrange them into grid (adding leading zeros if necessary):

1 1 0 0 0 1 0
1 1 1 0 1 0 1
1 1 0 1 1 1 0
1 1 0 1 1 1 0
1 1 1 1 0 0 1

Then, count the number of 1s in each row and column:

1 1 0 0 0 1 0   > 3
1 1 1 0 1 0 1   > 5
1 1 0 1 1 1 0   > 5
1 1 0 1 1 1 0   > 5
1 1 1 1 0 0 1   > 5

v v v v v v v

5 5 2 3 3 3 2

If, and only if, every single total is prime (such as here) then the string is a valid binary-prime.


The Challenge

Your task is to create a function or program which, when given a string, returns/outputs truthy if the string is primenary, and falsy otherwise.

Rules/Details

  • You may assume that the string's characters will always be in the ASCII range 33-126 (inclusive).
  • The string will not be empty.
  • A primenary string does not have to have a prime length - for example, W1n* is valid, despite having 4 characters.
  • This is , so the shortest answer (in bytes) wins - but all submissions are welcome.
  • Standard loopholes are banned.

Test Cases

'husband'     -> True
'HOTJava'     -> True
'COmPaTIBILE' -> True
'AuT0HACk'    -> True

'PPCW'        -> False
'code-golf'   -> False
'C++'         -> False
'/kD'         -> False

'HI'          -> False
'A'           -> False

There is also a working, but incredibly verbose Python example on repl.it that you can test your solution against.

FlipTack

Posted 2016-11-06T12:01:02.580

Reputation: 13 242

Can I ask how you discovered that husband was valid? Or any of them? Great problem, though! – Gabriel Benamy – 2016-11-06T21:55:38.690

3

@GabrielBenamy I'm glad someone asked! I looped through an online dictionary file, trying a few random capitalizations of each letter, sometimes switching letters for numbers, etc. Then I had a look through the outputted list and picked a couple of test cases I liked

– FlipTack – 2016-11-06T22:00:10.920

Every 1-2 character input is guaranteed to return False, correct? – mbomb007 – 2016-11-08T21:21:05.143

... because 0 and 1 are not prime, and every 1-2 char input string containing only chars in the given range is guaranteed to contain at least one 0 or 1 as a vertical sum. You should add some 1 and 2 character strings as test cases. – mbomb007 – 2016-11-08T21:35:06.857

@mbomb007 1 char inputs cannot have prime numbers columnwise, so they will return false. 2 char inputs could, but not in the ASCII range we're using, so for this scenario you're correct. – FlipTack – 2016-11-08T21:36:46.357

All of the test cases only have prime characters, i.e. rows in the bitmatrix, so they don't cover the case where only columns are checked for primality. Add beezz to fix this. There are two non-prime rows, but only prime columns in beezz. – movatica – 2019-06-26T19:31:06.640

What is the intended output for 7/8? – Nitrodon – 2019-06-26T20:07:54.210

Of the answers I was able to test, six accept 7/8 and six reject 7/8. – Nitrodon – 2019-06-26T20:22:36.403

The actual problem with 7/8 is leading zeroes. Should leading columns be ignored, if they are completely zeroed? Or should we always check 7 bits for each character? What about zero columns in the middle? – movatica – 2019-06-26T21:35:06.970

Answers

8

MATL, 10 bytes

BtXsw!shZp

Try it online!

This is the ideal language for the job. It's pretty much a literal transliteration of the challenge specification.

Bt % Converts input to binary matrix, duplicate
Xs  % Sum columns (alternative X version to prevent defaulting to sum along first non-singleton dimension, thanks @Jonathan Allan)
w! % Get the duplicate to the top of the stack, transpose
s  % Sum again
h  % Concatenate horizontally
Zp % Check primality element-wise. Display implicitly.

Since any zero makes a MATL array falsy as per meta, nothing else is needed - basically, an implicit A is called on ? (if).

Sanchises

Posted 2016-11-06T12:01:02.580

Reputation: 8 530

a should be falsy, but returns 1 1? (its columns do not add up to primes) – FlipTack – 2016-11-12T13:02:46.213

I think BtXsw!shZp would fix this and be a winner for 10. – Jonathan Allan – 2016-11-12T23:35:32.557

@Flp.Tck Completely forgot about MATLAB's 'forgiving' behaviour when working with row vectors. I'm sorry, fixed it now. – Sanchises – 2016-11-13T09:02:03.700

Works now :) (might want to update the try it online link tho) – FlipTack – 2016-11-13T09:10:40.483

@Flp.Tkc Done. Thanks for a nice challenge! – Sanchises – 2016-11-13T09:16:29.333

4

Jelly, 13 12 11 bytes

OBUZ;$S€ÆPẠ

TryItOnline! or all test cases

How?

OBUZ;$S€ÆPẠ - Main link: word                  e.g. ha!
O           - cast to ordinals                 e.g. [104,97,33]
 B          - convert to binary                e.g. [[1,1,0,1,0,0,0],[1,1,0,0,0,0,1],[1,0,0,0,0,1]]
  U         - reverse each entry (say "b")     e.g. [[0,0,0,1,0,1,1],[1,0,0,0,0,1,1],[1,0,0,0,0,1]]
     $      - last two links as a monad
   Z        - transpose                        e.g. [[0,1,1],[0,0,0],[0,0,0],[1,0,0],[0,0,0],[1,1,1],[1,1]]
    ;       - concatenate with "b"             e.g. [[0,1,1],[0,0,0],[0,0,0],[1,0,0],[0,0,0],[1,1,1],[1,1],[0,0,0,1,0,1,1],[1,0,0,0,0,1,1],[1,0,0,0,0,1]]
      S€    - sum €ach                         e.g. [2,0,0,1,0,3,2,3,3,2]
        ÆP  - is prime (1 if prime, 0 if not)  e.g. [1,0,0,0,0,1,1,1,1,1]
          Ạ - all truthy?                      e.g. 0

Jonathan Allan

Posted 2016-11-06T12:01:02.580

Reputation: 67 804

3

Mathematica, 75 bytes

And@@Join@@PrimeQ@{+##&@@#,+##&@@@#}&@IntegerDigits[ToCharacterCode@#,2,7]&

Unnamed function taking a string as input and returning True or False.

ToCharacterCode@# converts the input into the list of its ASCII values; IntegerDigits[...,2,7] turns each value into the list of its bits, padded to length 7 if necessary. So now we have a 2D array and we want all its row sums and column sums; lo and behold, the character-spasm {+##&@@#,+##&@@@#}&@... does exactly that (it applies the +##&, "sum all arguments", function to the list of vectors in the first coordinate using @@, and to each vector as its own list of integers in the second coordinate using @@@). Then we just check whether the results are PrimeQ, flatten the list with Join@@, and take the And of all those values.

Greg Martin

Posted 2016-11-06T12:01:02.580

Reputation: 13 940

3

05AB1E, 17 bytes

Çžz+b€¦€SDøìO0ÛpP

Try it online!

Emigna

Posted 2016-11-06T12:01:02.580

Reputation: 50 798

3

Jelly, 15 bytes

O+⁹Bṫ€3µS€;SÆPP

Try it online! or Verify all test cases..

Explanation

O+⁹Bṫ€3µS€;SÆPP  Main link. Input: string z
O                Ordinal, get ASCII value of each char
  ⁹              Nilad representing 256
 +               Add 256 to each ordinal value
   B             Binary digits of each
    ṫ€3          Tail, take each list of digits from the 3rd value to the end
                 These are the last seven digits of each
       µ         Start a new monadic chain
        S€       Sum each list of digits by rows
           S     Sum by column
          ;      Concatenate
            ÆP   Test if each is prime, 1 if true else 0
              P  Product

miles

Posted 2016-11-06T12:01:02.580

Reputation: 15 654

2

Ruby -rprime, 100 bytes

->s{a=s.bytes.map{|b|b.digits 2}
a.all?{|r|r.sum.prime?}&([0]*7).zip(*a).all?{|c|c.count(1).prime?}}

Try it online!

Explanation

->s{
    a=s.bytes                       # Get byte values from string
             .map{|b|b.digits 2}    # For each, map it to its binary digits
                                    #   (least significant digits first)
a.all?{|r|r.sum.prime?}             # Each character has a prime number of 1's?
    &                               # Bit-and (because it saves bytes here)
    ([0]*7).zip(*a)                 # Zip bit array with an all-zero array
                                    #   (If we don't, then uneven array lengths
                                    #   cause some columns to not be returned.)
    .all?{|c|c.count(1).prime?}     # All columns have a prime number of 1's?
                                    #   (We use count instead of sum here because
                                    #   zip pads columns with trailing nils, which
                                    #   can't be added to numbers via sum.)
}

Value Ink

Posted 2016-11-06T12:01:02.580

Reputation: 10 608

1

Python 3, 209 189 180 171 160 bytes

Thanx squid for -9 bytes :)

def p(s):n=s.count('1');return(n>1)*all(n%i for i in range(2,n))
def f(s):t=[f'{ord(c):07b}'for c in s];return all(map(p,t+[[u[j]for u in t]for j in range(7)]))

Try it online!

movatica

Posted 2016-11-06T12:01:02.580

Reputation: 635

I like how you rewrote the test case print statement :) – movatica – 2019-06-26T18:52:49.783

Yeah I'm a smidge obsessive compulsive about f-strings... Also, isn't it equivalent if you remove t+ in the map statement? – Reinstate Monica – 2019-06-26T18:59:46.647

Nope, because the prime check needs to cover both rows and columns in the bit matrix. t has all the rows, while [[t[i][j]..i..]..j..] is the transposed t, i.e. the columns. If there is a shorter way to transpose the matrix, we can save more bytes :) – movatica – 2019-06-26T19:06:02.243

It's working when I try it, do you know of a string that breaks it? – Reinstate Monica – 2019-06-26T19:07:48.017

Yes. beezz should return false, but does not. It's because the prime check is broken, it returns True for 4 bits. Try print(p('1111')). Fixed it now. All the test cases did not cover that, because all of the used characters ar primenary. – movatica – 2019-06-26T19:30:04.653

1

Pyth, 37 bytes

L.AmP_sdb=sMM.[L\0lh.MlZQ=.BMQ&yZy.TZ

Try it online!


                                 Code | Explanation
--------------------------------------+----------------------------------------------------------------
L.AmP_sdb=sMM.[L\0lh.MlZQ=.BMQ&yZy.TZ | Full code
L                                     | Define function y(b):
   m    b                             |   For each d in b:
    P_sd                              |     Is the sum of the elements of the list prime?
 .A                                   |   Return whether all elements of the resulting list are truthy
                         =   Q        | Assign the following to Q:
                          .BMQ        |   The list of binary strings for each character in the input
         =             Z              | Assign the following to Z:
               L             Q        |   For every element in Q:
             .[ \0                    |     Pad with 0 on the left
                  lh.MlZQ             |     To the length of the longest element in Q
            M                         |   For each element in the resulting list:
          sM                          |     Convert each character to an integer
                              &yZ     | Print y(Z) AND
                                 y.TZ |   y( <Transpose of Z> )

hakr14

Posted 2016-11-06T12:01:02.580

Reputation: 1 295

1

Brachylog, 14 bytes

ạḃᵐB↔ᵐz₁,B+ᵐṗᵐ

Try it online!

Outputs through success or failure. (In the case of success, a list of all column and row sums is available through the output variable.

   B              The variable B is
ạ                 the codepoints of the input
 ḃᵐ               converted to lists of binary digits,
    ↔ᵐ            which with each list reversed
      z₁          then zipped without cycling
        ,B        and concatenated with B
          +ᵐ      has elements which all sum to
            ṗᵐ    prime numbers.

Unrelated String

Posted 2016-11-06T12:01:02.580

Reputation: 5 300

1

O5AB1E, 12 bytes

Çžy+bø€SOp¦W

Try it online!

This is my first code golf so go easy :)

Ç              % Converts the implicit input into ascii values
 žy+           % Adds 128 to each value, inspired by Emigna as a way to pad zeros
    b          % Convert all values into bits
     ø         % Transpose
      €SO      % Sum each string of binary digits created
         p¦    % Check if each element is prime and cut the first element out (adding 128 makes it equal to the number of characters)
           W   % Take the minimum value to effectively "and" all the elements

Alex Waese-Perlman

Posted 2016-11-06T12:01:02.580

Reputation: 11

This yield an empty result for a single letter input. I'm not well versed in O5AB1E but if that is a falsey value, it's ok. – Sanchises – 2019-06-26T06:28:16.043

1

K (oK), 40 33 bytes

Solution:

&/{2=+/d=_d:x%!x}'+/'m,+m:(7#2)\'

Try it online!

Explanation:

Half is creating the matrix, the other half is the primality check.

&/{2=+/d=_d:x%!x}'+/'m,+m:(7#2)\' / the solution
                                ' / apply to each (')
                               \  / decode
                          (   )   / do this together
                           7#2    / 7#2 => 2 2 2 2 2 2 2
                        m:        / save as m
                       +          / transpose
                     m,           / append to m
                  +/'             / sum (+/) each (')
                 '                / apply to each
  {             }                 / lambda taking implicit x
              !x                  / range 0..x
            x%                    / x divided by ...
          d:                      / save as d
         _                        / floor
       d=                         / equal to d?
     +/                           / sum (+/)
   2=                             / equal to 2?
&/                                / minimum

streetster

Posted 2016-11-06T12:01:02.580

Reputation: 3 635

1

Python 3, 228 227 225 bytes

Not a great answer, I wasn't able to golf it as much as I would've liked, but I spent so long on it I feel I should post it. Suggestions on cutting bytes would be greatly appreciated.

r=range
n=[format(ord(c),"08b")for c in input()]
n=map(lambda s:s.count("1"),n+["".join([f[1]for f in filter(lambda e:e[0]%8<1,enumerate("X"*-~i+"".join(n)))][1:])for i in r(8)])
print(all(all(s%d for d in r(2,s))for s in n))

Edit 1: replaced e[0]%8==0 with e[0]%8<1, losing a byte. Thanks Flp.Tkc!

Edit 2: replacing (i+1) with -~i, losing two additional bytes. Thanks Erik for exposing how bad my bit-level knowledge is :) While testing this revision, I discovered that kappa is valid... make of that what you will.

FourOhFour

Posted 2016-11-06T12:01:02.580

Reputation: 241

1could you change e[0]%8==0 to e[0]%8<1? – FlipTack – 2016-11-06T17:37:28.273

@Flp.Tkc Good spot! There's no reason why that can't be done. – FourOhFour – 2016-11-06T17:40:22.670

1@Flp.Tkc I don't think I could save bytes by making it a function. I like how you've got 404 rep btw :) – FourOhFour – 2016-11-06T17:45:06.027

It is supposed to be <1, not <0? – Destructible Lemon – 2016-11-06T22:13:01.333

@Destructible Watermelon yep let me correct that. – FourOhFour – 2016-11-07T08:12:12.157

Welcome to PPCG! – Erik the Outgolfer – 2016-11-07T13:17:15.147

BTW, you can golf two by replacing (i+1) with -~i. – Erik the Outgolfer – 2016-11-07T13:25:51.887

@EriktheGolfer wow... code-golf royalty on my submission! Thanks for the suggestion. – FourOhFour – 2016-11-07T16:16:56.213

@FourOhFour You made a typo: "X"*-~1 should be "X"*-~i instead. – Erik the Outgolfer – 2016-11-07T16:23:25.013

I don't think this works. 0 and 1 are not prime numbers. – mbomb007 – 2016-11-08T21:33:24.660

Your program always returns True for strings 1 character long, but should always return False. – mbomb007 – 2016-11-08T21:38:42.180

@mbomb007 yep, it's an issue with my primality checking code. I'll look into fixing it. – FourOhFour – 2016-11-11T18:02:30.963

I just looked in the chat history and found your comment on how this is your favourite question type. You even sparked the creation of a new tag, decision-problem! I'll make sure to post more like this in the future :) – FlipTack – 2016-11-19T13:19:29.853

@Flp.Tkc yep, I love this stuff. This was a great challenge so I look forward to your next ones! – FourOhFour – 2016-11-19T20:09:18.943

@FourOhFour Currently I'm working on this challenge, after that I'll see if I can get some more decision problems going ;)

– FlipTack – 2016-11-19T20:11:32.873

@Flp.Tkc That's a neat challenge idea! I've got a few ideas for a second challenge myself but none are fully formulated. – FourOhFour – 2016-11-19T20:17:26.320

1

Perl, 151 121 111 + 3 = 114 bytes

Run with -lF. The program will only function correctly for the first input. Terminate the program and rerun for your next input.

Thanks to @Dada for letting me know the // after F were redundant. An additional byte can be removed (for 112) by piping the input in via echo -n, but I feel that that's technically adding more code, so YMMV.

for$c(@a=map{sprintf"%07b",ord}@F){$b[$_].=substr$c,$_,1 for 0..6}s/0//g,$d|=/^1?$|^(11+?)\1+$/ for@a,@b;say!$d

Readable:

                                     #Implicitly split input into characters in @F array
for$c(@a=map{sprintf"%07b",ord}@F)  #Convert @F to 7-bit binary as @a, then loop through it                        
    $b[$_].=substr$c,$_,1 for 0..6   #Transpose @a's bits into @b
}
s/0//g,$d|=/^1?$|^(11+?)\1+$/ for@a,@b; #Remove any zeros, then run through composite regex
say!$d                          #If all composite regex checks fail, then it's fully prime.

Gabriel Benamy

Posted 2016-11-06T12:01:02.580

Reputation: 2 827

1A version that only works on the first input is perfectly fine, so you can put the 141 bytes version as the main one, and suggest the other one to use on multiple inputs. – Dada – 2016-11-06T21:33:32.583

Also note that you can omit the // after -F, and you can take the input without final newline (with echo -n) to get rid of -l flag. – Dada – 2016-11-06T21:36:00.760

1

Groovy, 151 137 bytes

{p={x->x<3||(2..(x**0.5)).every{x%it}};y={it.every{p(it.count("1"))}};x=it.collect{0.toString((int)it,2) as List};y(x)&&y(x.transpose())}

No primality check in groovy...

p={x->x<3||(2..(x**0.5)).every{x%it}}; - Closure for primality testing.

y={it.every{p(it.count("1"))}}; - Closure to ensure that all counts of "1" for a passed binary 2D array are prime.

x=it.collect{0.toString((int)it,2) as List}; - Coversion from string to binary array.

y(x)&&y(x.transpose()) - For all prime-validated sums in the main matrix and the transposed matrix, ensure that they return true.

Magic Octopus Urn

Posted 2016-11-06T12:01:02.580

Reputation: 19 422

0

JavaScript (Node.js), 149 146 ... 134 130 129 bytes

x=>[...x].map(y=>a=[...a.map(n=>y.charCodeAt()&2**i++?++z&&-~n:n,z=i=0),z],a=[...Array(7)])&&!a.some(n=>(P=r=>n%--r?P(r):~-r)(n))

Try it online!

Explanation

x=>                        // Main function:
 [...x].map(               //  For each y in x:
  y=>
   a=[...a.map(            //   For each i in range(0, len(a)):
    n=>                   
     y.charCodeAt()&2**i++ //    If y AND 2**i is not zero:
     ?++z&&-~n:n,          //     z = z + 1; a[i] = a[i] + 1 (1 if a[i] is undefined)
    z=i=0                  //   Initially z = 0
   ),z],                   //   Then push z at the end of a
  a=[...Array(7)]          //  Initially a = [undefined] * 7
 )&&!a.some(               //  Then for each n in a:
  n=>(
   P=r=>                   //   Composite function:
    n%--r?                 //    If n % (r - 1) == 0 or r == 1:
     P(r)                  //     Return P(r - 1)
    :~-r                   //    Else: Return r - 2
  )(n)                     //   Starting from r = n
 )                         //  Return whether the composite function returns 0 for all n.

How does it even work!?

  • y.charCodeAt()&2**i
    • We need this code to return the corresponding bit of y.charCodeAt() if 0 <= i < 7, and 0 otherwise.
    • When i < 7, the code apparently works as usual.
    • When 7 <= i <= 32, since the corresponding bit of y.charCodeAt() is 0 anyway, the result is 0 as expected.
    • When 32 < i < 1024, since int32(2**i) == 0, the result is 0 as expected.
    • When 1024 <= i, we have 2**i == Infinity, and since int32(Infinity) == 0, the result is 0 as expected.
  • (P=r=>n%--r?P(r):~-r)(n)
    • For simplicity we let R = --r = r - 1.
    • This helper function terminates when n % R == 0 or n % R is NaN.
      • n % R == 0: R is a factor of n.
        • If R == 1, then n is prime because all 1 < R < n can't divide n. Return 0 (falsy).
        • If R == -1, then n == 0. Return -2 (truthy).
        • Otherwise, return R - 1 where R - 1 > 0 (truthy).
      • n % R is NaN: Invalid modular calculation.
        • If R == 0: n == 1. Return -1 (truthy).
        • If n is NaN: R is NaN. Return -1 (truthy).
    • As a result, only when R == 1 can this function return a falsy value, indicating n is prime.

Shieru Asakoto

Posted 2016-11-06T12:01:02.580

Reputation: 4 445

0

Perl 5 -MList::Util=all,sum -pF, 96 92 bytes

$_=all{//;all{$'%$_}2..$_-1}(map{$_=sprintf'%07b',ord;y/1//}@F),map{sum map{s/.//;$&}@F}0..6

Try it online!

Xcali

Posted 2016-11-06T12:01:02.580

Reputation: 7 671

0

Clojure, 180 bytes

#(let[S(for[i %](for[j[1 2 4 8 16 32 64]](min(bit-and(int i)j)1)))A apply](not-any?(fn[i](or(= i 1)(seq(for[d(range 2 i):when(=(mod i d)0)]d))))(into(for[s S](A + s))(A map + S))))

There might be a shorter way of generating bit lists and also the primality test.

NikoNyrh

Posted 2016-11-06T12:01:02.580

Reputation: 2 361

0

Python 3, 164 bytes

import numpy;a=numpy.array([list(f'{ord(_):07b}')for _ in input()]).astype(int);print(all([(v>1)*all(v%i for i in range(2,v))for v in set(a.sum(0))|set(a.sum(1))]))

Zulfiqaar

Posted 2016-11-06T12:01:02.580

Reputation: 101

0

Ruby 2.7 -rprime, 95 bytes

->s{a=s.bytes.map{[*@1.digits(2),0][..6]}
(a.map(&:sum)+a.transpose.map(&:sum)).all?(&:prime?)}

No TiO link because TiO still runs Ruby 2.5.5.

Explanation

Pretty simple. The first line gets the binary digits of each character as an array padded out to seven digits, which really ought to be easier:

a = s.bytes.map { [*@1.digits(2), 0][..6] }

Check out that numbered block parameter (@1) and beginless range (..6) hotness.

The second line sums the rows and columns and tests if they're all prime:

(a.map(&:sum) + a.transpose.map(&:sum)).all?(&:prime?)

Jordan

Posted 2016-11-06T12:01:02.580

Reputation: 5 001

0

PHP, 173 bytes

for($r=1;$b=substr_count($t[$i]=sprintf('%07b',ord($argv[1][$i++])),1);)$r&=$b==2|$b%2&$b>2;for(;$k++<7;){for($b=$j=0;$t[++$j];$b+=$t[$j][$k-1]);$r&=$b==2|$b%2&$b>2;}echo$r;

Test it online

Crypto

Posted 2016-11-06T12:01:02.580

Reputation: 862

0

JavaScript, 234 bytes

f=z=>(z=[...z].map(v=>v.charCodeAt(0))).map(v=>v.toString(2).replace(/0/g,"").length).every((p=v=>{for(i=2;i<v;i++){if(v%i===0){return 0}};return v>1}))&&[...""+1e6].map((v,i)=>z.reduce((a,e)=>!!(e&Math.pow(2,i))+a,0)).every(v=>p(v))

We get the horizontal values by converting the number to binary, removing the zeros using a string replacement, and then counting the 1s. The vertical sums are obtained by looping 1 to 7 and using a bitwise AND with 2 raised to the nth power.

Grax32

Posted 2016-11-06T12:01:02.580

Reputation: 1 282

Math.pow(2,i) can be shortened to (1<<i) assuming i<32, maybe saving 7 bytes, maybe not though. – Naruyoko – 2019-06-26T00:27:36.267