CBD model is computing Fibonacci numbers! :)

This commit is contained in:
Joeri Exelmans 2024-11-07 15:38:13 +01:00
parent 9c68b288c1
commit 80cba4b9f8
27 changed files with 429 additions and 269 deletions

View file

@ -1,7 +1,7 @@
# Adder, two inputs, one output
adder:Function {
func = ```
n2_out = n0_in + n1_in
read('n0_in') + read('n1_in')
```;
}
n0_in:InPort

View file

@ -1,9 +1,13 @@
# Initial state for both delay blocks:
d0s:State {
state = 0;
x = 0;
}
d1s:State {
state = 1;
x = 1;
}
:delay2State (d0 -> d0s)
:delay2State (d1 -> d1s)
clock:Clock {
time = 0;
}

View file

@ -2,12 +2,8 @@ Block:Class {
abstract = True;
}
InPort:Class {
# abstract = True;
}
OutPort:Class {
# abstract = True;
}
InPort:Class
OutPort:Class
hasInPort:Association (Block -> InPort) {
# Every Port contained by exactly one Block:
@ -21,27 +17,12 @@ hasOutPort:Association (Block -> OutPort) {
}
link:Association (OutPort -> InPort) {
#abstract = True;
# Every InPort connected to exactly one OutPort
source_lower_cardinality = 1;
source_upper_cardinality = 1;
}
# In- and Out-Ports are labeled:
# hasInPort_label:AttributeLink (hasInPort -> String) {
# name = "label";
# optional = False;
# }
# hasOutPort_label:AttributeLink (hasOutPort -> String) {
# name = "label";
# optional = False;
# }
# Function Block: pure function that computes outputs based on inputs
Function:Class
@ -69,61 +50,9 @@ Delay:Class {
num_outports = len(get_outgoing(this, "hasOutPort"))
if num_inports != 1:
errors.append(f"Delay block must have one inport, instead got {num_inports}")
in_type = None
else:
in_type = get_type_name(get_target(get_outgoing(this, "hasInPort")[0]))
if num_outports != 1:
errors.append(f"Delay block must have one inport, instead got {num_outports}")
out_type = None
else:
out_type = get_type_name(get_target(get_outgoing(this, "hasOutPort")[0]))
# if in_type != None and out_type != None and in_type[0:3] != out_type[0:3]:
# errors.append(f"Inport type ({in_type}) differs from outport type ({out_type})")
errors
```;
}
:Inheritance (Delay -> Block)
# Object Diagrams are statically typed, so we must create in/out-ports, and MemorySlots for all primitive types:
# # Port types
# BoolInPort:Class
# IntInPort:Class
# StrInPort:Class
# BoolOutPort:Class
# IntOutPort:Class
# StrOutPort:Class
# :Inheritance (BoolInPort -> InPort)
# :Inheritance (IntInPort -> InPort)
# :Inheritance (StrInPort -> InPort)
# :Inheritance (BoolOutPort -> OutPort)
# :Inheritance (IntOutPort -> OutPort)
# :Inheritance (StrOutPort -> OutPort)
# # Link types
# boolLink:Association (BoolOutPort -> BoolInPort)
# intLink:Association (IntOutPort -> IntInPort)
# strLink:Association (StrOutPort -> StrInPort)
# :Inheritance (boolLink -> link)
# :Inheritance (intLink -> link)
# :Inheritance (strLink -> link)
# # Delay block types
# BoolDelay:Class
# IntDelay:Class
# StrDelay:Class
# :Inheritance (BoolDelay -> Delay)
# :Inheritance (IntDelay -> Delay)
# :Inheritance (StrDelay -> Delay)

View file

@ -1,85 +1,47 @@
# Link state ("signal")
Signal:Class {
# abstract = True;
}
Signal:Class
Signal_signal:AttributeLink (Signal -> Integer) {
name = "signal";
Signal_x:AttributeLink (Signal -> Integer) {
name = "x";
optional = False;
}
hasSignal:Association (link -> Signal) {
hasSignal:Association (OutPort -> Signal) {
# every Signal has 1 link
source_lower_cardinality = 1;
source_upper_cardinality = 1;
# every link has 0..1 Signals:
target_upper_cardinality = 1;
}
# BoolSignal:Class
# IntSignal:Class
# StrSignal:Class
# :Inheritance (BoolSignal -> Signal)
# :Inheritance (IntSignal -> Signal)
# :Inheritance (StrSignal -> Signal)
# BoolSignal_signal:AttributeLink (BoolSignal -> Boolean) {
# name = "signal";
# optional = False;
# }
# IntSignal_signal:AttributeLink (IntSignal -> Integer) {
# name = "signal";
# optional = False;
# }
# StrSignal_signal:AttributeLink (StrSignal -> String) {
# name = "signal";
# optional = False;
# }
# Delay block state
# mandatory - otherwise we cannot determine the output signal of a delay block
State:Class {
# abstract = True;
}
State:Class
State_state:AttributeLink (State -> Integer) {
name = "state";
State_x:AttributeLink (State -> Integer) {
name = "x";
optional = False;
}
delay2State:Association (Delay -> State) {
# one-to-one
source_lower_cardinality = 1;
source_upper_cardinality = 1;
target_lower_cardinality = 1;
target_upper_cardinality = 1;
}
# BoolState:Class
# IntState:Class
# StrState:Class
Clock:Class {
lower_cardinality = 1;
upper_cardinality = 1;
}
# :Inheritance (BoolState -> State)
# :Inheritance (IntState -> State)
# :Inheritance (StrState -> State)
# BoolState_state:AttributeLink (BoolState -> Boolean) {
# name = "state";
# optional = False;
# }
# IntState_state:AttributeLink (IntState -> Integer) {
# name = "state";
# optional = False;
# }
# StrState_state:AttributeLink (StrState -> String) {
# name = "state";
# optional = False;
# }
Clock_time:AttributeLink (Clock -> Integer) {
name = "time";
optional = False;
}

View file

@ -0,0 +1,3 @@
clock:RAM_Clock {
RAM_time = `True`;
}

View file

@ -0,0 +1,36 @@
# If there is a Delay-block whose input signal differs from its state, we cannot yet advance time:
delay:RAM_Delay
delay_in:RAM_InPort
delay_has_input:RAM_hasInPort (delay -> delay_in)
some_outport:RAM_OutPort
delay_in_conn:RAM_link (some_outport -> delay_in)
in_signal:RAM_Signal
port_has_signal:RAM_hasSignal (some_outport -> in_signal)
state:RAM_State {
RAM_x = `get_slot_value(matched('in_signal'), 'x') != get_value(this)`;
}
delay_to_state:RAM_delay2State (delay -> state)
# Also, we cannot advance time until all outports have signals:
:GlobalCondition {
condition = ```
missing_signals = False
for _, outport in get_all_instances("OutPort"):
if len(get_outgoing(outport, 'hasSignal')) == 0:
missing_signals = True
break
missing_signals
```;
}

View file

@ -0,0 +1,10 @@
clock:RAM_Clock {
RAM_time = `get_value(this) + 1`;
}
:GlobalCondition {
condition = ```
for _, signal in get_all_instances("Signal"):
delete(signal)
```;
}

View file

@ -0,0 +1,27 @@
# We look for a Delay-block, its inport connected to an outport that has a signal
delay:RAM_Delay
delay_in:RAM_InPort
delay_has_input:RAM_hasInPort (delay -> delay_in)
some_outport:RAM_OutPort
delay_in_conn:RAM_link (some_outport -> delay_in)
in_signal:RAM_Signal
port_has_signal:RAM_hasSignal (some_outport -> in_signal)
# State of Delay block... (will be updated in RHS)
state:RAM_State {
# Attention: you MUST match the existing attribute, in order to force an UDPATE of the attribute, rather than CREATION
RAM_x = `True`;
}
delay_to_state:RAM_delay2State (delay -> state)

View file

@ -0,0 +1,6 @@
state:RAM_State # <- must repeat elements from LHS that we refer to
in_signal:RAM_Signal {
# If the signal is already equal to the state, the NAC holds:
RAM_x = `get_value(this) == get_slot_value(matched('state'), 'x')`;
}

View file

@ -0,0 +1,26 @@
# Everything from our LHS (don't delete anything)
delay:RAM_Delay
delay_in:RAM_InPort
delay_has_input:RAM_hasOutPort (delay -> delay_in)
some_outport:RAM_OutPort
delay_in_conn:RAM_link (some_outport -> delay_in)
in_signal:RAM_Signal
port_has_signal:RAM_hasSignal (some_outport -> in_signal)
state:RAM_State {
# Update:
RAM_x = ```
new_state = get_slot_value(matched('in_signal'), 'x')
print(f"Updating delay {get_name(matched('delay'))} state: {new_state}")
new_state
```;
}
delay_to_state:RAM_delay2State (delay -> state)

View file

@ -1,16 +0,0 @@
# We look for a Delay-block, its outgoing connection, and its State
delay:RAM_Delay
delay_out:RAM_OutPort # abstract
delay_has_output:RAM_hasOutPort (delay -> delay_out)
some_inport:RAM_InPort # abstract
delay_out_conn:RAM_link (delay_out -> some_inport)
state:RAM_State
delay_to_state:RAM_delay2State (delay -> state)

View file

@ -1,14 +0,0 @@
# From our LHS:
delay_out:RAM_OutPort # abstract
some_inport:RAM_InPort # abstract
delay_out_conn:RAM_link (delay_out -> some_inport) # abstract
# The delay block's outgoing connection already has a signal:
some_signal:RAM_Signal
:RAM_hasSignal (delay_out_conn -> some_signal)

View file

@ -0,0 +1,14 @@
# We look for a Delay-block, its outport, and its State
delay:RAM_Delay
delay_out:RAM_OutPort
delay_has_output:RAM_hasOutPort (delay -> delay_out)
state:RAM_State
delay_to_state:RAM_delay2State (delay -> state)
clock:RAM_Clock

View file

@ -0,0 +1,10 @@
# From our LHS:
delay_out:RAM_OutPort
# We don't want to see the delay block's outport already having a signal:
some_signal:RAM_Signal
:RAM_hasSignal (delay_out -> some_signal)

View file

@ -0,0 +1,20 @@
# Our entire LHS (don't delete anything):
delay:RAM_Delay
delay_out:RAM_OutPort
delay_has_output:RAM_hasOutPort (delay -> delay_out)
state:RAM_State
delay_to_state:RAM_delay2State (delay -> state)
clock:RAM_Clock
# To create:
new_signal:RAM_Signal {
RAM_x = `get_slot_value(matched('state'), 'x')`;
}
:RAM_hasSignal (delay_out -> new_signal)

View file

@ -1,23 +0,0 @@
# Our entire LHS (don't delete anything):
delay:RAM_Delay
delay_out:RAM_OutPort # abstract
delay_has_output:RAM_hasOutPort (delay -> delay_out)
some_inport:RAM_InPort # abstract
delay_out_conn:RAM_link (delay_out -> some_inport) # abstract
state:RAM_State
delay_to_state:RAM_delay2State (delay -> state)
# To create:
new_signal:RAM_Signal {
RAM_signal = `get_slot_value(match('state'), 'state')`;
}
:RAM_hasSignal (delay_out_conn -> new_signal)

View file

@ -0,0 +1,22 @@
# Match function and its out-connection
f:RAM_Function {
# Only match if the signal of all inputs has been computed:
condition = ```
ok = True
for o in get_outgoing(this, "hasInPort"):
inport = get_target(o)
in_conn = get_incoming(inport, "link")[0]
some_outport = get_source(in_conn)
if len(get_outgoing(some_outport, "hasSignal")) == 0:
ok = False
break
ok
```;
}
f_outport:RAM_OutPort
f_has_outport:RAM_hasOutPort (f -> f_outport)
clock:RAM_Clock

View file

@ -0,0 +1,14 @@
# From our LHS:
f:RAM_Function
f_outport:RAM_OutPort
f_has_outport:RAM_hasOutPort (f -> f_outport)
# We don't want to see the function's out-connection already having a signal:
some_signal:RAM_Signal
:RAM_hasSignal (f_outport -> some_signal)

View file

@ -0,0 +1,26 @@
# Our entire LHS (don't delete anything):
f:RAM_Function
f_outport:RAM_OutPort
f_has_outport:RAM_hasOutPort (f -> f_outport)
clock:RAM_Clock
# To create:
f_out_signal:RAM_Signal {
RAM_x = ```
def read(inport_name):
inport = get(inport_name)
outport = get_source(get_incoming(inport, "link")[0])
signal = get_target(get_outgoing(outport, "hasSignal")[0])
return get_slot_value(signal, "x")
code = get_slot_value(matched('f'), 'func')
eval(code, {}, { 'read': read })
```;
}
:RAM_hasSignal (f_outport -> f_out_signal)