This example finds all "letter" structures.
letter a = LMLMMM
letter b = LMMMMM
letter c = MMLMMM
letter d = MMMMMM
Symbol L = live = prime candidate number Symbol M = multiple = composite number
The code can be found on github. https://github.com/cerebrummi/letterfa
It implements "letter analysis" of the prime and gap structure from my paper: https://zenodo.org/records/16829092
CODE
package common;
import java.text.Collator;
import java.util.ArrayList;
import java.util.Comparator;
import java.util.HashMap;
import java.util.Locale;
import enums.Letter;
public class StartLetterFa
{
/**
* max number of steps = 18
* otherwise the length of a string is exceeded
*/
private final static int NUMBER_OF_STEPS = 17;
private static HashMap<String, Integer> counter = new HashMap<>();
public static void main(String[] args)
{
LetterFA letterFA = new LetterFA();
for (int i = letterFA.getWalksetBn(); i < NUMBER_OF_STEPS; i++)
{
letterFA.step();
counter.put(letterFA.getPatternSize() + "_" + (i + 1) + "_a",
letterFA.getCounterA());
counter.put(letterFA.getPatternSize() + "_" + (i + 1) + "_b",
letterFA.getCounterB());
counter.put(letterFA.getPatternSize() + "_" + (i + 1) + "_c",
letterFA.getCounterC());
counter.put(letterFA.getPatternSize() + "_" + (i + 1) + "_d",
letterFA.getCounterD());
}
ArrayList<String> keys = new ArrayList<>(counter.keySet());
handleCounter(keys);
}
public static void handleCounter(ArrayList<String> keys)
{
keys.sort(new Comparator<String>()
{
@Override
public int compare(String o1, String o2)
{
if (o1.split("_")[0].compareTo(o2.split("_")[0]) != 0)
{
int o1Int = Integer.parseInt(o1.split("_")[0]);
int o2Int = Integer.parseInt(o2.split("_")[0]);
return Integer.compare(o1Int, o2Int);
}
if (o1.split("_")[1].compareTo(o2.split("_")[1]) != 0)
{
int o1Int = Integer.parseInt(o1.split("_")[1]);
int o2Int = Integer.parseInt(o2.split("_")[1]);
return Integer.compare(o1Int, o2Int);
}
Collator coll = Collator.getInstance(Locale.GERMAN);
coll.setStrength(Collator.PRIMARY);
return coll.compare(o1.split("_")[2], o2.split("_")[2]);
}
});
int a = 0, b = 0, c = 0, d = 0;
double total = 0;
for (String key : keys)
{
if (Letter.a.name().compareTo(key.split("_")[2]) == 0)
{
a = counter.get(key);
}
else if (Letter.b.name().compareTo(key.split("_")[2]) == 0)
{
b = counter.get(key);
}
else if (Letter.c.name().compareTo(key.split("_")[2]) == 0)
{
c = counter.get(key);
}
else if (Letter.d.name().compareTo(key.split("_")[2]) == 0)
{
d = counter.get(key);
total = a + b + c + d;
}
else
{
System.err.println("wrong letter");
System.exit(1);
}
System.out.println(
key.split("_")[2] + " = " + counter.get(key) + " size = " + key);
if (Letter.d.name().compareTo(key.split("_")[2]) == 0)
{
System.out.println("total = " + total);
System.out.println("a = " + (a/total));
System.out.println("b = " + (b/total));
System.out.println("c = " + (c/total));
System.out.println("d = " + (d/total));
System.out.println("--------------------");
}
}
}
}
AND
package common;
import enums.Letter;
/** A fractal algorithm shows prime number patterning.
*
* @author heeren Heeren, B. (2025). A fractal algorithm shows prime number
* patterning. Zenodo. https://doi.org/10.5281/zenodo.16829092
*/
public class LetterFA
{
/**
* 4 is the step where letter a has formed.
*/
private int walksetBn = 4;
private String walksetBPn = "M";
private int offset = 0;
StringBuilder walksetCPn = new StringBuilder(Letter.a.pattern);
private int counterA;
private int counterB;
private int counterC;
private int counterD;
public void step()
{
walksetBn++;
walksetBPn = String.valueOf(walksetCPn.charAt(0));
fractalProcessMove();
if ("L".equalsIgnoreCase(walksetBPn.toString()))
{
fractalProcessCopy();
fractalProcessChange();
}
counterA = 0;
counterB = 0;
counterC = 0;
counterD = 0;
String copyCPn = walksetCPn.toString();
String head = copyCPn.substring(0, offset);
int start = offset;
int end = offset + 6;
for (; end < copyCPn.length();)
{
String letter = copyCPn.substring(start, end);
start += 6;
end += 6;
matchLetter(letter);
}
matchLetter(copyCPn.substring(start) + head);
}
public void matchLetter(String letter)
{
if (Letter.a.pattern.equals(letter))
{
counterA++;
}
else if (Letter.b.pattern.equals(letter))
{
counterB++;
}
else if (Letter.c.pattern.equals(letter))
{
counterC++;
}
else if (Letter.d.pattern.equals(letter))
{
counterD++;
}
else
{
System.err.println("invalid letter " + letter + " n = " + walksetBn);
System.exit(1);
}
}
private void fractalProcessChange()
{
int index = walksetBn + 1;
for (int i = 0; i < walksetCPn.length(); i++)
{
if ((index % walksetBn) == 0)
{
walksetCPn.replace(i, i + 1, "M");
}
index++;
}
}
private void fractalProcessCopy()
{
String copy = walksetCPn.toString();
for (int i = 1; i < walksetBn; i++)
{
walksetCPn.append(copy);
}
}
private void fractalProcessMove()
{
String firstSymbol = walksetCPn.substring(0, 1);
walksetCPn.append(firstSymbol);
walksetCPn.deleteCharAt(0);
offset--;
if (offset < 0)
{
offset = 5;
}
}
public int getCounterA()
{
return counterA;
}
public int getCounterB()
{
return counterB;
}
public int getCounterC()
{
return counterC;
}
public int getCounterD()
{
return counterD;
}
public int getWalksetBn()
{
return walksetBn;
}
public Integer getPatternSize()
{
return walksetCPn.length();
}
}
AND
package enums;
public enum Letter
{
a("LMLMMM"),
b("LMMMMM"),
c("MMLMMM"),
d("MMMMMM");
public final String pattern;
Letter(String pattern)
{
this.pattern = pattern;
}
}
1 Answer 1
Starting from the assumption that the program will use four symbols a, b, c, d referring to the Letter
enum and that those can be so considered an invariant object some simplifications can be used in the program. In the StartLetterFa
there are the lines below:
counter.put(letterFA.getPatternSize() + "_" + (i + 1) + "_a", letterFA.getCounterA());
counter.put(letterFA.getPatternSize() + "_" + (i + 1) + "_b", letterFA.getCounterB());
counter.put(letterFA.getPatternSize() + "_" + (i + 1) + "_c", letterFA.getCounterC());
counter.put(letterFA.getPatternSize() + "_" + (i + 1) + "_d", letterFA.getCounterD());
There is a repetition that can be avoided using the fact that a,b,c,d characters are consecutive and and the distance between two consecutive characters is 1, so the four lines can be reduced to one in a loop like below:
char[] chars = "abcd".toCharArray();
String template = "%d_%d_%c";
for (int j = 0; j < 4; ++j) {
counter.put(String.format(template, letterFA.getPatternSize(), i + 1, chars[j]),
letterFA.getCounter(chars[j]));
}
In this case it has been defined a new method letterFA.getCounter(char c)
taking a char returning the appropriate counter.
Some simplification can be applied to the following lines:
if (o1.split("_")[0].compareTo(o2.split("_")[0]) != 0) {
int o1Int = Integer.parseInt(o1.split("_")[0]);
int o2Int = Integer.parseInt(o2.split("_")[0]);
return Integer.compare(o1Int, o2Int);
}
Using some new variables it is possible avoid repetitions:
String[] arr1 = o1.split("_");
String[] arr2 = o2.split("_");
if (!arr1[0].equals(arr2[0])) {
return Integer.compare(Integer.parseInt(arr1[0]), Integer.parseInt(arr2[0]));
}
Using the same criteria the StartLetterFa
can be updated in this way:
public class StartLetterFa {
/**
* max number of steps = 18 otherwise the length of a string is exceeded
*/
private final static int NUMBER_OF_STEPS = 17;
private final static Map<String, Integer> counter = new HashMap<>();
public static void main(String[] args) {
LetterFA letterFA = new LetterFA();
char[] chars = "abcd".toCharArray();
String template = "%d_%d_%c";
for (int i = letterFA.getWalksetBn(); i < NUMBER_OF_STEPS; i++) {
letterFA.step();
for (int j = 0; j < 4; ++j) {
counter.put(String.format(template, letterFA.getPatternSize(), i + 1, chars[j]),
letterFA.getCounter(chars[j]));
}
}
List<String> keys = new ArrayList<>(counter.keySet());
handleCounter(keys);
}
public static void handleCounter(List<String> keys) {
keys.sort(new Comparator<String>() {
@Override
public int compare(String o1, String o2) {
String[] arr1 = o1.split("_");
String[] arr2 = o2.split("_");
if (!arr1[0].equals(arr2[0])) {
return Integer.compare(Integer.parseInt(arr1[0]), Integer.parseInt(arr2[0]));
}
if (!arr1[1].equals(arr2[1])) {
return Integer.compare(Integer.parseInt(arr1[1]), Integer.parseInt(arr2[1]));
}
Collator coll = Collator.getInstance(Locale.GERMAN);
coll.setStrength(Collator.PRIMARY);
return coll.compare(arr1[2], arr2[2]);
}
});
int a = 0, b = 0, c = 0, d = 0;
double total = 0;
for (String key : keys) {
String s = key.split("_")[2];
int count = counter.get(key);
if (s.equals(Letter.a.name())) {
a = count;
} else if (s.equals(Letter.b.name())) {
b = count;
} else if (s.equals(Letter.c.name())) {
c = count;
} else if (s.equals(Letter.d.name())) {
d = count;
total = a + b + c + d;
} else {
System.err.println("wrong letter");
System.exit(1);
}
System.out.println(s + " = " + count + " size = " + key);
if (s.equals(Letter.d.name())) {
System.out.println("total = " + total);
System.out.println("a = " + (a / total));
System.out.println("b = " + (b / total));
System.out.println("c = " + (c / total));
System.out.println("d = " + (d / total));
System.out.println("--------------------");
}
}
}
}
Note: instead of using HashMap
or ArrayList
on the left of an assignment usually it is better to use an interface or superclass to avoid future corrections in the code.
In the LetterFA
class there is an use of string
variables of one char , better to use the char
type instead, so for example private String walksetBPn = "M";
can be declared as private char walksetBPn = 'M';
with consequent substitutions in the code. Code like below:
int end = offset + 6;
for (; end < copyCPn.length();) {
String letter = copyCPn.substring(start, end);
start += 6;
end += 6;
matchLetter(letter);
}
It can be rewritten declaring variables in the scope of the for:
for (int end = offset + 6; end < copyCPn.length(); end += 6) {
String letter = copyCPn.substring(start, end);
start += 6;
matchLetter(letter);
}
The LetterFA
class can be rewritten in this way:
public class LetterFA {
/**
* 4 is the step where letter a has formed.
*/
private int walksetBn = 4;
private char walksetBPn = 'M';
private int offset = 0;
StringBuilder walksetCPn = new StringBuilder(Letter.a.pattern);
int[] counter = {0, 0, 0, 0};
public void step() {
walksetBn++;
walksetBPn = walksetCPn.charAt(0);
fractalProcessMove();
if (walksetBPn == 'L' || walksetBPn == 'l') {
fractalProcessCopy();
fractalProcessChange();
}
for (int i = 0; i < 4; ++i) {
counter[i] = 0;
}
String copyCPn = walksetCPn.toString();
String head = copyCPn.substring(0, offset);
int start = offset;
for (int end = offset + 6; end < copyCPn.length(); end += 6) {
String letter = copyCPn.substring(start, end);
start += 6;
matchLetter(letter);
}
matchLetter(copyCPn.substring(start) + head);
}
public void matchLetter(String letter) {
if (Letter.a.pattern.equals(letter)) {
++counter[0];
} else if (Letter.b.pattern.equals(letter)) {
++counter[1];
} else if (Letter.c.pattern.equals(letter)) {
++counter[2];
} else if (Letter.d.pattern.equals(letter)) {
++counter[3];
} else {
System.err.println("invalid letter " + letter + " n = " + walksetBn);
System.exit(1);
}
}
private void fractalProcessChange() {
for (int index = walksetBn + 1, i = 0; i < walksetCPn.length(); i++, index++) {
if ((index % walksetBn) == 0) {
walksetCPn.replace(i, i + 1, "M");
}
}
}
private void fractalProcessCopy() {
String copy = walksetCPn.toString();
for (int i = 1; i < walksetBn; i++) {
walksetCPn.append(copy);
}
}
private void fractalProcessMove() {
walksetCPn.append(walksetCPn.charAt(0));
walksetCPn.deleteCharAt(0);
if (--offset < 0) {
offset = 5;
}
}
public int getCounter(char c) {
return counter[c - 'a'];
}
public int getWalksetBn() {
return walksetBn;
}
public int getPatternSize() {
return walksetCPn.length();
}
}
-
1\$\begingroup\$ Thank you for your review. I want to keep it easy reading, therefore I will not implement this. I looked at it in detail. Thank you again. \$\endgroup\$dragoness– dragoness2025年08月30日 02:10:19 +00:00Commented Aug 30 at 2:10
-
\$\begingroup\$ @dragoness It's okay and glad to have helped. \$\endgroup\$dariosicily– dariosicily2025年08月30日 09:29:16 +00:00Commented Aug 30 at 9:29