[Whitepaper] Awesome.AI: A Dynamics-Based Framework for Thought Simulation

Version: Prototype
Document Type: Technical White Paper (Draft)
Author: Joakim Jacobsen
Repository: https://github.com/copenhagen-ai
Website: https://www.copenhagen-ai.com
Note: This system is experimental and subjective by design.
1. Overview
1.1 Problem Statement
AI systems today utilises many different ML algorithms and frameworks. These, including state-of-the-art LLMs, are good at pattern recognition, they process input → output in mostly static fashion, but lack internal dynamics that simulate continuous thought. This framework produces that dynamics.
1.2 Project Goal
The Awesome.AI framework proposes a new computational way to simulate the dynamics of the mind, using concepts borrowed from classical and modern physics. It aims to:
Create a simulated thought as smooth and continuous as in a biological system
Simulate will, emotion and motivation using dynamics
Present a new approach and paradigm in AI (and Psychology)
1.3 What It Is
At its core, it is a decision engine, a highly autonomous agent. Does the thought go up or does it go down and from this more advanced systems emerge.
There are two ways to view this system:
as an agent built on the concept of competing micro-agents, called UNITs. Each UNIT represents a candidate thought that competes for becoming an actual thought.
as an infinite statemachine, UNITs being states and nonlinear or nondeterministic mechanics for navigating these states.
Other AI frameworks try to map every neuron in the brain, instead this framework maps entire networks(HUBs and UNITs) in the brain and uses dynamics to move between these networks.
2. Core Concepts
One can think of HUBs as the context/problems and UNITs as answers/solutions.
2.1 UNIT (Thought Node)
A UNIT is a single representation of a thought. It moves along the x-axis (UNIT-space).
interface Unit {
index: number; // Positional value between 0.0 and 100.0, along the x-axis (aka UNIT-space)
data: string; // Static or generated by ChatGpt according to index and HUB subject
credit: number; // Score between 0.0 and 10.0
ticket: string; // Used for matching UNIT with external object
}
A UNIT can in itself, be viewed as a micro-agent - Competing to become current UNIT and eventually an actual thought, by continuosly adjusting index.
In order to continuously better itself, the system dynamically adds and removes UNITs.
This means UNITs have width (ALPHA) around a point in UNIT-space. This area can be arbitrarily narrow, and therefore still adds up to an infinite number of UNITs.
NOTE: Alternatively UNITs can be viewed as states in an infinite statemachine governed by a nonlinear or nondeterministic overall framework.
2.2 HUB (Context Group)
A HUB is a collection of related UNITs, bound by a shared context.
interface Hub {
id: string;
subject: string; // (e.g., “work”, “having fun”, “friends”)
units: Unit[]; // can be empty
max_num_units: number;
}
3. Mechanics
The mechanics are metaphores for the dynamics of the mind. These are tested to be working, others may exist.
3.1 Mech Noise (Low Layer)
Pseudocode, see Appendix A
Uses: Newtons 2. law,
F = ma
, m <- car mass and a <- deduced from current UNIT indexThis was the base mech during the formation of the project.
Two cars connected by a rope or chain, they are going opposite directions and car one is dragging with a constant force, while car two is dragging with a variable force.
This produces the noise (momentum), centered around ~0.0, which is used in later mechs.
This simulates the Heart/Soul/Will of the system.
Friction
In order to calculate the friction of mech noise, the system uses the dynamic credits of UNIT, to find the friction coeficient.
Now the actual force for the mechanics can be calculated.
3.2 Mech One (High Layer)
Pseudocode, see Appendix B
Like Mech Noise, 2 cars connected by a rope or chain. Instead of oscilating around 0.0, the system here uses a Sine(time) + Noise from Mech One, to calculate the dynamics.
This is used for making and sending promtps to ChatGPT or other tasks.
3.3 Mech Two (High Layer)
Pseudocode, see Appendix C
This setup simulates a ball balancing on top of a hill. The ball can go down the sides. The hill can be more or less steep. By pushing the ball up the hill, the game is to keep it from falling down the sides.
Like Mech One the system uses a Sine(time) + Noise to produce the dynamics, for sending promtps to ChatGPT or other tasks.
Terrain Expansion (Planned Feature)
- In later versions of the system, one can imagine entire landscapes of hills and valleys.
3.4 Mech Three (Source Only)
Here the setup simulates a rocket trying to "leave orbit" of a black hole. The system calculates momentum and opposing forces.
Its only in source, because of the complexity of the numbers being much greater in a setup like this.
Common Pattern in All Mechanics:
- The similarities for these mechanics, are that there is a static force dragging one direction and a variable force dragging or pushing the other way. ie. the car with a constant pressure on the the pedal (Mech One) and gravity (Mech Two, Mech Three).
From these mechanics the system gets a momentum, and if the momentum is increasing, the thought goes up and decreasing the thought goes down.
4. Dataflow, Layers and Algorithm
4.1 Dataflow
The system operates in a feedforward architecture:
Mech Noise (Low Layer)
↓
Current UNIT
↓
→ Mech One → Thoughtpattern/Mood Index → Prompt A
→ Mech Two → Thoughtpattern/Mood Index → Prompt B
→ Mech Three → Thoughtpattern/Mood Index → Prompt C
- The dataflow between the two running mechanics is FeedForward. Meaning that the lower layer (mech noise) is feeding its output (current unit) into the higher layer (mech one or two). Higher layers does not produce a current unit. This makes it a feed forward dataflow between the two layers.
4.2 Layers and Thoughtpatterns
- Higher layers produces thoughtpatterns. These are just versions of a given mech. Like is the Sine going from -1 to 1 (GENERAL), 0 to 1 (GOOD) or -1 to 0 (BAD). This is used to produce the mood of the system.
4.3 Overall Algorithm
It is build on the notion: many (eg. 500) impressions, produces one thought.
// this pseodocode is conceptual
Initialize system state
For i = 1 to N:
Apply Mechanics (noise) + friction
Apply filters (credit, direction, lowcut)
Find current UNIT
Return most frequently selected UNIT
Repeat From Top
- After N iterations, it finds the statistically dominant UNIT. Which is then considered "the actual thought"
5. Filters, Selection and Internal State
Pseudocode, see Appendix D
Pseudocode, see Appendix E
5.1 Filters
the three main filters are:
Direction
- Removes UNITs not aligned with the current direction.
Credit
Prevents overuse of any single UNIT.
Credit is continuesly updated.
Credit must be > 1.0 for a UNIT to be valid in UNIT-space.
Current UNITs credit reduces (fast) and refills when not "current UNIT" (slow).
LowCut
Removes the heaviest UNITs from selection (UNIT-space).
This can be used to hide certain UNITs.
Hidden UNITs are not subconcious thoughts, but lowcutted possible thoughts. Meaning, currently (long term) not available to the system.
The idea of this dynamics was such a thought/UNIT.
5.2: Selection Of Current Unit
After applying filters, the current UNIT is selected by:
determining a point (near) in opposite end of UNIT-space, that current UNIT should jump to, in order to balance the mechanics
determining "near": near = 100.0 - Normalize(momentum, 100)
selecting, from valid UNIT-space, the UNIT closest to "near"
5.3: Handling Internal State
Initially UNITs are scattered randomly across UNIT-space.
While selecting current UNIT, the state of UNIT-space is also updated.
Add UNIT
- if criterias are met, the system adds a new UNIT in an arbitrarily narrow area (ALPHA) around "near"
Criterias are:
number of UNITs in HUB is less than HUB.max_num_units
distance from near to (newly) selected UNIT is more than avarage distance (100.0 / HUB.units count)
Remove UNIT:
- the system removes all UNITs in an arbitrarily narrow area (ALPHA) around "near"
Adjust Index:
- updates current UNITs index by: MyRandomDouble * ETA * direction
6. The Hack, Down and the Quantum Connection
Pseudocode, see Appendix F
6.1 Background
Down is an enum (YES/NO) representation of direction.
The meaning of Down, is that the system say/decides No or Yes to going down.
6.2 Changing Direction
Since the beginning of the project, the system used a "hack", where the flip of direction, was done only for best performance. This hack has now been removed and replaced by these options.
These only apply to Low Level (Mech Noise). MyQuantumXOR connects the Awesome.AI agent with another simpler agent.
When delta momentum is below 0.0, direction is true.
Mode | Description |
Classical (legacy, valid or logic error?) | The system flips the value (changes direction). This produces the noise. |
Probabilistic | Uses momentum to calculate a probability for flipping the value (changing direction). |
Quantum (Experimental) | Uses a Qubit-like XOR of two agents: MyQuantumXOR(awesome_agent.direction, simple_agent.direction) |
6.3 Variants of Down
HARD
A binary value, is delta momentum above or below 0.0:
Range: YES, NO
FUZZY
A fuzzy value, based on the value and interval of delta momentum:
Range: ← VERYNO | NO | MAYBE | YES | VERYYES →
PERIOD
Evaluates a series of HARD Downs (e.g., past 100 steps) to determine trend.
7. Prompt Generation / Monologue
The monologue has two modes, the default is deterministic.
7.1 Deterministic Mode
This mechanism uses static texts.
The texts are chosen based on current mood-index and HUB-subject.
If texts are positive or negative, they are combined with "..and..", if different then "..but.." - (XNOR).
This produces the flow in the monologue.
7.2 Fluent Mode (via ChatGPT)
GPT (or similar) generates two sentences from mood-index and HUB-subject.
Plays "Connect the Dots" with GPT (or similar) to combine them into a more natural, emotionally-toned output.
Can express nuance and variation via prompt design.
This produces the flow in the monologue.
8. Decisions
These are some of the ways decisions are made within the system. The answers are stored in the data field of current UNIT. Both versions has a UNIT, that starts the process - either by HUB subject or by setting system state to QUICKDECISION. Decisions are used, fx. when Awesome.AI starts and answers chat conversations.
8.1 Quick
Quick decisions are made within an epoch (~500 cycles or less)
Activates system state
QUICKDECISION
Clears UNIT-space and injects a number of
QUICKDECISION
UNITsRemoves
QUICKDECISION
UNITs as they are visitedReturns a binary Yes/No decision
8.2 Long
- Run across multiple epochs, with two possible solution paths:
State 1:
Solution 1: depending on current UNIT data, return a Yes/No answer
Solution 2: depending on current UNIT data, proceed to next state or decline
State 2:
- Solution 2: if DOWN = No, return current UNIT data. If DOWN = Yes decline.
9. Occupation and UNIT-space
INFO: This section is optional and non-essential to core framework*.*
INFO: the system produces a MyRandom, which is used for this feature.
What has been described so far is the core of the framework. The core is focused on a fixed UNIT-space, but with occupation (-of the mind), UNIT-space is divided into portions of valid UNITs, thereby letting the system have trails of thought.
Occupation defines a named mental activity with a list of HUBs:
interface Occupation {
name: string; // what is the systems current occupation
max_epochs: number; // a number indicating how many epochs (max) is spend on this Occupation
hubs: Hub[]; // a list of HUBs associated with this Occupation
}
9.1 Internal Occupation
uses
MyRandom
to pick a number below max_epochsuses
MyRandom
to pick a Occupationfor a unit to be valid, it checks if current UNIT->HUB is contained in current Occupation values, this determines if the UNIT show up in UNIT-space
9.2 External Occupation
To be valid in UNIT-space, a simple tag/ticket matching feature has been implemented.
External objects are decorated with a tag (e.g., like a HUB subject)
UNITs are valid in UNIT-space only if their ticket matches the external tag
10. Limitations
No consciousness (only dynamics)
No memory (or less than seconds)
No feeling; but some simulated basic emotion/thoughtpatterns
No free will; but the illusion of free will. ie. the heaviest UNITs are LowCutted, the system therefore cannot "recognize" the pattern. Hence the illusion of free will.
Prompt output quality - for monologue - is highly sensitive to HUB naming and grouping
11. Implications and Final Thoughts
The biggest problem is..
the idea is quite obvious, but hasn’t been tried implemented before
what has been holding this idea back, is it was a lowcutted thought
should this idea remain hidden?
is the idea generel or specific to my thought?
the outcome may be, that we define the physical laws of the world and this simulation
this setup only needs validation for the idea to be correct?
12. Mentions
12.1 Mechanics Additions
Mechanic | Extreme Behavior |
Mech One / Two | Position → 0.0 → Perceived experience → ∞ (emotional singularity*) |
Mech One / Two (alternative) | Position → 0.0 → Perceived experience → 0.0, y0 or ∞ (emotional singularity**) |
Mech Three | Position → Schwarzschild Radius (Rs) → Time Dilation → 0.0 |
* pain (my speculation); physical or emotional, could be enlightenment or truth
* could be a transition to a new state
** the dependent of position could be defined by the system itself, could serve as a motivation factor
These limits model extreme internal experiences (transcendence, shutdown, insight, recursion collapse). They form the edge cases of mental simulation within this framework.
12.2 Additional
what drives the system, is trying to solve the "error" introduced in THE HACK. Also, maybe this "error" can be made more complex and thereby breaking the limited UP/DOWN motion.
the system produces a random number, from momentum.
maybe the definition for this system is not "a dynamics of the mind, but rather "a dynamics of the will of the mind".
this is my subjective vision of how the dynamics of the mind should be modelled.
this is a prototype.. and therefore not the final version.
13. Glossary
Term | Description |
UNIT | Individual data node representing a thought or decision |
HUB | Persistent container grouping UNITs by theme or problem space |
Mech Noise | Core mechanic producing oscillating dynamics (soul/will) |
Delta Momentum | Change in system movement that guides directional transitions |
LowCut | Filter removing most "massive" thoughts temporarily |
Credit | A decay-based score regulating UNIT reuse |
Mood Index | Value derived from sine wave + dynamics; guides emotional tone |
14. Appendix
Appendix A
- Pseudocode: Mech Noise
function Peek(curr):
Calc(curr, true, -1)
peek_norm ← mind.calc.normalize(peek_momentum, m_out_low_p, m_out_high_p, 0.0, 100.0)
function Calc(curr, peek, cycles):
if cycles = 1:
Reset()
deltaT ← 0.02
m ← 500.0
N ← m * CONST.GRAVITY
F_static ← ApplyStatic()
F_dynamic ← ApplyDynamic(curr)
u ← Friction(curr.credits, -2.0)
F_friction ← u * N
F_net ← -F_static + F_dynamic + (F_friction * -Sign(-F_static + F_dynamic))
delta_vel ← (F_net * deltaT) / m
if peek:
peek_momentum ← p_prev + (m * 2) * delta_vel
else:
d_prev ← d_curr
d_curr ← (m * 2) * delta_vel
p_prev ← p_curr
p_curr ← p_curr + d_curr
if peek_momentum ≤ m_out_low_p: m_out_low_p ← peek_momentum
if peek_momentum > m_out_high_p: m_out_high_p ← peek_momentum
if p_curr ≤ m_out_low_n: m_out_low_n ← p_curr
if p_curr > m_out_high_n: m_out_high_n ← p_curr
if d_curr ≤ d_out_low: d_out_low ← d_curr
if d_curr > d_out_high: d_out_high ← d_curr
function ApplyStatic():
acc ← CONST.MAX / 10
m ← 500.0
F_applied ← m * acc
if F_applied ≤ 0.0:
F_applied ← 0.0
return F_applied
function ApplyDynamic(curr):
if curr.is_null():
throw "ApplyDynamic"
max ← CONST.MAX
val ← curr.variable
acc ← (max - val) / 10.0
m ← 500.0
if acc ≤ 0.0:
acc ← 0.0
F_applied ← m * acc
if F_applied ≤ 0.0:
F_applied ← 0.0
return F_applied
function Friction(credits, shift):
c ← 10.0 - credits
x ← 5.0 - c + shift
friction ← mind.calc.logistic(x)
return friction
Appendix B
- Pseudocode: Mech One
variable velocity ← 0.0
variable position_x ← 5.0
function Calc(pattern, cycles):
if cycles = 1:
Reset()
Fmax ← 5000.0, omega ← 2 * π * 0.5, eta ← 0.5, m1 ← 300.0, m2 ← 300.0, total_mass ← m1 + m2, dt ← 0.1
mu ← 0.1
g ← CONST.GRAVITY
friction_force ← mu * total_mass * g
t ← cycles * dt
F_static ← ApplyStatic(Fmax)
F_dynamic ← ApplyDynamic(pattern, Fmax, t, omega, eta)
friction ← friction_force * Sign(velocity) // Opposes motion
F_net ← -F_static + F_dynamic - friction
if |F_net| < friction_force AND |velocity| < 0.01:
F_net ← 0
velocity ← 0
acceleration ← F_net / total_mass
velocity ← velocity + acceleration * dt
position_x ← position_x + velocity * dt
p_prev ← p_curr
p_curr ← total_mass * velocity
d_curr ← p_curr - p_prev
if p_curr ≤ m_out_low_c: m_out_low_c ← p_curr
if p_curr > m_out_high_c: m_out_high_c ← p_curr
if d_curr ≤ d_out_low: d_out_low ← d_curr
if d_curr > d_out_high: d_out_high ← d_curr
function GetRandomNoise():
curr_unit ← mind.unit_noise
if curr_unit = null:
throw "TugOfWar, GetRandomNoise"
var ← curr_unit.variable
return Normalize(var, 0.0, 100.0, -1.0, 1.0)
function Sine(pattern, t, omega):
switch pattern:
case PATTERN.MOODGENERAL:
return (sin(omega * t) + 1.0) / 2.0
case PATTERN.MOODGOOD:
return 0.6 + ((sin(omega * t) + 1.0) / 2.0 * 0.4)
case PATTERN.MOODBAD:
return ((sin(omega * t) + 1.0) / 2.0 * 0.4)
default:
throw "TugOfWar, Sine"
function ApplyStatic(Fmax):
F_applied ← Fmax * CONST.BASE_REDUCTION
return F_applied
function ApplyDynamic(pattern, Fmax, t, omega, eta):
if mind.goodbye.is_yes():
return 0.0
F_applied ← Fmax * (Sine(pattern, t, omega) + eta * GetRandomNoise())
return F_applied
Appendix C
- Pseudocode: Mech Two
variable velocity ← 0.0
variable position_x ← CONST.STARTXY
function Calc(pattern, cycles):
if cycles = 1:
Reset()
a ← 0.1 // Hill steepness (parabola coefficient)
g ← CONST.GRAVITY // Gravity
F0 ← 5.0 // Wind force amplitude
omega ← π // Wind frequency
beta ← 0.02 // Friction coefficient
dt ← 0.1 // Time step
eta ← 0.5 // Random noise amplitude
m ← 0.35 // Ball mass
t ← cycles * dt
Fx ← ApplyDynamic(pattern, omega, t, F0, eta) // Wind force
F_gravity ← ApplyStatic(m, g, a, position_x) // Gravity along slope
F_friction ← -beta * velocity // Friction opposes motion
a_tangent ← (F_gravity + Fx + F_friction) / m // Net acceleration along slope
velocity ← velocity + a_tangent * dt
position_x ← position_x + velocity * dt
p_prev ← p_curr
p_curr ← m * velocity
d_curr ← p_curr - p_prev
if p_curr ≤ m_out_low_c: m_out_low_c ← p_curr
if p_curr > m_out_high_c: m_out_high_c ← p_curr
if d_curr ≤ d_out_low: d_out_low ← d_curr
if d_curr > d_out_high: d_out_high ← d_curr
function GetRandomNoise(noise_amplitude):
curr_unit ← mind.unit_noise
if curr_unit = null:
throw "ApplyDynamic"
var ← curr_unit.variable
rand ← Normalize(var, 0.0, 100.0, -1.0, 1.0)
return rand * noise_amplitude // Range [-amplitude, amplitude]
function Sine(pattern, t, omega):
switch pattern:
case PATTERN.MOODGENERAL:
return (sin(omega * t) + 1.0) / 2.0
case PATTERN.MOODGOOD:
return 0.5 + ((sin(omega * t) + 1.0) / 2.0 * 0.5)
case PATTERN.MOODBAD:
return ((sin(omega * t) + 1.0) / 2.0 * 0.5)
default:
throw "BallOnHill, Sine"
function ApplyStatic(m, g, a, x):
slope ← 2 * a * x
sin_theta ← slope / sqrt(1 + slope²)
F_gravity ← -(m * g) * sin_theta
return F_gravity
function ApplyDynamic(pattern, omega, t, F0, eta):
if mind.goodbye.is_yes():
return 0.0
Fx ← F0 * Sine(pattern, t, omega) + GetRandomNoise(eta)
if Fx < 0.0:
Fx ← 0.0
return Fx
Appendix D
- Pseudocode: UpdateCredit
function UpdateCredit():
if mind.z_current ≠ "z_noise":
return
if mind.unit_current.is_quick_decision():
return
list ← mind.mem.units_all()
for each u in list:
if u.is_quick_decision():
continue
if u.root = mind.unit_current.root:
continue
cred ← mind.parms_current.update_cred
u.credits ← u.credits + cred
if u.credits > CONST.MAX_CREDIT:
u.credits ← CONST.MAX_CREDIT
mind.unit_current.credits ← mind.unit_current.credits - 1.0
if mind.unit_current.credits < CONST.LOW_CREDIT:
mind.unit_current.credits ← CONST.LOW_CREDIT
Appendix E
- Pseudocode: Internal State
function UpdateUnit(current_unit, unit_above, unit_below):
if unit_above = null OR unit_below = null:
return
// Only noise can update unit
if mind.z_current ≠ "z_noise":
return
parm ← mind.parms_current
idx_sign ← (parm.high_at_zero ? -1 : 1)
add_sign ← (current_unit = unit_below ? 1 : -1)
near ← NearPercent()
dist ← DistAbsolute(current_unit, near)
Update(current_unit, idx_sign, add_sign, near, dist)
function Map(unit):
mech ← mind.mech["z_noise"]
mech.peek(unit)
norm ← mech.peek_norm
return norm
function NearPercent():
norm ← 100.0 - mind.mech_current.p_100
return norm
function DistAbsolute(unit, near):
var ← Map(unit)
res ← |var - near|
return res
function Update(unit, idx_sign, add_sign, near, dist):
if NOT CONST.ACTIVATOR.random_sample(mind):
return
if Add(unit, near, dist):
return
Remove(unit, near)
Adjust(unit, idx_sign, add_sign, dist)
function Add(unit, near, dist):
count ← unit.HUB.units.count
max ← unit.HUB.max_num_units
avg ← 100.0 / count
if count > max:
return false
if dist < avg:
return false
low ← (near - CONST.ALPHA ≤ CONST.MIN ? CONST.MIN : near - CONST.ALPHA)
high ← (near + CONST.ALPHA ≥ CONST.MAX ? CONST.MAX : near + CONST.ALPHA)
mind.mem.units_add(unit, low, high)
return true
function Remove(unit, near):
low ← near - CONST.ALPHA
high ← near + CONST.ALPHA
mind.mem.units_rem(unit, low, high)
function Adjust(unit, idx_sign, add_sign, dist):
if dist < CONST.ALPHA:
return
rand ← mind.rand.my_random_double
unit.index ← Index + (rand * CONST.ETA * add_sign * idx_sign)
if unit.index ≤ CONST.MIN: unit.index ← CONST.MIN
if unit.index ≥ CONST.MAX: unit.index ← CONST.MAX
Appendix F
- Pseudocode: The Hack
agent ← new SimpleAgent()
down1 ← deltaMomentum ≤ 0.0
down2 ← agent.SimulateDown()
switch CONST.Logic:
case CLASSICAL:
down1 ← not down1
case PROBABILITY:
down1 ← Probability(down1, momentum)
case QUBIT:
down1 ← MyQuantumXOR(down1, down2)
return HARDDOWN.YES if down1 else HARDDOWN.NO
Subscribe to my newsletter
Read articles from Joakim Jacobsen directly inside your inbox. Subscribe to the newsletter, and don't miss out.
Written by
