Skip to content

Commit

Permalink
Merge pull request #90 from Phuire-Research/UI
Browse files Browse the repository at this point in the history
UI
  • Loading branch information
REllEK-IO committed Oct 15, 2023
2 parents 609d06d + 4f45651 commit 5336dc1
Show file tree
Hide file tree
Showing 11 changed files with 327 additions and 24 deletions.
51 changes: 51 additions & 0 deletions ActionController.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,51 @@
# ActionController
This was the original inspiration for the STRX Principle concept. Except here we decomposed and recomposed the concept into two parts. Here the ActionController in contrast to its original is an subject that fires once and has an expiration. This streamlines the difficulty of working with this concept, as originally to make it wholly responsible for itself, it would require an additional subscription to determine whether it should be open or closed. But now with the additional refinement of each action having an expiration, we can define the expiration as the limit to the lifespan of each action. And would be the second point of failure that an ActionStrategy would move into a failure state.

The purpose of the ActionController is to perform singular actions that effect one thing asynchronously. For example in a FileSystem concept, it would be the literal Method, that would allow for manipulation of files. As each operation can have a failure state that is outside of the control of STRX. Such as a file being open by a user, or the lack of permission allotted to the run time.

In order to have the ActionController work within STRX we must set up the Method in a specific manner to ensure type safety. Note the usage of the "switchMap," as we are changing the context of the stream from an Action to a specific subject that will later return an Action.
## Example
``` typescript
const createSomeMethodCreator: MethodCreator = () => {
const logSubject = new Subject<Action>();
const logMethod: Method = logSubject.pipe(
switchMap((act: Action) => {
return createActionController$(act, (controller, action) => {
const payload = selectPayload<SomePayload>(action);
if (action.strategy) {
someAsyncFunction.then(value => {
const strategy = action.strategy as ActionStrategy;
if (value) {
const newStrategy =
strategySuccess(
strategy,
strategyData_unifyData(strategy, {some: value})
);
controller.fire(newStrategy);
} else {
const newStrategy =
strategyFailed(
strategy,
strategyData_appendFailure(strategy, 'Some Async function failed.')
);
controller.fire(newStrategy);
}
}
);
} else {
controller.fire(axiumConclude());
}
});
}),
);
return [
logMethod,
logSubject
];
};
```
In the above we are likewise paying attention to the possibility of failure within the Asynchronous Function. Then informing the type of failure that occurred. It is advisable if you know these failures modes in advance. To create an enum that can store such. As the failureCondition is just some enum holding a set of strings. Then use this enum to inform your next decision from your FailureNode. Note here that in classical game ai systems that they would ordinarily restrict the amount of successive actions that an ai might make to 2. This pattern of design of informing some failure demonstrates the inherit higher order reasoning within STRX's design. Complexity classically has been seen as a poor design choice, but the goal within STRX is to fully decompose intelligent systems as the unfortunate truth is that higher order logic is complex by default. But may be made less complex via logical determinism, wherein we decision with failure modes in mind. Versus leaving that decision to some probability.

The easiest example of such is living with room mates and wanting to have a bowl of cereal before going to work. The entire strategy involves the confirmation that the room mate did not drink the rest of the milk the previous night. Therefore the strategy that we impose accounts for this possibility via changing the meal, or forgoing it entirely to get to work on time. But likewise if we forgo our breakfast and get to work. We should take into account the possibility of grabbing a snack from the break room, but if all the snacks are gone. Then in the last ditch effort can have some coworker or delivery service bring in some food. If none of these options are available, then we will have to wait till lunch.

