Approximate Pi
Full RecipeΒΆ
Shared by: Ethan Bell
Incrementally approximate pi using Leibniz' formula for Ο
Pi Recipe
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 | |
Shared by: Ethan Bell
Incrementally approximate pi using Leibniz' formula for Ο
Pi Recipe
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 | |
ScenarioΒΆ
Incrementally approximates pi using Leibniz' formula for Ο -- the arctangent function is incrementally (corecursively) computed along :improved_by edges, and each arctangent approximation is quadrupled to yield an approximation of pi.
How it WorksΒΆ
The recipe is completely self contained. We take advantage of the unique match, output action structure of a standing query to improve the approximation of pi by continuously streaming nodes back into the graph.
- pattern:
type: Cypher
query: MATCH (n:arctan) WHERE n.approximation IS NOT NULL AND n.denominator IS NOT NULL RETURN DISTINCT id(n) AS id
outputs:
# iterate over arctan
iterate:
type: CypherQuery
query: |-
MATCH (n)
WHERE id(n) = $that.data.id
WITH n, -sign(n.denominator)*(abs(n.denominator)+2) as nextDenom
WITH n, nextDenom, n.approximation+(1/nextDenom) as nextApprox
MATCH (next) WHERE id(next) = idFrom(nextDenom)
SET next:arctan, next.denominator = nextDenom, next.approximation=nextApprox
CREATE (n)-[:improved_by]->(next)
# map arctan to piApprox
piApprox:
type: CypherQuery
query: |-
MATCH (arctan)
WHERE id(arctan) = $that.data.id
WITH arctan, arctan.denominator AS denominator, arctan.approximation*4 AS approximatedPi
MATCH (approximation) WHERE id(approximation) = idFrom('approximation', denominator)
SET approximation:piApproximation, approximation.approximatedPi = approximatedPi
CREATE (arctan)-[:approximates]->(approximation)
RETURN approximatedPi
andThen:
type: WriteToFile
path: $out_file
{
"pattern": {
"type": "Cypher",
"query": "MATCH (n:arctan) WHERE n.approximation IS NOT NULL AND n.denominator IS NOT NULL RETURN DISTINCT id(n) AS id"
},
"outputs": {
"iterate": {
"type": "CypherQuery",
"query": "MATCH (n)\nWHERE id(n) = $that.data.id\nWITH n, -sign(n.denominator)*(abs(n.denominator)+2) as nextDenom\nWITH n, nextDenom, n.approximation+(1/nextDenom) as nextApprox\nMATCH (next) WHERE id(next) = idFrom(nextDenom)\nSET next:arctan, next.denominator = nextDenom, next.approximation=nextApprox\nCREATE (n)-[:improved_by]->(next)"
},
"piApprox": {
"type": "CypherQuery",
"query": "MATCH (arctan)\nWHERE id(arctan) = $that.data.id\nWITH arctan, arctan.denominator AS denominator, arctan.approximation*4 AS approximatedPi\nMATCH (approximation) WHERE id(approximation) = idFrom('approximation', denominator)\nSET approximation:piApproximation, approximation.approximatedPi = approximatedPi\nCREATE (arctan)-[:approximates]->(approximation)\nRETURN approximatedPi",
"andThen": {
"type": "WriteToFile",
"path": "$out_file"
}
}
}
}
standingQueries:
- name: arctan-processor
pattern:
type: Cypher
query: MATCH (n:arctan) WHERE n.approximation IS NOT NULL AND n.denominator IS NOT NULL RETURN DISTINCT id(n) AS id
mode: DistinctId
outputs:
# iterate over arctan
- name: iterate
preEnrichmentTransformation:
type: InlineData
resultEnrichment:
query: |-
MATCH (n)
WHERE id(n) = $that.id
WITH n, -sign(n.denominator)*(abs(n.denominator)+2) as nextDenom
WITH n, nextDenom, n.approximation+(1/nextDenom) as nextApprox
MATCH (next) WHERE id(next) = idFrom(nextDenom)
SET next:arctan, next.denominator = nextDenom, next.approximation=nextApprox
CREATE (n)-[:improved_by]->(next)
RETURN null
parameter: that
destinations:
- type: Drop
# map arctan to piApprox
- name: piApprox
preEnrichmentTransformation:
type: InlineData
resultEnrichment:
query: |-
MATCH (arctan)
WHERE id(arctan) = $that.id
WITH arctan, arctan.denominator AS denominator, arctan.approximation*4 AS approximatedPi
MATCH (approximation) WHERE id(approximation) = idFrom('approximation', denominator)
SET approximation:piApproximation, approximation.approximatedPi = approximatedPi
CREATE (arctan)-[:approximates]->(approximation)
RETURN approximatedPi
parameter: that
destinations:
- type: File
path: $out_file
{
"name": "arctan-processor",
"pattern": {
"type": "Cypher",
"query": "MATCH (n:arctan) WHERE n.approximation IS NOT NULL AND n.denominator IS NOT NULL RETURN DISTINCT id(n) AS id",
"mode": "DistinctId"
},
"outputs": [
{
"name": "iterate",
"preEnrichmentTransformation": {
"type": "InlineData"
},
"resultEnrichment": {
"query": "MATCH (n)\nWHERE id(n) = $that.id\nWITH n, -sign(n.denominator)*(abs(n.denominator)+2) as nextDenom\nWITH n, nextDenom, n.approximation+(1/nextDenom) as nextApprox\nMATCH (next) WHERE id(next) = idFrom(nextDenom)\nSET next:arctan, next.denominator = nextDenom, next.approximation=nextApprox\nCREATE (n)-[:improved_by]->(next)\nRETURN null",
"parameter": "that"
},
"destinations": [
{
"type": "Drop"
}
]
},
{
"name": "piApprox",
"preEnrichmentTransformation": {
"type": "InlineData"
},
"resultEnrichment": {
"query": "MATCH (arctan)\nWHERE id(arctan) = $that.id\nWITH arctan, arctan.denominator AS denominator, arctan.approximation*4 AS approximatedPi\nMATCH (approximation) WHERE id(approximation) = idFrom('approximation', denominator)\nSET approximation:piApproximation, approximation.approximatedPi = approximatedPi\nCREATE (arctan)-[:approximates]->(approximation)\nRETURN approximatedPi",
"parameter": "that"
},
"destinations": [
{
"type": "File",
"path": "$out_file"
}
]
}
]
}
We use a tag propagation technique set up in the standing query to perform the calculation.
Submitting the [No Output] Run this query to begin processing. sample query creates a seed node (n:arctan) in the graph with an initial approximation of 1.0.
WITH 1 AS initialDenominator
MATCH (n)
WHERE id(n) = idFrom(1)
SET n.denominator = toFloat(1),
n.approximation = toFloat(1),
n:arctan
Once the seed node is set in the graph, iteration over the approximation is done in several parts.
-
Detect when the seed node or its descendants enter the graph.
MATCH (n:arctan) WHERE n.approximation IS NOT NULL AND n.denominator IS NOT NULL RETURN DISTINCT id(n) AS id -
Iterate over arctan.
MATCH (n) WHERE id(n) = $that.data.id WITH n, -sign(n.denominator)*(abs(n.denominator)+2) as nextDenom WITH n, nextDenom, n.approximation+(1/nextDenom) as nextApprox MATCH (next) WHERE id(next) = idFrom(nextDenom) SET next:arctan, next.denominator = nextDenom, next.approximation=nextApprox CREATE (n)-[:improved_by]->(next) -
Map arctan to piApprox.
MATCH (arctan) WHERE id(arctan) = $that.data.id WITH arctan, arctan.denominator AS denominator, arctan.approximation*4 AS approximatedPi MATCH (approximation) WHERE id(approximation) = idFrom('approximation', denominator) SET approximation:piApproximation, approximation.approximatedPi = approximatedPi CREATE (arctan)-[:approximates]->(approximation) RETURN approximatedPi
Running the RecipeΒΆ
β― java -jar quine-1.10.0.jar -r pi.yaml -x out_file=approximation.log
Graph is ready
Running Recipe: Pi
Using 2 node appearances
Using 4 sample queries
Running Standing Query STANDING-1
Quine web server available at http://localhost:8080
| => STANDING-1 count 0
Connect to Quine once it is started and submit the [No Output] Run this query to begin processing. sample query.
Warning
Once you submit the [No Output] Run this query to begin processing. query, Quine will immediately begin to produce new approximations for pi. You must quit Quine (Ctrl+C) to stop the sequence.
You will immediately see the count of STANDING-1 matches increase and entries in the approximation.log fie.
| => STANDING-1 count 5043
{"meta":{"isPositiveMatch":true,"resultId":"106f731f-be27-2650-af22-b3010744124c"},"data":{"approximatedPi":3.141791500277029}}
Submit the [Node] Get Best Approximation (so far) sample query to display the latest approximation of pi as a node.
Quine will manifest a graph similar to this.
Submit the [Text] Repeatedly Get Best Approximation (so far) sample query with Shift+Enter to view the stream of updated approximations in the Exploration UI.
Build your skillsΒΆ
What ingest query could be added to replace the function of the [No Output] Run this query to begin processing. sample query?
Solution
We solved this by modifying the ingest query to use the NumberIteratorIngest type.
Replace the empty ingest query with this one.
- type: NumberIteratorIngest
startAtOffset: 1
ingestLimit: 1
format:
type: CypherLine
query: |-
WITH $that AS initialDenominator
MATCH (n)
WHERE id(n) = idFrom(1)
SET n.denominator = toFloat(1),
n.approximation = toFloat(1),
n:arctan



