It implements prime number envelopes (page 3) from my paper: https://zenodo.org/records/16829092
The full working example is on github: https://github.com/cerebrummi/primeenvelopes
- "StartFA" has a main method that shows the sieve that grows prime numbers SFA with FA. [This part is equal to this question https://codereview.stackexchange.com/questions/297904] From my research implementation the pattern develop like this: https://www.youtube.com/watch?v=I0w78ewvum4
Step 2 and 3 are NEW!!!
"StartTree" has a main method that shows how a data structure (tree of leafs with floors) is being build in TFA from SFA with FA.
"StartEnvelopes" has a main method that uses the TFA to generate the prime number envelopes.
CODE
package common;
public class StartFA
{
final static int NUMBER_OF_STEPS = 8;
public static void main(String[] args)
{
SFA sfa = new SFA();
sfa.printWalksets();
for( int i = 0 ; i < NUMBER_OF_STEPS; i++)
{
System.out.println("========== step start ==========");
sfa.step();
sfa.printWalksets();
System.out.println("========== step end ===========");
}
}
}
AND
package common;
public class StartTree
{
final static int NUMBER_OF_STEPS = 12;
public static void main(String[] args)
{
TFA tfa = new TFA();
for (int i = 1; i < NUMBER_OF_STEPS; i++)
{
tfa.step();
}
// tfa.printFloors();
/**
* for NUMBER_OF_STEPS = 17
*
* TFA: patternsize 1
* TFA: patternsize 2
* TFA: patternsize 6
* TFA: patternsize 30
* TFA: patternsize 210
* TFA: patternsize 2310
* TFA: patternsize 30030
* TFA: patternsize 510510
*/
tfa.printPatternSizes();
}
}
AND
package common;
import java.math.BigDecimal;
import io.PrimeReader;
import tree.Floor;
public class StartEnvelopes
{
final static int NUMBER_OF_STEPS = 14;
public static void main(String[] args)
{
PrimeReader reader = new PrimeReader();
String primenumber = reader.readFromData();
//String primenumber = "19387777";
BigDecimal prime = new BigDecimal(primenumber);
TFA tfa = new TFA();
for (int i = 1; i < NUMBER_OF_STEPS; i++)
{
tfa.step();
}
Floor floor = tfa.getLastFloor();
do
{
int patternSize = floor.getPatternSize();
BigDecimal size = new BigDecimal(patternSize);
if (size.compareTo(prime) == 1)
{
floor = floor.getPreviousFloor();
}
else
{
break;
}
} while (floor != null);
System.out.println("StartEnvelope: prime number = " + primenumber);
System.out
.println("StartEnvelope: pattern size = " + floor.getPatternSize());
System.out.println("");
do
{
int a = floor.getPatternSize();
int b = floor.getLeaf(prime).intValue();
System.out.println("Envelope equation f(x) = " + a + "*x + " + b);
floor = floor.getPreviousFloor();
} while (floor != null);
}
}
1 Answer 1
Really interesting design and the diagram helped a lot. A few Java-side tweaks will make the structure cleaner and easier to extend.
Model
Floors
andLeaves
explicitly as value objectsFrom the diagram it’s clear: a
Floor
is a level with a step number and pattern size, and it holdsLeaf
nodes. ALeaf
carries metadata (headNumber, previousHeadNumber, symbol) and links to itsFloor
and maybe a predecessor. That’s a perfect fit for immutable records or at least classes with final fields. Right now the code leans on mutable lists and null checks. Switching to:record Floor(int stepNumber, int patternSize, List<Leaf> leaves) {} record Leaf(Symbol symbol, int headNumber, int previousHeadNumber, Floor floor) {}
would get rid of half the boilerplate and many NPE checks.
Keep navigation one-way
In the diagram,
Leaves
point back to theirFloor
, andFloors
also seem to link back down. Two-way navigation is fragile - serialization and testing get messy. Pick one direction: e.g.Floor
owns its list ofLeafs
, and aLeaf
has a reference to itsFloor
. That’s enough to traverse both ways without circular state.Attach
stepNumber/patternSize
toFloor
, notLeaf
They belong to the whole level. Right now they look duplicated or recalculated in several places. Give each
Floor
itsstepNumber
andpatternSize
once, and let everyLeaf
read them throughleaf.floor().patternSize()
. This reduces drift and makes the invariants explicit.Use enums instead of raw strings for symbols
Instead of storing "L", "M", "P", treat them as an
enum Symbol { L, M, P }
. That makes conditions inSFA.step()
self-explanatory and removes accidental typos.Push printing out of the model
The diagram shows structural relationships. Keep the model classes (
Floor, Leaf
) data-only and overridetoString()
. Let the "starter" classes (StartFA, StartTree, StartEnvelopes
) decide what to print. That separation makes the algorithm testable without console output noise.
-
1\$\begingroup\$ Thank you very much, I edited the image to show that the floors are in an ArrayList, which is necessary. I will edit the code later. \$\endgroup\$dragoness– dragoness2025年08月16日 10:57:29 +00:00Commented Aug 16 at 10:57
-
1\$\begingroup\$ I cleaned the code. \$\endgroup\$dragoness– dragoness2025年08月17日 06:05:31 +00:00Commented Aug 17 at 6:05