# linkPrecision

RxDeep is designed to be extremely precise, meaning states should emit only when they have a good reason to. To be more precise (pun unintended), absolute precision means a state emits values when and only when one of the following holds:

1. Its value has changed.

2. Its value is directly updated (possibly to the same value).

3. It points to the same address in state-tree as another state whose value is directly updated (possibly to the same value).

4. One of its descendent sub-states (a sub-state in its sub-tree) satisfies (2) or (3).

1linkconst root = state([2link  { name: 'Jack', address: { city: 'Java', country: 'Indonesia' } },3link  { name: 'Jafar', address: { city: 'Jiroft', country: 'Iran' } },4link]);5link6linkconst mid1 = root.sub(0);7linkconst mid2A = mid1.sub('address');                     // --> shares tree address with mid2B8linkconst mid2B = root.sub(0).sub('address');              // --> shares tree address with mid2A9linkconst leaf1 = root.sub(0).sub('address').sub('city');  // --> shares tree address with leaf210linkconst leaf2 = mid2A.sub('city');                       // --> shares tree address with leaf111link12linkleaf1.value = leaf1.value;                             // --> issue update without value change13link14link// As a result:15link// > leaf1 will emit (due to (2))16link// > leaf2 will emit (due to (3))17link// > mid2A, mid2B, mid1, and root will emit (due to (4))

By this definition RxDeep is absolutely precise if object immutabilty is respected and objects passed to it are of plain (non-circular) JavaScript objects.

## linkLossiness

A Loss is when a State should emit (according to the outlined criteria) but it doesn't. RxDeep is not lossy by default, only IF object immutability is respected. Simply put, you must not change the value of a State without changing its reference, as otherwise there is no mechanism for RxDeep to pickup those changes and distinguish what has changed.

## linkRedundancy

Redundancy refers to situations when a state emits without a good reason for doing so (i.e. none of the outline criteria hold up). RxDeep has no redundancy, meaning a state does not emit values without a good reason (without one of the aforementioned criteria being true).

This is due to the fact that leaf-changes are fully traced and delivered only to affected sub-states, and arbitrary changes are traced until their issuing depth and then post-traced so that the change trace is complete until leafs of the state-tree, allowing for precise propagation of the change.

## linkPerformance

As discussed here, a leaf-change has $\Omicron(\log(n))$ complexity and an arbitrary change at depth $\delta$ and above a sub-tree of $n_{\delta}$ nodes has $\Omicron(\log(n) + n_{\delta}\log(n_{\delta}))$ time complexity. For most day to day use cases both of these are more than fast enough.

However, in special cases you might need that additional performance. As (also) discussed here, if the whole sub-tree needs to change, you need minimum of $\Omicron(\log(n) + n_{\delta}\log(n_{\delta}))$ operations, as you need that many emissions to not be lossy. However, if your change affects a bounded number of leaf states, for example $k$ leaf states, then the minimum number of operations is given by:

$\Omicron(\log(n) + (k - 1)\log(n_{\delta})) = \Omicron(\log(n))$1

A simple method of achieving that performance is identifying the $k$ leaf nodes and applying change to them. Time-complexity of this solution is given by:

$\Omicron(k\log(n)) = \Omicron(\log(n))$1

However, this also results in $k$ emissions by all affected states (e.g. the root state will also emit $k$ times).

1linkconst company = state({2link  teams: [{3link    people: [{name: 'Jack', age: 42}, {name: 'Jill', age: 31}],4link    name: 'Awesome Team',5link  }, ...]6link});7link8link//9link// Find all affected leaf changes and apply changes directly to them.10link//11linkcompany.sub('teams').sub(0).sub('people').sub(0).sub('name').value = 'Jafar';12linkcompany.sub('teams').sub(0).sub('name').value = 'Pro Team';

A more efficient solution would be to:

1. Identify the top-most common ancestor of all affected leaf nodes,

2. Apply changes respecting maximal object immutability.

1linkconst company = state({2link  teams: [{3link    people: [{name: 'Jack', age: 42}, {name: 'Jill', age: 31}],4link    name: 'Awesome Team',5link  }, ...]6link});7link8link//9link// This is the top-most common ancestor:10link//11linkconst target = company.sub('teams').sub(0);12link13link//14link// Now lets apply changes with maximal object immutability:15link//16linktarget.value = {17link  ...target.value,18link  name: 'Pro Team',19link  people: [20link    {21link      ...target.value.people[0],22link      name: 'Jafar'23link    }24link    ...target.value.people.slice(1),25link  ]26link}

Object immutability means that the reference of an object is changed IF its value has changed.
Maximal object immutability means the reference of an object is changed IF AND ONLY IF its value has changed.

The post-tracing algorithm of RxDeep makes quick reference checks to rule out identical objects, so when making a change respecting maximal object immutability, and with the aforementioned criteria holding (constant $k$ leafs are actual subjects of the change), post-tracing consumes $\Omicron(k\log(n_{\delta}))$ operations, so the complexity of overall change propagation is given by:

$\Omicron(log(n) + (k - 1)log(n_{\delta})) = \Omicron(log(n))$1

Additionally, with this solution affected states emit exactly once.