Note here that while we are doing so seamlessly. In a video game context this would be considered to be too complex to design. As classically in order to create this behavior it would be the generation of smaller steps to achieve some short sighted goal or interaction. But in the scope of planning, in order to make it through to the end of the day. We are having to make decisions in line with our overall goals to successfully make it back to bed at a reasonable hour. As we not only take into account that day, but know that if we go out and play. We likewise can hamper our own next work the next day, if we don't get home on time. This demonstrates the purpose of identifying "Time" and "Space" as a "Universal Concepts." Where time is the limiter to our ability to perform some action, depending on other strategies we are required to perform. And space the locality and availability of some concept to successfully perform some action. That you may sleep at the office if working late, but then you would need some clothes in your car. And if your work has a clean shave policy, then likewise you would need a method of shaving available to match the requirements that your workspace has set you for you to meet each day.
6 changes: 4 additions & 2 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -14,11 +14,13 @@ The inspiration for STRX was that of Redux and its origin via the FLUX design pa
![Ghostbusters - "We'll Cross the Streams" - (HD) - Scenes from the 80s - (1984)](https://github.com/Phuire-Research/STRX/blob/main/CrossTheStreams.gif?raw=true)

### Concept Index
* [ActionStrategy](https://github.com/Phuire-Research/STRX/blob/main/ActionStrategy.md) - Created in 2018, this is the governing concept that allows for the Unified Turing Machine to have a strong halting quality. Likewise the direct analog of higher order logic and universal transformer.
* [Action Strategy](https://github.com/Phuire-Research/STRX/blob/main/ActionStrategy.md) - Created in 2018, this is the governing concept that allows for the Unified Turing Machine to have a strong halting quality. Likewise the direct analog of higher order logic and universal transformer.
* [Axium](https://github.com/Phuire-Research/STRX/blob/main/Axium.md) - Governing concept that contains the set of concepts that formalizes each axium.
* [Concept](https://github.com/Phuire-Research/STRX/blob/main/Concept.md) - The programming abstraction of a concept that is decomposable to the sum of its parts via: state, qualities, principles, and mode.
* [Stage Planner](https://github.com/Phuire-Research/STRX/blob/main/StagePlanner.md) - Introducing the stage planner paradigm. A specialized helper function to prevent action overflow when dispatching actions in subscriptions.
* [Stage Planner](https://github.com/Phuire-Research/STRX/blob/main/StagePlanner.md) - Introducing the stage planner paradigm. A specialized helper function to prevent action overflow when dispatching actions in subscriptions.
* [Action Controller](https://github.com/Phuire-Research/STRX/blob/main/ActionController.md) - Allows methods to be performed asynchronously.
* [Spatial Ownership](https://github.com/Phuire-Research/STRX/blob/main/SpatialOwnership.md) - Streamlines the complex nature of the ActionStrategy as it relates to itself and other axiums. This is what allows STRX to be a graph computation paradigm.
* [Strategy Data](https://github.com/Phuire-Research/STRX/blob/main/StrategyData.md) - Allows for the ActionStrategy pattern to act as a "Universal Transformer." Likewise decorates strategies with the necessary information to inform "ActionNodes," of possible failure conditions.
* [Unified Turing Machine](https://github.com/Phuire-Research/STRX/blob/main/The-Unified-Turing-Machine.md) - The governing concept for this entire framework.

## The Halting Problem
Expand Down
47 changes: 47 additions & 0 deletions StrategyData.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,47 @@
# Strategy Data
This is the true power of the ActionStrategy design pattern as a Universal Transformer. As this system is informed by "Data Oriented Design." We are focusing explicitly on the transforming of some data over a period of time. How are doing so, is via the creation of some Record that would be unified over the lifetime of that ActionStrategy. As the act of unifying some data. Is merely decomposing those records and recomposing such into a new record with all previous parameters with the newest taking president.

What allows for the ActionStrategy paradigm to be a "Universal Transformer." Is the recognition of the most fundamental truth in computer programming. Is that via the utilization of plain text with transpilation to some native binary. Allows for all files to be modified within a plain text environment. As such this could also include the vertices within some graphical model that would be used to inform the appearance of some geometry within a simulation.

The ActionStrategy's goal would be how to transform that data over a series of steps to match the goal set out by its topic. The difficulty within this approach is that it requires specific naming conventions to handle this transformation over time. As we are matching "Universal Properties." Therefore if a parameter is not being opted in to this unifying data approach. That parameter should have some preposition that stops this process from happening. For example, "uiDivStyle," versus "style."

## Consumer Functions
``` typescript
export const strategyData_appendFailure = (strategy: ActionStrategy, condition: failureConditions | string): Record<string, unknown> => {};
export const strategyData_selectFailureCondition = (strategy: ActionStrategy): failureConditions | string | undefined => {};
export const strategyData_clearFailureCondition = (strategy: ActionStrategy): Record<string, unknown> | undefined => {};
export const strategyData_select = <T>(strategy: ActionStrategy): T | undefined => {};
export const strategyData_unifyData = (strategy: ActionStrategy, data: Record<string,unknown>): Record<string,unknown> => {};
```
* strategyData_appendFailure - This will append a "failureCondition," property that is informed either by the failureConditions enum or your string. This allows for your failureNodes to make intelligent decisions. Or if there is no data field present, it will create a new record with this property.
* strategyData_selectFailureCondition - This will return the failure condition or undefined if not set.
* strategyData_clearFailureCondition - This will clear such from the current record, otherwise if there are no additional properties on the record, or if no record is present at the time of clear, it will return undefined. As this forces data validation to ensure there is some data to unify given some success.
* strategyData_select - This will simply return and set the current type of the returned data. But forces type safety via the possibility of an undefined type. Note here that the strength of TypeScript allows for Records to be return or casted as a Slice of the given type, even if other Actions have added properties that would not be accounted for within your transformation context.
* strategyData_unifyData - The reason for all the undefined returns. This will take the current records, decomposed, and recompose such together with the newest data taking precedent.

## The Reason for this Approach
We are using within the context your concepts the creation of consumer functions to ensure type safety even within the context of data that would be unified with other concepts. That these records might have the failureCondition property. But your logic would only care for the parameters that it is attempting to transform. This in effect allows for the creation of new emergent data if the "crossing of the streams." And in contrast to previous methods of programming, this would be similar to the creation of the assembly line within the context of programming. As classically the assembly line is generalized within the context of classic via the utilization of factories. As factories have assembly lines, but you are traditionally only caring for the output based on some input.

Therefore this approach decomposes the concept of the factory into its parts. And allows for different concepts to inform the unified output of your overall factory as the "Axium." As even if we examine the properties of some file type binary. When in the context of its informing program, that file would just be some set of properties. The decision to turn such into a binary does save on space and allows such to be condensed and represents a construct that purposefully resists decomposition from other programs. We could take advantage of this approach while having a shared standard for the binary transformation of plain text and its decomposition. Point being, it is a relative thing and what matters in the context of programming and entities is that everything is merely a list of properties. The difficulty is gaining access to those that you would otherwise transform.

## Failure Conditions and Higher Order Logic
``` typescript
export enum failureConditions {
ownershipExpired = 'ownershipExpired',
ownershipBlocked = 'ownershipBlocked',
controllerExpired = 'controllerExpired',
axiumExpired = 'axiumExpired',
axiumBadGeneration = 'axiumBadGeneration'
}
```
Note with the above, due to there being by default 3 different types of failure within an ActionStrategy within STRX. That being "Expiration," "Blocked," and "Bad Generation." Expiration, which we treat as an absolute failure with no recovery. If a strategy must be recovery if it expires, please use a subscription or plan to pay attention to the badActions list on the "Axium." From there you can determine either you action's type or strategy topic to reissue such if it expired. Blocked signifies that the "Ownership" concept is currently loaded at the target transformation is temporarily being blocked, but may still expire. And finally "Bad Generation," this denotes whether the quality or governing concept is currently loaded within the Axium. As the axium is allowed to transform its functionality over time, the generation signifies the current iteration of its configuration. This is effected via the removal or concepts or the addition of such. If one wants to effect the composition of qualities on a concept, it is advised to still use these functions while providing a means to transfer the current state onto the new concept.

We have likewise introduced additional data handling functions. Specially here we are using "strategyData_appendFailure." To denote, specially what type of failure has happened within the ActionStrategy. Therefore the FailureNode, may utilize "strategyData_selectFailureCondition," to determine some decision to handle the returned property. This is where this system becomes complex. Noting that within traditional game Ai systems that would use some behavior tree or action planner. This is why those systems limit the amount of actions to just 2, and call anything more than that as overtly complex. Therefore this likewise reinforces that this system of programming is the bluntest form of higher order logic.

As the fundamental difficulty of higher order logic, is having to take into account complex state arrangements to make decisions. And the longer the strategy, or the more successive used in unison, the higher chance there will be some failure. Therefore this is higher order via the exponential factor of decision making that must be taken into account per ActionStrategy.

The advantage that STRX has over these classical game Ai systems. Is we know in advance some "Universal Concepts," that would inform the failure mode. That being you cannot have two sets of feet standing in the same position, would be "Spatial Ownership." Or in the case of computer systems, is whether you are modifying some file that is already open by another program.

The other would be "Time," or expiration paradigm within STRX that limits of lifetimes of Strategies within this System. As the createActionController function assigns a timer to the life time of that specific ActionController. That is cleared upon success or will fire the next FailureNode or conclusion if present, while appending the failure context to the data property.

*There is much more to be expanded in addition to working examples. Internally this is being used to prototype a "UserInterface" concept and will release those examples once that concept is worthy of being in a mvp state.*
2 changes: 1 addition & 1 deletion package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "@phuire/strx",
"version": "0.0.33",
"version": "0.0.34",
"description": "Unified Turing Machine",
"main": "dist/index.js",
"module": "dist/index.mjs",
Expand Down
12 changes: 10 additions & 2 deletions src/concepts/ownership/ownership.mode.ts
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@ import { AppendActionListToDialogPayload, axiumAppendActionListToDialogType } fr
import { selectState } from '../../model/selector';
import { OwnershipState, ownershipName } from './ownership.concept';
import { AxiumState } from '../axium/axium.concept';
import { failureConditions, strategyData_appendFailure } from '../../model/actionStrategyData';

export const ownershipMode: Mode = (
[_action, _concepts, action$, concepts$] : [Action, Concept[], Subject<Action>, UnifiedSubject]
Expand All @@ -33,9 +34,13 @@ export const ownershipMode: Mode = (
const shouldBlock = ownershipShouldBlock(concepts, action);
if (shouldBlock) {
if (action.strategy) {
const strategy = action.strategy;
if (action.strategy.currentNode.failureNode === null) {
// This assumes that the Strategy does not account for the Block
let nextAction = strategyFailed(action.strategy);
let nextAction = strategyFailed(
strategy,
strategyData_appendFailure(strategy, failureConditions.ownershipBlocked)
);
// Logical Determination: axiumConcludeType
if (nextAction.semaphore[3] === 3) {
concepts = clearStubs(concepts, nextAction.strategy as ActionStrategy);
Expand All @@ -50,7 +55,10 @@ export const ownershipMode: Mode = (
// This assumes that the Strategy is accounting for the Block
// console.log('Check Action Failed1', action);
[concepts, action] = checkIn(concepts, action);
const nextAction = strategyFailed(action.strategy as ActionStrategy);
const nextAction = strategyFailed(
strategy,
strategyData_appendFailure(strategy, failureConditions.ownershipBlocked)
);
concepts = updateAddToPendingActions(concepts, nextAction);
concepts$.next(concepts);
}
Expand Down
11 changes: 10 additions & 1 deletion src/concepts/ownership/ownership.principle.ts
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,15 @@ import { UnifiedSubject } from '../../model/stagePlanner';
import { BadActionPayload, axiumBadActionType } from '../axium/qualities/badAction.quality';
import { axiumRegisterStagePlanner } from '../axium/qualities/registerStagePlanner.quality';
import { axiumSelectOpen } from '../axium/axium.selector';
import { failureConditions, strategyData_appendFailure } from '../../model/actionStrategyData';

function denoteExpiredPending(action: Action): Action {
if (action.strategy) {
const strategy = action.strategy;
action.strategy.data = strategyData_appendFailure(strategy, failureConditions.ownershipExpired);
}
return action;
}

export const ownershipPrinciple: PrincipleFunction = (
observer: Subscriber<Action>,
Expand Down Expand Up @@ -63,7 +72,7 @@ export const ownershipPrinciple: PrincipleFunction = (
const newPending: Action[] = [];
for (const pending of ownershipState.pendingActions) {
if (pending.expiration < Date.now()) {
badActions.push(pending);
badActions.push(denoteExpiredPending(pending));
} else {
newPending.push(pending);
}
Expand Down
Loading

0 comments on commit 5336dc1

Please sign in to comment.