version: 2
title: Pi
contributor: https://github.com/emanb29
summary: Incrementally approximates pi using Leibniz' formula
description: |-
  Incrementally approximates pi using Leibniz' formula -- the arctangent function is incrementally
  (corecursively) computed along :improved_by edges, and each arctangent approximation is quadrupled
  to yield an approximation of pi.

ingestStreams: []

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

nodeAppearances:
  - predicate:
      propertyKeys: []
      knownValues: {}
      dbLabel: piApproximation
    icon: π
    size: 40
    color: "#f1c232"
    label:
      type: Property
      key: approximatedPi
      prefix: ''
  - predicate:
      propertyKeys: []
      knownValues: {}
      dbLabel: arctan
    icon: ⦛
    size: 20
    color: "#000000"
    label:
      type: Constant
      value: 𝚊𝚛𝚌𝚝𝚊𝚗

sampleQueries:
  - name: "[No Output] Run this query to begin processing."
    query: WITH 1 AS initialDenominator MATCH (n) WHERE id(n) = idFrom(1) SET n.denominator = toFloat(1), n.approximation = toFloat(1), n:arctan
  - name: "[Node] Get Best Approximation (so far)"
    query: |-
      CALL recentNodes(15) YIELD node AS nId
      MATCH (n)
      WHERE id(n) = nId AND n.approximatedPi IS NOT NULL
      RETURN n LIMIT 1
  - name: "[Text] Get Best Approximation (so far)"
    query: |-
      CALL recentNodes(15) YIELD node AS nId
      MATCH (n)
      WHERE id(n) = nId AND n.approximatedPi IS NOT NULL
      RETURN n.approximatedPi LIMIT 1
  - name: "[Text] Repeatedly Get Best Approximation (so far)"
    query: |-
      UNWIND range(0, 1000) AS x UNWIND range(0, 1000) AS y
      CALL util.sleep(1000)
      CALL cypher.doIt("
        CALL recentNodes(15) YIELD node AS nId
        MATCH (n)
        WHERE id(n) = nId AND n.approximatedPi IS NOT NULL
        RETURN n.approximatedPi AS approximatedPi LIMIT 1
      ") YIELD value
      RETURN value.approximatedPi AS approximatedPi, abs(pi() - value.approximatedPi) AS error

quickQueries: []
