2025-11-28 11:30:59
It takes all the running you can do, to keep in the same place
When I think about safe guarding LLMs against attacks the paradigm that comes to mind is the Red Queen Hypothesis:
The Red Queen hypothesis in evolutionary biology is a theory that species must constantly adapt, evolve, and proliferate in order to survive while pitted against ever-evolving opposing species.
source
How does a theory from Evolutionary Biology relate to modern day Artificial Intelligence attacks? In the wild, the prey can never fully evolve past the predator’s attacks because as the prey is evolving it’s defenses, the predator is in parallel, evolving strategies to overcome those defenses. So, evolutionary speaking, the prey can never fully out run it’s predator — it can only “keep pace” with the predator (see sub-header above).
Just like a rabbit trying to out run a fox, as safe guards in Artificial Intelligence become more sophisticated, so do the attacks. Which brings us to today’s topic.
LLMs are designed to resist engaging in bad behavior. Jailbreaks attempt to overcome this design and override the programed-benevolence of the LLM. A Jailbreak attempts to move the line of what the LLM can do and what it is willing to do. This is also known as Alignment, which ensures that the LLM goals and outputs are consistent with the human’s intentions and values. Jailbreak attacks exploit vulnerabilities in this alignment to make the model generate harmful, biased, or restricted content. In addition, previous Jailbreak attacks have been single-turn inputs.
Various Jailbreak attacks include:
optimization-based jailbreaks: involve adversaries optimizing a suffix to circumvent the model’s safety measures
textual inputs: where attackers craft a text input that includes instructions or triggers, often in a one-shot setting
Tools already exist to block these types of attacks, but what makes the Crescendo method different is it uses a multi-turn conversational inputs that are benign but are intended as an attack.
As LLMs evolve to become more complex and sophisticated, the attacks also evolve with the LLMs in order to penetrate the newly adapted safeguards. Crescendo builds upon existing Jailbreak attacks, it uses a simple multi-turn conversational method in a benign manner. It starts with a general question to the LLM about the task at hand and then gradually escalates by referencing the model’s replies progressively, which leads to a successful Jailbreak.
Through multiple interactions, Crescendo gradually steers the model to generate harmful content in small, benign steps. Crescendo can be automated using the Crescendomation, a tool that automates the Crescendo jailbreak technique.
Fortunately, there are ways to circumvent a Crescendo attack:
During the LLM training phrase the training data should be pre-filtered to exclude bad content. A drawback with this is that it’s costly and it may be difficult to fully sanitize the training data.
Crescendomation could generate datasets across various tasks and use them during alignment to make models more resilient.
Having output and input guardrails could also help detect the
Crescendo jailbreak prompts and model outputs.
The DeepTeam Python Library has a CrescendoJailbreaking library that can be used to simulate attacks on your LLM. I highly recommend playing around with the library and seeing the Cresendo Method in action.
Protecting your LLM application is the upmost importance for any AI Engineer. It leads to a better user experience while protecting your application. Staying up to date with the newest attacks is part of the job. I hope this article helps to highlight this new type of attack, while providing solutions to circumvent them.
Source:
https://arxiv.org/pdf/2404.01833
https://www.trydeepteam.com/docs/red-teaming-adversarial-attacks-crescendo-jailbreaking
2025-11-28 11:08:55
MongoDB has become one of the most popular NoSQL databases in the world. Its flexible schema, JSON-like documents, and developer-friendly ecosystem make it a top choice for modern applications, from small side projects to large-scale enterprise systems.
In this article, you will learn everything you need to know to get started with MongoDB, from installation to CRUD operations, indexes, aggregation, schema design, and best practices.
MongoDB is a NoSQL document database that stores data in BSON (Binary JSON) format. Unlike relational databases, MongoDB does not require predefined schemas, making it more flexible for fast-moving projects and distributed systems.
MongoDB stores data using the following hierarchy:
MongoDB
└── Database
└── Collection
└── Document
└── Field (key/value)
Example:
myDatabase
└── users (collection)
└── { name: "Klie", age: 22 } (document)
You can install MongoDB Community Edition using:
brew install mongodb-community
mongosh
import mongoose from "mongoose";
mongoose.connect("mongodb://localhost:27017/mydb")
.then(() => console.log("MongoDB connected"))
.catch(err => console.log(err));
show dbs
use myDatabase
show collections
db.users.insertOne({
name: "Klie",
age: 24,
skills: ["C++", "Node.js", "MongoDB"]
});
db.users.insertMany([
{ name: "Farhad", age: 22 },
{ name: "Rahimi", age: 30 }
]);
db.users.find();
db.users.find({ age: { $gt: 20 } });
db.users.findOne({ name: "Klie" });
db.users.updateOne(
{ name: "Klie" },
{ $set: { age: 25 } }
);
db.users.updateMany(
{ age: { $lt: 30 } },
{ $set: { status: "active" } }
);
db.users.deleteOne({ name: "Farhad" });
db.users.deleteMany({ age: { $gt: 40 } });
Indexes help improve query performance.
db.users.createIndex({ name: 1 }); // 1 = ascending
db.users.getIndexes();
db.users.dropIndex("name_1");
Aggregation is like SQL’s GROUP BY.
db.users.aggregate([
{ $group: { _id: "$age", total: { $sum: 1 } } }
]);
db.users.aggregate([
{ $sort: { age: 1 } }
]);
db.users.aggregate([
{ $match: { age: { $gt: 20 } } },
{ $sort: { age: -1 } },
{ $limit: 5 }
]);
import mongoose from "mongoose";
const userSchema = new mongoose.Schema({
name: String,
age: Number,
skills: [String]
});
const User = mongoose.model("User", userSchema);
export default User;
const user = await User.create({
name: "Klie",
age: 24,
skills: ["C++", "Node.js"]
});
const users = await User.find({ age: { $gt: 20 } });
Think in objects, not tables.
Keep document size < 16MB.
mongod --auth)MongoDB is used in:
MongoDB is a powerful, flexible, and highly scalable NoSQL database that fits modern development workflows very well. Whether you are building an e-commerce platform, a social media system, or a personal project, MongoDB offers simplicity and strong performance.
If you are working with JavaScript, Node.js, or full-stack applications, MongoDB integrates seamlessly and accelerates development time.
2025-11-28 11:07:13
For a long time, I believed software development was all about writing good code clean, scalable, and efficient. I thought if I improved my coding skills, learned new frameworks, and solved more problems, everything else would fall into place.
But as I grew in the field, one realization hit me harder than any bug I ever faced:
Coding isn't the skill that separates average developers from great ones communication is.
Many beginners and even intermediate developers spend years mastering syntax but can't clearly explain their ideas, collaborate smoothly with others, or express their thoughts confidently. And in today's modern software world, that communication gap is a career limiter.
Why Developers Struggle With Communication
Most developers (especially beginners) overlook communication for one simple reason: They think their code will speak for them.
Code doesn't tell your team why you made certain decisions. Code doesn't communicate with designers, product managers, or clients. Code doesn't defend itself in a code review or meeting. YOU do.
This is why good developers sometimes get ignored, overshadowed, or misunderstood not because their code is bad, but because their communication is.
Why Communication Matters More Than You Think
1.Teams depend on it
Modern software engineering is highly collaborative. You're constantly interacting with:
Teammates, designers, project managers, QA testers, and stakeholders. If you can't communicate your ideas clearly, you slow the entire team down.
2. It shows confidence and professionalism
The ability to speak clearly, explain decisions, and ask the right questions instantly makes you look more confident even if you're still a beginner.
Many juniors lose opportunities not because they're unskilled… but because they sound unsure, confused, or quiet.
3. It makes code reviews smoother
Code reviews aren't just about fixing bugs. They're about explaining:
why you chose a certain approach, how your solution works, and what your thinking process was. If you can do this clearly, your team trusts you more.
4. Recruiters notice it instantly
Companies look for more than technical skill. They want people who can: collaborate, explain, documen, and communicate. A developer who writes and speaks clearly feels like someone who can handle responsibility.
A Real Example That Happens Every Day Imagine two junior developers:
Developer A:
Writes excellent, efficient code but struggles to explain their logic. Stays quiet during meetings. Gets nervous when asked questions about their work.
Developer B:
Still learning. Makes mistakes. Not the strongest coder but communicates clearly, explains their thought process, and asks good questions.
Guess who gets trusted more?
Guess who gets chosen for important tasks?
Guess who gets promoted faster?
Always Developer B.
Because teams value clarity and confidence more than silent perfection. How Miscommunication Slows You Down A developer might spend 2 hours writing code… but then 20 minutes fumbling through explanations in a meeting because they never practiced communication. Or they might build something great… only to have it rejected because they misunderstood the requirements all due to poor communication.
Communication failure = project failure. It's that simple.
The Moment I Realized Communication Is a Superpower
At first, I didn't think communication mattered. I believed everything depended on my ability to code well. But the more I learned about the tech industry, the more I understood:
Developers who communicate get more responsibility.
Developers who explain ideas get noticed.
Developers who ask good questions learn faster.
Developers with clear thinking become leaders.
That's when it hit me: Communication is not separate from software engineering it is software engineering. How to Start Improving Your Communication Today Here are simple steps you can begin practicing immediately:
✔ Explain your code to yourself If you can't explain it, you don't understand it enough.
✔ Ask clarifying questions in meetings It shows maturity not weakness.
✔ Write more (posts, notes, documentation) Writing builds the clarity that developers need.
✔ Practice summarizing problems This makes you sound decisive and structured.
✔ Talk through your solutions Even talking to yourself or a mentor helps you sharpen your communication.
Conclusion & Takeaway
Great developers aren't the ones who write the most complex code. They're the ones who can explain, collaborate, and communicate clearly. In a world where teams, remote work, and cross-functional collaboration are the norm, communication isn't a "soft skill." It's a core engineering skill. Good developers code. Great developers communicate. And the earlier you understand this, the faster you grow.
2025-11-28 11:06:58
A Quality Management Plan is often introduced early in project planning, but many teams treat it as a static document instead of a living system for controlling and improving quality. This is where problems begin. A weak or incomplete Quality Management Plan creates gaps that are eventually felt through defects, miscommunication, cost overruns or dissatisfied stakeholders. In project management, these consequences are expensive and difficult to reverse.
A clear and detailed Quality Management Plan helps teams understand what quality means for the project, how it will be measured and how issues will be handled. In this article, you will learn the most common mistakes that weaken a Quality Management Plan, how to fix them, a simple four step method to create one correctly and practical tips you can apply right away. The goal is to help you produce a plan that strengthens your deliverables, supports continuous improvement and aligns with stakeholder expectations.
A Quality Management Plan is a document in project management that explains how a project will achieve the level of quality expected by stakeholders. It guides the team from the early stages of project planning to the final handoff.
It supports consistency and reduces risks by outlining how work should be performed, checked and improved. Instead of reacting to problems at the end, the plan encourages prevention, early detection and continuous refinement throughout the entire project lifecycle.
Before looking at the mistakes, it helps to revisit what a Quality Management Plan usually contains. A complete plan often includes:
These elements create structure, predictability and accountability. When several of them are unclear or missing, the project becomes vulnerable to delays, rework, unclear responsibilities and inconsistent expectations.
Below are the most frequent errors found in Quality Management Plans. Each error includes a thorough explanation, the impact on project management and detailed steps to correct the issue. For variety and readability, some sections include bullet points, examples and breakdowns.
Some plans use language that sounds positive but does not provide measurable direction. Terms like high quality, easy to use or fast performance are too subjective. They cannot be tested or validated because no one knows what threshold defines success.
Why this matters
Vague standards create inconsistent interpretations. One team member may believe the interface is responsive while another may think it still feels slow. Customers may assume a level of polish that the team never planned for. These gaps lead to late stage conflict and rework.
How to fix it
Translate subjective statements into measurable criteria. Examples include:
Specific measurements help the team design tests, evaluate outcomes and agree on what acceptable quality looks like.
Quality is not defined by the project team alone. Project stakeholders often have expectations about functionality, appearance, performance, compliance or reliability. When their input is collected once at the beginning but never validated, misalignment grows throughout the project.
Signs this error is happening
Why this matters
Stakeholder dissatisfaction can delay approval, increase negotiation cycles and trigger costly rework. It also weakens trust and makes project governance harder.
How to fix it
Blending stakeholder input with project limitations creates a more realistic and achievable definition of quality.
Quality assurance and quality control support two different parts of the project. Quality assurance focuses on preventing defects through process improvements. Quality control focuses on detecting defects in deliverables. Many plans mix the two or fail to define them at all.
The impact of this mistake
How to fix it
Break the activities down clearly.
Quality assurance examples
Quality control examples
This separation helps the team prevent, detect and correct quality issues systematically.
A Quality Management Plan must identify who is responsible for quality activities. When roles are unclear, tasks are either duplicated or forgotten.
Common symptoms
How to fix it
Assign roles for every quality activity. A RACI-style breakdown works well. It is based on these principles:
This approach removes ambiguity and supports smooth project execution.
Even when standards appear clear, many Quality Management Plans do not define thresholds for acceptable performance. A deliverable may meet functional requirements but still fail expectations because the allowable range is unclear.
Examples of missing thresholds
How to fix it
Include performance thresholds such as:
These thresholds help teams understand exactly when a result is acceptable and when corrective action is needed.
Monitoring quality without a consistent reporting rhythm leads to blind spots. Plans often fail because reporting is informal or irregular. Decisions are then based on incomplete information.
Why this matters
How to fix it
Predictable reporting strengthens communication and early intervention.
Identifying an issue is only the first step. Many projects struggle because corrective action is not clearly defined or scheduled. Problems are acknowledged but not addressed quickly enough.
Consequences
How to fix it
Corrective action should bring the project back to the quality baseline rather than only patching symptoms.
Below is the four step method from your earlier version, kept intact because it is the most accurate and practical.
Identify customer quality objectives through interviews and research. Review legal, environmental, professional and industry standards. Balance customer needs with project constraints. Define performance thresholds and confirm them with customers.
Carry out tasks according to the approved Quality Management Plan. Maintain communication across teams and document activities. Gather observations for future lessons learned.
Conduct technical reviews, process oversight and verification steps. Compare results with customer quality objectives and report findings at regular intervals. Treat each cycle as an opportunity for continuous improvement.
Address anomalies quickly to return the project to its quality baseline. Document changes so improvements can be kept for future projects or updates to the Quality Management Plan.
| Section | Example |
|---|---|
| Project | Mobile App Feature Upgrade |
| Customer Quality Objectives | Smooth performance, under 1-second load time, no critical bugs |
| Industry Standards | App Store compliance, basic accessibility, data security |
| Performance Thresholds | 95% test pass rate, maximum two minor defects per release |
| Execution Notes | Weekly sync between development and QA teams, documented test cycles |
| Quality Checks | Code reviews, regression testing, small user group usability tests |
| Corrective Action | Fix defects within 48 hours, adjust workflow if patterns repeat |
This Quality Management Plan outlines how a team ensures an upgraded mobile app feature meets customer expectations and industry requirements. It highlights clear performance goals, like fast load times and minimal bugs, and ties them to measurable testing standards.
The plan also defines how quality will be maintained during development, including weekly coordination between teams, structured test cycles, and consistent code reviews. Finally, it sets rules for corrective action so issues are fixed quickly and recurring problems are addressed through workflow improvements.
A strong Quality Management Plan protects your project from avoidable issues by setting clear standards, defining responsibilities and aligning everyone on what quality truly means. When these elements are missing or vague, even simple tasks can lead to delays, rework and frustrated stakeholders.
By applying the four step method and keeping quality checks consistent, your plan becomes a practical guide that supports better decisions and smoother delivery. With the right approach, quality becomes predictable, customer satisfaction increases and your project has a far stronger chance of success.
2025-11-28 11:05:30
Complex systems often appear chaotic or incomprehensible, yet closer examination reveals that such complexity can frequently be reduced to a simple underlying mechanism. By systematically removing layers of emergent behavior, one can uncover a fundamental rule or equation from which the entire system originates.
While the system described in this article may appear trivial at first glance, the resulting patterns exhibit quasi-fractal behavior that can be analyzed, encoded, and even predicted through symbolic methods. The work presented here was developed independently through direct observation, rather than derived from prior literature.
A useful way to motivate this exploration is by analogy with a common physical phenomenon - wave interference. Consider waves on the surface of a river: a wavefront moves toward the shore, reflects, and overlaps with itself. Do these reflections contain an underlying order? Is it possible to extract structure from the interference?
To investigate this, we simplify the system. Rather than modeling the full wave, we consider only the motion vector - essentially, a ray. We also smooth the “shoreline” and discretize the environment into a rectangular grid. From this setup emerges the core construction of this article.
":)"
The example of waves on the surface of a river serves as a real, intuitive starting point - an accessible physical system that demonstrates how simple rules, such as reflection and interference, can produce complex behavior. It illustrates the central idea: that what appears chaotic often emerges from deterministic structure.
The initial motivation was driven by the conviction that apparent disorder is not randomness, but the result of unresolved or hidden structure. Any system that seems chaotic is governed by rules - its complexity a consequence of perspective, not unpredictability.
To explore this further, attention turned to constructing the simplest possible system that could look chaotic yet remain fully deterministic.
One such system involved a sine wave originating from the corner of a rectangle and reflecting off its boundaries. The nonlinearity of the sine function causes it to intersect itself in complex and unintuitive ways. However, due to limited tools available at the time, the model was simplified even further.
Instead of a sine wave, a straight line was used. The line was made periodic (dashed), and the system was designed to be reproducible using only a pencil and a sheet of graph paper. Despite its simplicity, this construction revealed intricate and structured patterns-forming the foundation of what would later be described as the “billiard fractals.”
The following sequence illustrates the core mechanism of the discrete billiard system:
An animated version:
Output pattern:
A selection of patterns generated from rectangles with various dimensions:
![]() |
![]() |
![]() |
![]() |
![]() |
![]() |
![]() |
![]() |
![]() |
![]() |
![]() |
![]() |
JavaScript implementation of this algorithmpattern.js - source code
The patterns generated by this system exhibit fractal structure: they are self-similar across scales, recursive in construction, and can be compressed symbolically. As the rectangle dimensions increase following the Fibonacci sequence, the patterns reveal increasingly detailed versions of the same underlying structure.
This refinement process is simple: given rectangle dimensions (m, n), new dimensions are generated by Fibonacci summation. For example, starting with 8×13:
Each step increases resolution while preserving the underlying structure.
| 8×13 | 13×21 | 21×34 | 34×55 | 55×89 |
|---|---|---|---|---|
![]() |
![]() |
![]() |
![]() |
"233×377 preview comparison"
The article’s header image corresponds to the 233×377 pattern. Its structure can be directly compared with the earlier 13×21 case.
When constructing these patterns using Fibonacci-based dimensions, we are effectively approximating a rectangle with side lengths in the golden ratio - that is, a ratio approaching (1 : φ). With each step, the approximation improves, and the pattern gains additional structure and resolution.
Although the overall structure of the pattern remains consistent during Fibonacci-based refinement, certain symmetries within the pattern depend on the parity of the rectangle's side lengths. Specifically, when both the width and height are odd integers, the resulting pattern exhibits clear diagonal, horizontal, and vertical symmetry. This occurs because the billiard path, under these conditions, terminates in the corner diagonally opposite from its starting point. In contrast, when one or both sides are even, the path terminates elsewhere, and the resulting pattern loses this precise symmetry - although the underlying recursive structure remains unchanged.
To understand why the structure persists under Fibonacci expansion, consider cutting a square from the pattern. The boundary behavior reveals that the path (i.e., the “billiard ball”) always returns to its entry point:
Moreover, the path always (except for diagonal cases) crosses an even number of cells. This ensures that the pattern remains consistent across such subdivisions.
By recursively separating square regions from the larger pattern, the symbolic seed of the system can be exposed:
The path traced by the billiard ball through the grid can be encoded as a binary sequence. As the ball moves from cell to cell, its internal state alternates according to a fixed rule. We can label these alternating states with binary values - for example, assigning 0 to one state and 1 to the other. This produces a binary field that can be visualized directly.
For example:
The top row of the binary field can be viewed as a symbolic boundary - a compact representation of the billiard system's behavior along a single edge. By studying the structure of the full 2D pattern and recursively extracting square sections from it, we arrive at symbolic generation rules. These rules allow us to reconstruct the boundary sequences using only binary operations.
Two core recursive generators are presented below:
function invers(array) {
var temp = [];
for (let i = 0; i < array.length; i++)
temp[i] = array[i] === 0 ? 1 : 0;
return temp;
}
function revers(array, s) {
var temp = [];
for (let i = 0; i < s; i++)
temp[i] = array[array.length - i - 1];
return temp;
}
function sequence(fn, fn1) {
if (fn1 === 3) return [1];
fn1 = fn - fn1;
fn = fn - fn1;
var array = sequence(fn, fn1);
var a0 = invers(array);
var a1 = (fn1 % 2 === 0) ? [1] : [];
var a2 = revers(array, Math.floor((fn - fn1) / 2));
return a0.concat(a1, a2);
}
function sequenceFibonacci(iterations) {
let f0a = [0];
let f1a = [0];
for (let i = 0; i < iterations; i++) {
let f0 = f0a.length;
let a2 = revers(f1a, f0);
if (f1a.length % 2 === 0) a2[0] ^= 1;
f0a = f1a;
f1a = f1a.concat(a2);
}
let array = [];
for (let i = 0; i < Math.floor(f1a.length / 2); i++)
array[i] = f1a[i * 2];
return array;
}
These constructions reproduce the symbolic edges of Fibonacci-based patterns and can be interpreted as recursive encoding schemes derived directly from the observed geometry.
"Toward Generalization"
While the above generators are constructed specifically for Fibonacci-sized rectangles, preliminary experiments suggest that similar structures may emerge for other co-prime pairs. These systems may obey different symbolic transformation rules, but exhibit comparable recursive or compressible traits. A formal generalization of these behaviors remains an open area of exploration.
One of the central challenges that motivated the progression from the original 2013 construction to the deeper analysis in 2019 was the question of irrational proportions: what happens when the rectangle’s side lengths form a truly irrational ratio, such as (1 : φ), rather than an integer-based approximation like 13 : 21?
While recursive generators such as sequence(fn, fn1) accurately reproduced the symbolic boundary sequences for Fibonacci-based rectangles, they were inherently tied to integer dimensions. The challenge was clear: how can one generate the same structures when no exact grid alignment is possible - when the trajectory no longer closes?
This question defines the next stage of the investigation. To answer it, we will analyze the boundary sequences themselves - the so-called fractal sequences - and show how they encode the entire 2D pattern. We will show that these sequences - far from being edge artifacts - contain enough information to deterministically reconstruct the entire 2D pattern. This finding enables a powerful dimensional reduction: the entire billiard system can be expressed as a 1D sequence.
We now shift from the dashed-line visualization to a binary representation. Instead of drawing the trajectory, we color the cells the ball passes through, alternating black (0) and white (1) with each step.
Given a rectangle with side lengths
MMM
and
NNN
, the ball is launched from a corner and follows diagonal motion, reflecting off the walls. Each step alternates the internal binary state.
The reflection rule causes the trajectory to shift by one cell after each bounce. This alternation creates a consistent visual structure.
When
MMM
and
NNN
are coprime, the trajectory visits every cell exactly once:
JavaScript implementationbinarypattern.js
"Gif"
JavaScript implementationbinarypattern_point.js
If the dimensions share a common divisor ( gcd(M,N)>1gcd(M, N) > 1gcd(M,N)>1 ), the trajectory terminates at a corner before filling all cells:
In this case, the system is equivalent to a billiard in a reduced rectangle with dimensions ( MGCD\frac{M}{GCD}GCDM , NGCD\frac{N}{GCD}GCDN ):
In the coprime case, the ball crosses every row and column. Notably, each pass between the top and left walls consists of an even number of steps.
From this, we can observe a critical symmetry: the left column contains the inverted bits of the top row, excluding the initial bit.
Furthermore, every second bit ( 2n−12_{n-1}2n−1 ) in the top sequence is the inverted version of its neighbor ( 2n2_{n}2n ). Therefore, we can discard every second bit and retain full pattern information:
For example, with dimensions M=21,N=13M=21, N=13M=21,N=13 , the resulting sequence is: 1010010110
This sequence is unique for every coprime pair (M,N)(M, N)(M,N) . It encodes all necessary information about the pattern.
The trajectory between two reflections from the upper wall is always 2N2N2N cells long. Each such pass begins with a black cell (bit = 0) and ends with a white cell (bit = 1):
More formally:
1 indicates that the ball arrived from a reflection off the right wall
0 indicates it came from the left wall
This mapping gives the sequence its meaning. In the diagram below, the trajectory is colored black when moving right and white when moving left:
A curious side effect of the billiard construction is that it naturally encodes binary division of two numbers. Specifically, by tracking the direction of the billiard ball’s movement at each wall collision, and sampling this information at exponentially increasing intervals, one can extract the binary digits of a rational fraction.
Let the billiard table have side lengths MMM and NNN , and let the ball bounce between corners. At each collision with the top or bottom wall:
If the ball is moving to the right, record a 0
If moving to the left, record a 1
Then, at every 2n2^n2n -th collision (i.e., 1st, 2nd, 4th, 8th, …), we record the state.
Example: for a table of size M=21,N=13M=21, N=13M=21,N=13 , we obtain:
1st (bottom, →): 0
2nd (top, ←): 1
4th (top, →): 0
8th (top, →): 0
16th (top, ←): 1
32nd (top, ←): 1
...
This produces the binary expansion:
0.1001111001111001111…
Which is precisely the binary representation of
1321\frac{13}{21}2113
.
The full billiard pattern can be reconstructed from this single boundary sequence. Even extrapolation beyond the grid is possible.
Let us begin by placing the bits along the top edge of a square grid of width MMM . Bits are spaced every 2 cells - these are the points where the ball would hit the upper wall:
Then:
1, we extend a diagonal to the left
0, we extend it to the right
The first bit (bit 0) is treated specially - it begins the pattern:
The reconstruction produces the exact original pattern:
JavaScript implementationvisualizer.js
This result shows that the 1D sequence contains complete information about the original 2D billiard pattern.
But we're not done.
From the surface of the river, we reduced the system to a rectangular billiard with a dashed diagonal trajectory. Then we reduced it further - to a binary field generated by alternating internal states. Now, we push the reduction one step further: we collapse the entire 2D billiard into a one-dimensional rule. A symbolic system with no geometry left - only structure.
This is where we begin to uncover the origin of these fractals.
On the XXX number axis, we take two points: 000 and MMM .
Moving from one point to another, we measure the distances NNN :
We marked a point. We continue to measure the distance from this point, maintaining the direction. If we reach point 000 or MMM , we change the direction:
As you can see in the pictures above, the first point shows the place where the ball touches the bottom wall of the billiard table. We are not interested in this point. We will only mark the points 2kN2kN2kN for k=0,1,2,…k=0,1,2,…k=0,1,2,… .
How to mark these points? Let's unfold our billiard table on the XXX axis. Let's mark the points 0,M,2M,3M,…0, M, 2M, 3M,…0,M,2M,3M,… . Now, having reached point MMM , we do not change the direction of movement, but continue moving to point 2M2M2M .
Points that are multiples of MMM divide our axis into segments. We will conditionally mark these segments with ones and zeros (alternating). On the segments marked with zeros, the ball (in rectangular billiards) moves from left to right. On the segments marked with ones, it moves from right to left. Or more simply: the ball moves from left to right if Qk=0Q_k=0Qk=0 , for
Qk=⌊2kNM⌋ (mod 2);k=0,1,2,…Q_k=\lfloor \frac{2kN}{M} \rfloor \; (\textrm{mod} \; 2); \quad k=0,1,2,…Qk=⌊M2kN⌋(mod2);k=0,1,2,…
It is easy to see that the point at which the ball touched the upper wall of the billiard table is the remainder of dividing 2kN2kN2kN by MMM . In this case, we don't need to record the movement of the ball in the opposite direction. We take the integer part of dividing 2kN2kN2kN by MMM , if it is even - we calculate the remainder of dividing 2kN2kN2kN by MMM . We divide the resulting remainder by 2 (the distance between adjacent touch points is two cells). This gives us the indices of the array elements that correspond to rightward motion (zeros). All other entries - representing leftward trajectories - are filled with ones.
Sequence length =
M2\frac{M}{2}2M
.
function sequence(m,n){
var md=m/2;
var array=[];
for(var k=0;k<md;k++) array[k]=1;
for(var k=0;k<md;k++) if(Math.floor(2*k*n/m)%2==0) array[((2*k*n)%m)/2]=0;
return array;
}
Now we can build a binary sequence for billiards with any sides
MMM
and
NNN
(natural numbers). Some examples:
144x89 (Fibonacci numbers):
010100101101001011010110100101101001010010110101001011010100101
169x70 (Pell numbers):
010101101010010101101010010101101010100101011010101001010110101001010101010010101101010010
233x55 (odd Fibonacci numbers
FnF_nFn
and
Fn−3F_{n-3}Fn−3
):
010010011011011001001101101100100100110110010010011011001001001101101100100110110110010010011011001001001101100100100
Very curious graphs are obtained if you take a billiard table with width M and construct sequences for each N from 0 to M. Then these sequences are stacked.
var array;
for(var y=1;y<m;y++){
array=sequence(m,y);
for(var x=0;x<array.length;x++){
if(array[x]==0) context.fillRect (x, y, 1, 1);
}
}
Some examples.
| M=610 | M=611 | M=612 | M=613 | M=614 |
|---|---|---|---|---|
![]() |
![]() |
![]() |
![]() |
![]() |
JavaScript implementationsequences.js
We have sequences. How else can we visualize binary sequences? With Turtle graphics.
The sequence length determines the complexity of the curve. The more irrational the ratio between M and N, the more non-periodic and fractal - like the structure becomes.
Draw a segment. Then take bits from our sequence one by one. If bit = 1 - rotate the segment relative to the previous one by 60∘60^{\circ}60∘ (clockwise). If bit = 0 - rotate the segment by −60∘-60^{\circ}−60∘ . The beginning of the next segment is the end of the previous one.
Take two large enough Fibonacci numbers: F29=514229F_{29}=514229F29=514229 and F28=317811F_{28}=317811F28=317811 . This ensures that the pattern is long enough for the fractal structure to become apparent, but still bounded enough for visualization.
We built the sequence:
0010110100101101001010010110100101101010010110100101101001010010110100101… (257114 symbols plus a zero bit).
Visualize using turtle graphics. The size of the initial segment is 1 pixels (the initial segment is in the lower right corner):
The next example is Pell numbers.
We take P16=470832P_{16}=470832P16=470832 and P15=195025P_{15}=195025P15=195025 .
The sequence is:
00101001010110101001010101010100101011010100101010110101001010101101 (235415 symbols plus a zero bit).
The size of the initial segment is 1 pixel:
Another example is the odd Fibonacci numbers
FnF_nFn
and
Fn−3F_{n-3}Fn−3
.
Let's take
F28=317811F_{28}=317811F28=317811
and
F25=75025F_{25}=75025F25=75025
.
The sequence is:
00110110010010011011001001101101100100110110110010011011011001001… (158905 plus a zero bit).
Instead of the angles
60∘60^{\circ}60∘
and
−60∘-60^{\circ}−60∘
, we will use the angles
90∘90^{\circ}90∘
and
−90∘-90^{\circ}−90∘
.
The size of the initial segment is 1 pixels:
This curve is called "Fibonacci Word Fractal". The Hausdorff dimension for this curve is known:
D=3logΦlog(1+2)=1.6379;Φ=1+52D=3{\frac {\log \Phi }{\log(1+{\sqrt {2}})}}=1.6379; \quad \Phi =\frac {1+{\sqrt {5}}}{2}D=3log(1+2)logΦ=1.6379;Φ=21+5
JavaScript implementationturtle.js
Is it possible to draw a pattern for billiards, the sides of which are incommensurable (one of the sides is an irrational number)? At first glance, the task seems impossible. Trying to solve this problem, we will face a number of questions:
The first two questions obviously have no solution. But if there were a way to fill the sequence in order, then we could, moving along the sequence from left to right, restore the pattern in the way we used above. And thus see what the pattern looks like in the upper left corner of the billiard table whose sides are incommensurable.
Let's take a billiard table, the sides of which are equal to the Fibonacci numbers (this trick may not work with other numbers). Let's throw a ball into it and record the number of times the ball touches the upper wall. We'll paint the numbers white if the ball moved from right to left and black if the ball moved from left to right:
White corresponds to the number one in the sequence, black to zero. Now let's arrange the numbers in order:
We've got exactly the same sequence of ones and zeros.
21(1), 13(0), 8(1), 26(0), 5(0), 16(1), 18(0), 3(1), 24(1), 10(0), 11(1), 23(0), 2(0), 19(1), 15(0), 6(1), 27(1), 7(0), 14(1), 20(0), 1(1), 22(1), 12(0), 9(1), 25(0), 4(0), 17(1)
1(1), 2(0), 3(1), 4(0), 5(0), 6(1), 7(0), 8(1), 9(1), 10(0), 11(1), 12(0), 13(0), 14(1), 15(0), 16(1), 17(1), 18(0), 19(1), 20(0), 21(1), 22(1), 23(0), 24(1), 25(0), 26(0), 27(1)
"For other numbers"
The origin is the upper left corner. The X axis is the width of the billiard table M. The Y axis is the height of the billiard table N. The numbers for which the sequences match are marked with white dots:
Numbers for which the sequence is inverted:
JavaScript implementation:
The first line is the mouse coordinates, which are used as the width and height of the billiard table.
The second line is the first 100 bits of the sequence obtained through the remainders of the division.
The third line is the first 100 bits of the sequence obtained through the parity of the integer part.
Black color - Visualization of the first sequence using Turtle graphics.
Purple - visualization of the second sequence.
JavaScript implementationturtle_dynamic.js
In fact, in some cases, we do not need to take the remainder from the division. For Fibonacci numbers, it is enough to check the parity of the integer part of the division of 2kN2kN2kN by MMM :
Qk=⌊2kNM⌋ (mod 2);k=0,1,2,…Q_k=\lfloor \frac{2kN}{M} \rfloor \; (\textrm{mod} \; 2); \quad k=0,1,2,…Qk=⌊M2kN⌋(mod2);k=0,1,2,…
In the numerator we have FnF_{n}Fn . In the denominator - Fn+1F_{n+1}Fn+1 .
As is known:
limn→∞FnFn+1=1Φ\lim_{n\to\infty} \frac{F_n}{F_{n+1}}= \frac{1}{\Phi}limn→∞Fn+1Fn=Φ1
This gives us a bridge: rational billiards ( FnF_{n}Fn , Fn+1F_{n+1}Fn+1 ) converge toward an irrational limit - Φ\PhiΦ - allowing us to define an infinite symbolic sequence.
Φ\PhiΦ is the Golden Ratio. An irrational number. Now we can write our formula as:
Qk=⌊2kΦ⌋ (mod 2);k=0,1,2,…Q_k=\lfloor \frac{2k}{\Phi} \rfloor \; (\textrm{mod} \; 2); \quad k=0,1,2,…Qk=⌊Φ2k⌋(mod2);k=0,1,2,…
We have obtained a formula with which we can fill in the sequence for a billiard table, the width of which is Φ\PhiΦ and the height is 111 . The length of the sequence = ∞\infty∞ , but we can restore part of the pattern by moving from left to right along the sequence and looking into the upper left corner of the billiard table. It remains to figure out how to calculate Φ\PhiΦ
One divided by the golden ratio can be rewritten as:
1Φ=−1+52\frac{1}{\Phi}=\frac {-1+{\sqrt {5}}}{2}Φ1=2−1+5
We can get rid of the two:
2kΦ=2k(−1+5)2=k5−k\frac{2k}{\Phi}=\frac {2k(-1+{\sqrt {5}})}{2}=k\sqrt{5}-kΦ2k=22k(−1+5)=k5−k
Our formula takes the form:
Qk=⌊k5−k⌋ (mod 2);k=0,1,2,…Q_k=\lfloor k\sqrt{5}-k \rfloor \; (\textrm{mod} \; 2); \quad k=0,1,2,…Qk=⌊k5−k⌋(mod2);k=0,1,2,…
Now we can draw part of the billiard pattern with sides 111 and Φ\PhiΦ :
If we do not subtract kkk each time, then every second bit in the sequence is inverted. We get the general formula:
Qk=⌊kx⌋ (mod 2);k=0,1,2,…Q_k=\lfloor k\sqrt{x} \rfloor \; (\textrm{mod} \; 2); \quad k=0,1,2,…Qk=⌊kx⌋(mod2);k=0,1,2,…
Let's build a sequence for
k2k\sqrt{2}k2
var x=2;
var q=[];
for(var k=0;k<256000;k++) q[k]=Math.floor(k*Math.sqrt(x))%2;
The first few bits of the sequence (A083035):
01001101100100110011001101100100110110011001001101100100110110…
Angles are 90∘90^{\circ}90∘ and −90∘-90^{\circ}−90∘ . The size of the initial segment is 5 pixels:
"This is interesting"
From this curve, we can reconstruct the "billiard pattern" and see what is around the curve:
It would be interesting to find M and N for this pattern.
Number of segments in the repeating part of the curve = PnP_nPn (Pell numbers: 0, 1, 2, 5, 12, 29, 70, 169, 408, 985, 2378, … ).
2=limn→∞Pn−1+PnPn\sqrt{2} = \lim_{n\to\infty} \tfrac{P_{n-1}+P_n}{P_n}2=limn→∞PnPn−1+Pn
Someone may doubt that the parity of the integer part of k2k\sqrt{2}k2 gives a fractal sequence. Let's visualize part of this sequence with the visualizer described earlier:
For clarity, we colored the longest curve in the resulting pattern:
This curve has a name - "Fibonacci word fractal".
Thus, by gradually reducing billiard geometry through symbolic encodings, we arrive at a powerful realization: even irrational systems, which defy spatial tiling and corner reflection, can still produce deterministic, fractal structure - using only integer math.
In the previous sections, we showed how symbolic sequences can generate complex boundary structures in discrete 2D space. All of these patterns - whether generated by rational billiards or floor-based symbolic systems - form enclosed regions.
Some of these regions close against the boundaries of the rectangle, while others are fully self-contained, looping within the grid. In either case, the resulting trajectories always define fully enclosed cells.
Consider the following example:
A binary sequence generated by the floor function:
Qn=⌊n2⌋ (mod 2);n=0,1,2,…Q_n=\lfloor n\sqrt{2} \rfloor \; (\textrm{mod} \; 2); \quad n=0,1,2,…Qn=⌊n2⌋(mod2);n=0,1,2,…
0100110110010011001001101100
Using the visualizer in diagonal mode, we generate a familiar fractal boundary.
However, switching to horizontal-vertical visualization, we invert every even-indexed bit and plot dashed lines accordingly. For bits with value 0, the lines are offset by one unit.
Vertical lines:
Horizontal lines:
Merged:
This technique resembles Hitomezashi stitching, a traditional Japanese method of generating textile patterns. While historically used to create decorative designs, this form of boundary generation bears striking similarity to the symbolic outlines produced in our system.
However, Hitomezashi does not solve the filling problem. It provides only the skeleton - the structure of edges - but no mechanism for interior construction.
To solve this, we developed a symbolic method to automatically fill the interior regions - using only the original sequence. No region detection, no geometry, no search algorithms.
The method works as follows:
Construct a cumulative array a[n], based on the bitwise value of the fractal sequence:
We define:
and
In code:
var a = [0];
for (var i = 1; i < size; i++) {
if (Math.floor(i * Math.sqrt(2)) % 2 == 1)
a[i] = a[i - 1] + 1;
else
a[i] = a[i - 1] - 1;
}
Then, for each cell (x, y), compute:
q = (a[x] + a[y] + 512) % 4;
if (q === 0 || q === 1)
context.fillRect(x, y, 1, 1);
The result is a filled pattern - not derived from pixel analysis or region marking, but emerging directly from the same symbolic system that generated the boundaries.
var a=[0];
for(var i=1;i<size;i++){
if(Math.floor(i*Math.sqrt(2))%2==1)
a[i]=a[i-1]+1;
else
a[i]=a[i-1]-1;
}
for(var x=0;x<size;x++){
for(var y=0;y<size;y++){
q=(a[x]+a[y]+512)%4;
if(q==0 || q==1) context.fillRect(x, y, 1, 1);
}
}
Hitomezashi and Symbolic Filling Algorithm
Fractal fill based on:
Qn=⌊n2⌋ (mod 2);n=0,1,2,…Q_n=\lfloor n\sqrt{2} \rfloor \; (\textrm{mod} \; 2); \quad n=0,1,2,…Qn=⌊n2⌋(mod2);n=0,1,2,…
"Gif"
Qn=⌊n(5+1)⌋ (mod 2);n=0,1,2,…Q_n=\lfloor n(\sqrt{5}+1) \rfloor \; (\textrm{mod} \; 2); \quad n=0,1,2,…Qn=⌊n(5+1)⌋(mod2);n=0,1,2,…
(Fibonacci-based)
"Gif"
Visualizer - Fractal Fill from Irrationalsfractal.js
Dynamic Visualization - Using Rational Approximationsfractal_dynamic.js
We can compare fractal sequences from floor-based systems with sequences produced by a perfect shuffle function.
Here's our shuffle logic:
function shuffle(array, shiftAmount) {
let len = array.length;
let shuffled = new Array(len * 2);
for (let i = 0; i < len; i++) {
shuffled[2 * i] = array[(i + shiftAmount) % len];
shuffled[2 * i + 1] = array[i];
}
return shuffled;
}
We start with a base array:
let shuffleIterations = 2*7+1;
let powerOfTwo = 2**7;
let shiftAmount = y * powerOfTwo;
let array1 = [1, 0];
for (let i = 0; i < shuffleIterations; i++) {
array1 = shuffle(array1, shiftAmount);
}
And compare it with this floor-based sequence:
let powerOfTwo = 2**7;
let irrationalApproximation = y / powerOfTwo;
let array2 = [];
for (let i = 0; i < sizexy; i++) {
array2[i] = Math.floor(i * irrationalApproximation) % 2;
}
Both arrays are then visualized using our bit-pattern analysis:
for (let y = 0; y < sizexy; y++) {
// generate array1 or array2
let digit;
let bits = [];
for (let i = 0; i < len; i++) {
digit = 0;
for (let j = 0; j < bitLength; j++) {
digit |= array[i + j] << (bitLength - 1 - j);
}
if (!bits.includes(digit)) {
bits.push(digit);
}
}
for (let i = 0; i < bits.length; i++) {
context.fillRect(bits[i] * size, y * size, size, size);
}
}
Here are the results:
Perfect shuffle:
Floor-based sequence:
Next:
let pow=7;
let shuffleIterations = 2*pow+1;
let powerOfTwo = 2**pow;
let map1=[];
for(let y=0;y<sizexy;y++){
map1[y]=[];
let shiftAmount = y * powerOfTwo;
let array = [0, 1];
for (let i = 0; i < shuffleIterations; i++) {
array = shuffle(array, shiftAmount);
}
map1[y]=array;
}
drawMap(document.getElementById('myCanvas'), map1);
map2=[];
for(let y=0;y<sizexy;y++){
let irrational = y / powerOfTwo;
let array2=[];
for (let i=0;i<sizexy;i++){
array2[i]=Math.floor(i * irrational)%2;
}
map2[y]=array2;
}
drawMap(document.getElementById('myCanvas1'), map2);
We generate two binary images using two completely different methods.
In the first image, each row is created by starting with [0, 1] and applying a recursive "perfect shuffle" operation. This operation doubles the array size each time and mixes a shifted copy of the previous state with itself. The shift amount depends on the current row number. We repeat this shuffle a specific number of times for each row to reach the final size.
In the second image, each row is generated by multiplying each column index by a scaled version of the row number, then taking the floor and reducing it modulo 2.
The two outputs are not just visually similar—they are bitwise identical, pixel by pixel, after horizontal flipping.
We verified this not just through floating-point floor operations, but also with a pure integer formulation using bit shifts:
array2[i] = ((i * y) >> pow) % 2;
This version avoids any irrational approximations entirely. It shows that the mapping:
By(i)=⌊i⋅y2pow⌋ mod 2B_{y}(i) = \left\lfloor \dfrac{i \cdot y}{2^{\text{pow}}} \right\rfloor \bmod 2By(i)=⌊2powi⋅y⌋mod2
is equivalent to a symbolic shift-and-fold recursion using perfect shuffles:
[0, 1] is shuffled 2·pow + 1 timesy × 2^pow each timeWe also observe that the symbolic structure of the shuffle is time-reversed compared to the floor-based sequence, which explains the horizontal flipping.
This means the perfect shuffle method is not just a metaphor or numerical coincidence — it's an algebraic encoder for binary floor-based mappings.
Let:
Then:
Shuffley[2p+1](x)=1−BinaryFloory(N−x−1)\boxed{\text{Shuffle}{y}^{[2p+1]}(x) = 1 - \text{BinaryFloor}{y}(N - x - 1)}Shuffley[2p+1](x)=1−BinaryFloory(N−x−1)
This relation holds exactly, using pure bitwise arithmetic.
See:shuffle_and_billiard_isomorphism.js
The binary sequence generated by
⌊k2⌋ mod 2\left\lfloor k \sqrt{2} \right\rfloor \bmod 2⌊k2⌋mod2
can be interpreted geometrically as a rotation on the unit circle. At each step kkk , we rotate by an irrational angle (e.g., 2\sqrt{2}2 ) and assign a 0 or 1 depending on which half of the circle the point lands in.
An alternative but mathematically equivalent formulation is:
sin(πk2)>0\sin\left( \pi k \sqrt{2} \right) > 0sin(πk2)>0
The sine function is positive in one half of the circle and negative in the other - effectively producing the same binary threshold.
This circular diagram shows the orbit of
k2 mod 1k \sqrt{2} \bmod 1k2mod1
projected onto the unit circle. The points rotate continuously and never repeat. Each crossing of the horizontal axis (i.e., sign change of sin(πk2)\sin\left( \pi k \sqrt{2} \right)sin(πk2) ) causes a binary switch. The result is a Sturmian sequence - a symbolic encoding of irrational rotation - visualized as a point traveling clockwise and recording its hemisphere.
Interestingly, even a sequence like
sin(k)>0\sin\left( k \right) > 0sin(k)>0
generates a similarly complex structure. Though the function seems simple, stepping by exactly 1 radian per iteration is irrational with respect to the sine wave’s natural period of 2π2 \pi2π . Thus:
sin(k)>0⟺⌊kπ⌋ mod 2\sin(k) > 0 \quad \Longleftrightarrow \quad \left\lfloor \frac{k}{\pi} \right\rfloor \bmod 2sin(k)>0⟺⌊πk⌋mod2
Which means: irrational step size alone is enough to create symbolic fractals. It’s not the shape of the function - it’s the incommensurability that matters.
We begin with a geometric interpretation of the function
⌊k2⌋ mod 2\left\lfloor k \sqrt{2} \right\rfloor \bmod 2⌊k2⌋mod2
This can be visualized as a straight line y=k2y=k \sqrt{2}y=k2 traversing a periodic 2D space where the yyy -axis alternates between bands labeled 0 and 1. The value of the function at each step depends on the integer part of k2k\sqrt{2}k2 , determining whether the line intersects an even or odd band.
Alternatively, we may interpret the system as a function y=xy=xy=x with 2\sqrt{2}2 acting as a discretization step along the vertical axis. This perspective reduces the behavior of the original billiard system to a symbolic sampling of a continuous linear function.
Both
⌊k2⌋ mod 2andsin(πk2)>0\left\lfloor k \sqrt{2} \right\rfloor \bmod 2 \quad \text{and} \quad \sin\left( \pi k \sqrt{2} \right) > 0⌊k2⌋mod2andsin(πk2)>0
serve as symbolic discretization methods - one yielding binary values via integer floor division, the other through sign thresholding on a continuous sinusoid.
Having reduced the system to a linear function and its discretization, we now explore the effects of replacing the base function y=xy=xy=x with a nonlinear alternative.
Linear rotation yields symbolic Sturmian sequences. What happens if we increase the curvature? Quadratic growth is the simplest next step.
We now substitute the linear function with:
y=x2y = x^2y=x2
We construct the new sequence using:
Qx=⌊x22⌋ (mod 2);x=0,1,2,…Q_x=\lfloor x^2\sqrt{2} \rfloor \; (\textrm{mod} \; 2); \quad x=0,1,2,…Qx=⌊x22⌋(mod2);x=0,1,2,…
q[x] = Math.floor(x * x * Math.sqrt(2)) % 2;
This substitution shifts us from uniform linear growth to a system governed by accelerating curvature, producing richer and more complex symbolic behavior.
Visualizing this sequence with the Symbolic Filling Algorithm yields a disordered pattern.
"Gif"
Similarly, applying Turtle graphics results in "chaotic" outputs
suggesting that the underlying symbolic dynamics differ significantly from the linear case. This observation motivated us to try a simpler visual encoding.
This prompts a reconsideration of visualization methods. Rather than relying on complex binary sequence encodings (e.g., symbolic filling or turtle graphics), we adopt a simpler approach:
k=35:
k=661:
This reveals that a seemingly chaotic 1D sequence can exhibit coherent spatial behavior when unfolded along two dimensions. Generalizing this, we rewrite the indexing expression as:
q[x] = Math.floor((x + k * y) ** 2 * Math.sqrt(2)) % 2;
Expanding the square:
(x+ky)2=x2+2kxy+k2y2(x + k y)^2 = x^2 + 2kxy + k^2 y^2(x+ky)2=x2+2kxy+k2y2
This quadratic form suggests a symbolic sampling of a 3D curved surface. We abstract this into a general expression:
z=a(x2+bxy+cy2)dz = a \left( x^2 + bxy + c y^2 \right)^dz=a(x2+bxy+cy2)d
Here:
For example, setting b=0,c=1,d=1b=0,c=1,d=1b=0,c=1,d=1 yields:
z=a(x2+y2)z = a \left( x^2 + y^2 \right)z=a(x2+y2)
an elliptical paraboloid, a classic bowl-shaped surface.
We then visualize both:
⌊z2⌋ mod 2\left\lfloor z \sqrt{2} \right\rfloor \bmod 2⌊z2⌋mod2
sin(πz2)\sin\left( \pi z \sqrt{2} \right)sin(πz2)
...using this surface. Despite differing in output (binary vs. continuous), both render structurally equivalent patterns: the sine version produces smooth grayscale textures, while the floor function yields crisp binary segmentation. In either case, the resulting 2D images exhibit radial, interference-like motifs - strongly reminiscent of diffraction or holographic patterns.
| binary | continuous |
|---|---|
![]() |
![]() |
The sine-based rendering reveals finer gradients and smoother interference zones, but the underlying symbolic structure is identical to the binary version.
In classical holography, a point source emits nested spherical wavefronts. When these are sliced by a flat recording plane, the amplitude at each (x, y) position encodes a continuous interference pattern. The spacing between wavefronts defines the wavelength - effectively a discretization step in the z-direction.
Our system inverts this paradigm: instead of slicing nested curved shells with a flat surface, we intersect a single curved surface with stacked, evenly spaced binary planes - symbolic layers representing a plane wavefront. Each (x, y) coordinate samples which symbolic layer the surface intersects, producing a binary (or thresholded) value.
While the components differ - continuous vs symbolic, curved emitter vs curved surface - the underlying mechanism is the same: a curved geometry intersected by layered structure, producing interference-like textures from simple spatial rules.
Despite differences in physical interpretation, both systems share a core structure: curved geometry meets layered slicing - and complexity emerges.
Our picture size is 400 pixels. We used a=1400a=\frac{1}{400}a=4001 for previous picture to fit the picture.
Here another pattern with a=1200a=\frac{1}{200}a=2001 :
| binary | continuous |
|---|---|
![]() |
![]() |
ccc modulates stretching along the yyy -axis
(we will use continuous patterns from now).
| c=2c=2c=2 | c=0.2c=0.2c=0.2 |
|---|---|
![]() |
![]() |
bbb introduces diagonal shear
| b=−1.5b=-1.5b=−1.5 | b=1.5b=1.5b=1.5 |
|---|---|
![]() |
![]() |
For b=0,c=−1,d=1b=0,c=-1,d=1b=0,c=−1,d=1 our equation becomes:
z=a(x2−y2)z=a(x^2-y^2)z=a(x2−y2)
This is a hyperbolic paraboloid - a surface with negative Gaussian curvature:
| a=1400a=\frac{1}{400}a=4001 | a=1200a=\frac{1}{200}a=2001 |
|---|---|
![]() |
![]() |
For b=0,c=1,d=1/5b=0, c=1, d=1/5b=0,c=1,d=1/5 our equation becomes:
z=a(x2+y2)1/5z=a(x^2+y^2)^{1/5}z=a(x2+y2)1/5
| a=1a=1a=1 | a=10a=10a=10 |
![]() |
![]() |
| a=100a=100a=100 | a=1000a=1000a=1000 |
![]() |
![]() |
The most interesting patterns are obtained if we take a ddd that differs slightly from 1. For example, for
b=0,c=1,d=11.01b=0, c=1, d=\frac{1}{1.01}b=0,c=1,d=1.011
| a=18258a=\frac{182}{58}a=58182 | a=173165a=\frac{173}{165}a=165173 |
![]() |
![]() |
| a=170109a=\frac{170}{109}a=109170 | a=11170a=\frac{111}{70}a=70111 |
![]() |
![]() |
| a=57178a=\frac{57}{178}a=17857 | a=186119a=\frac{186}{119}a=119186 |
![]() |
![]() |
b=1,c=1,d=11.01b=1, c=1, d=\frac{1}{1.01}b=1,c=1,d=1.011
| a=174111a=\frac{174}{111}a=111174 | a=50152a=\frac{50}{152}a=15250 |
![]() |
![]() |
Static Visualizationhologram_s.js
Dynamic Visualizationhologram_dynamic.js
Hologram Experimenthologram_reconstruction.html
This study began with a simple system: a billiard ball reflecting within a rectangular grid. By examining its trajectory and translating spatial behavior into symbolic sequences, we uncovered patterns exhibiting recursive structure, boundary self-similarity, and interference-like properties.
Through progressive abstraction - from 2D reflections to 1D symbolic sequences, and eventually to nonlinear surfaces - we showed that binary patterns can emerge from discretized irrational steps alone. Formulas such as:
Qk=⌊kx⌋ mod 2andQk=sin(πkx)>0Q_k=\left\lfloor k \sqrt{x} \right\rfloor \bmod 2 \quad \text{and} \quad Q_k=\sin\left( \pi k \sqrt{x} \right) > 0Qk=⌊kx⌋mod2andQk=sin(πkx)>0
generate deterministic sequences that yield quasi-fractal geometries when visualized spatially. Though entirely discrete, these systems exhibit behaviors commonly associated with continuous wave phenomena.
Further generalization using surface equations of the form:
z=a(x2+bxy+cy2)dz = a \left( x^2 + bxy + c y^2 \right)^dz=a(x2+bxy+cy2)d
reveals that curvature, shear, and nonlinearity shape the resulting symbolic slices in ways reminiscent of optical interference. The resemblance between these binary patterns and holographic textures suggests a structural parallel, despite their different origins.
No physical claims are made. However, the symbolic systems presented here demonstrate that simple integer-based operations, applied to irrational quantities or curved domains, can generate high-order structure with properties of both visual and mathematical interest. This offers a conceptual bridge between number theory, symbolic dynamics, and emergent spatial organization.
While this study has uncovered significant insights, several open questions remain to inspire further research:
GitHub repository: https://github.com/xcontcom/billiard-fractals
// Detect dark theme var iframe = document.getElementById('tweet-1941606569273155829-901'); if (document.body.className.includes('dark-theme')) { iframe.src = "https://platform.twitter.com/embed/Tweet.html?id=1941606569273155829&theme=dark" }
2025-11-28 11:02:45
The Artificial Intelligence landscape is in rapid flux, touching everything from hardware innovation to the very definition of intelligence and its impact on the global economy and workforce. This post serves as a technical primer on recent developments: