Skip to content

Commit

Permalink
Merge pull request #164 from Phuire-Research/UI
Browse files Browse the repository at this point in the history
Experimental: Plan Beats
  • Loading branch information
REllEK-IO authored Nov 28, 2023
2 parents 11df453 + ca4f927 commit e7825ac
Show file tree
Hide file tree
Showing 4 changed files with 103 additions and 9 deletions.
5 changes: 5 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,11 @@ User Interface Proof of Concept and Demo: [logixUX](https://github.com/Phuire-Re
*Note if you notice a strange any capitalization, this is a new format that is being formalized as conceptual logic. Where we capitalize not just people, places, and things, but concepts as well. In addition, there was no generative intelligence used in the creation of this framework or documentation. This is **100% hand written.***

## Change Log ![Tests](https://github.com/Phuire-Research/Stratimux/actions/workflows/node.js.yml/badge.svg)
### 11/27/23
* Added a new experimental parameter to staging. Beat, which is a duration that will "Throttle and debounce," state notifications to that specific plan.
*Note: This becomes necessary to set once your application grows in complexity. As the fundamental issue with graph programming, is that at a sufficient scale. You are fighting your computers branch prediction. You can think of the run time of Stratimux like a balloon. In theory as long as your logic is clean, you shouldn't run into race conditions. But the unfortunate truth is that the more logic that your balloon if filled with. The higher likelihood your balloon will pop. So to avoid this, you need to supply a beat to complex plans that might overinflate your balloon.*

*This is counter intuitive to most programming, but is the trade off for this new dynamic paradigm. As computers have been designed for transactional object oriented programming. This paradigm moves beyond that comfortable scale of complexity and reveals the generally good enough design of the computers we rely upon. Funny to say that you can write by hand a program that hallucinates. **hint** **hint***
### 11/26/23
* Updated naming conventions throughout. Counter is now CounterState. Strategies now export with their associated concept's prepended.
* Added parsing tokens. If curious about this functionality see the logixUX project. These tokens in combination with that project will upon its release. Allow for the ease of parsing Stratimux or other TypeScript projects into high quality training data.
Expand Down
2 changes: 1 addition & 1 deletion package.json
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
{
"name": "stratimux",
"license": "GPL-3.0",
"version": "0.0.75",
"version": "0.0.76",
"description": "Unified Turing Machine",
"main": "dist/index.js",
"module": "dist/index.mjs",
Expand Down
41 changes: 33 additions & 8 deletions src/model/stagePlanner.ts
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,9 @@ export type Plan = {
stages: Staging[],
stage: number;
stageFailed: number;
beat: number;
offBeat: number;
timer: NodeJS.Timeout[]
}

export type NamedStagePlanner = {
Expand Down Expand Up @@ -200,13 +203,14 @@ export class UnifiedSubject extends Subject<Concepts> {
private planId = 0;
private currentStages: Map<number, Plan> = new Map();
private stageDelimiters: Map<number, StageDelimiter> = new Map();
private concepts: Concepts = {};
constructor() {
super();
}
stage(title: string, stages: Staging[]): StagePlanner {
stage(title: string, stages: Staging[], beat?: number): StagePlanner {
const planId = this.planId;
this.planId++;
this.currentStages.set(planId, {title, stages, stage: 0, stageFailed: -1});
this.currentStages.set(planId, {title, stages, stage: 0, stageFailed: -1, beat: beat ? beat : -1, offBeat: -1, timer: []});
const conclude = () => {
this.currentStages.delete(planId);
};
Expand Down Expand Up @@ -287,28 +291,49 @@ export class UnifiedSubject extends Subject<Concepts> {
}

next(value: Concepts) {
const concepts = {
this.concepts = {
...value
};
if (!this.closed) {
// Need a Stage Observer that would merely deconstruct to {concepts: Concepts , dispatch: Dispatcher}
// Where Dispatcher would be (action$: Subject<Action>) => {}();
const axiumState = value[0].state as AxiumState;
this.currentStages.forEach((plan, key) => {
const dispatcher: Dispatcher = (action: Action, options: dispatchOptions) => {
this._dispatch(axiumState, key, plan, concepts, action, options);
};
const index = plan.stage;
if (index < plan.stages.length) {
plan.stages[index](concepts, dispatcher);
const timer = plan.timer;
const now = Date.now();
if (plan.beat > -1) {
if (plan.offBeat < now) {
plan.offBeat = Date.now() + plan.beat;
const dispatcher: Dispatcher = (action: Action, options: dispatchOptions) => {
this._dispatch(axiumState, key, plan, this.concepts, action, options);
};
plan.stages[index](this.concepts, dispatcher);
} else if (timer.length === 0 && plan.offBeat > now) {
timer.push(setTimeout(() => {
plan.timer = [];
plan.offBeat = Date.now() + plan.beat;
const dispatcher: Dispatcher = (() => (action: Action, options: dispatchOptions) => {
this._dispatch(axiumState, key, plan, this.concepts, action, options);
}).bind(this)();
plan.stages[index](this.concepts, dispatcher);
}, plan.offBeat - Date.now()));
}
} else {
const dispatcher: Dispatcher = (action: Action, options: dispatchOptions) => {
this._dispatch(axiumState, key, plan, this.concepts, action, options);
};
plan.stages[index](this.concepts, dispatcher);
}
}
});
const {observers} = this;

const len = observers.length;
for (let i = 0; i < len; i++) {
if (observers[i]) {
observers[i].next(concepts);
observers[i].next(this.concepts);
}
}
}
Expand Down
64 changes: 64 additions & 0 deletions src/test/stagePlannerBeat.test.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,64 @@

/*<$
For the graph programming framework Stratimux, generate a test to ensure that you can create a stage planner that sets the beat parameter
of the plan. The beat will ensure that within a span of time the first notification of state change will be observed.
But any new additional changes to state will be debounced for the beat duration.
But if the beat has not been notified for a period. The first notification will go through and start this process over again.
This is a combination of throttle and debounce.
$>*/
/*<#*/
import { createAxium } from '../model/axium';
import { selectState } from '../model/selector';
import { axiumSelectOpen } from '../concepts/axium/axium.selector';
import { axiumPreClose } from '../concepts/axium/qualities/preClose.quality';
import { axiumKick } from '../concepts/axium/qualities/kick.quality';
import { CounterState, counterName, createCounterConcept } from '../concepts/counter/counter.concept';
import { counterAdd } from '../concepts/counter/qualities/add.quality';

test('Stage Planner Beat Test', (done) => {
let timerActive = false;
const axium = createAxium('axium test stage planner beat', [
createCounterConcept()
], true, true);
const plan = axium.stage('Stage Planner Beat Test', [
(___, dispatch) => {
timerActive = true;
setTimeout(() => {
timerActive = false;
}, 1000);
dispatch(axiumKick(), {
iterateStage: true,
on: {
selector: axiumSelectOpen,
expected: true
},
});
},
(___, dispatch) => {
dispatch(counterAdd(), {
iterateStage: true
});
},
(concepts, dispatch) => {
if (!timerActive) {
const state = selectState<CounterState>(concepts, counterName);
if (state) {
expect(state.count).toBe(10);
setTimeout(() => done(), 1000);
dispatch(axiumPreClose({exit: false}), {
iterateStage: true
});
plan.conclude();
}
} else {
dispatch(counterAdd(), {
throttle: 1
});
}
},
() => {
//
}
], 93);
});
/*#>*/

0 comments on commit e7825ac

Please sign in to comment.