Skip to content

Commit

Permalink
modifying formatting of pcfs in UI and adding LIReC see also
Browse files Browse the repository at this point in the history
  • Loading branch information
krachwal committed Jun 25, 2024
1 parent a18ffb7 commit 51c1e33
Show file tree
Hide file tree
Showing 10 changed files with 136 additions and 37 deletions.
12 changes: 7 additions & 5 deletions lirec-grpc-server/server.py
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
from concurrent import futures

import grpc
from LIReC.db.access import db
from LIReC.db.access import db, PolyPSLQRelation

import constants
import lirec_pb2
Expand All @@ -14,10 +14,12 @@
class LIReCServicer(lirec_pb2_grpc.LIReCServicer):
def Identify(self, request: lirec_pb2.IdentifyRequest, context: object) -> lirec_pb2.IdentifyResponse:
logger.debug(f"Received request: <{type(request)}> {request}")
closed_forms = db.identify(values=[request.limit], wide_search=[1], min_prec=constants.DEFAULT_PRECISION)
logger.debug(f"Received response: <{type(closed_forms)}> {[str(item) for item in closed_forms]}")
return lirec_pb2.IdentifyResponse(closed_forms=[str(item) for item in closed_forms])

results = db.identify(values=[request.limit], wide_search=[1], min_prec=constants.DEFAULT_PRECISION, see_also=True)
logger.debug(f"Received response: <{type(results)}> {[str(item) for item in results]}")
if len(results) > 0 and type(results[0]) is list:
return lirec_pb2.IdentifyResponse(closed_forms=[str(item) for item in results[0]], see_also=[str(item) for item in results[1]])
else:
return lirec_pb2.IdentifyResponse(closed_forms=[str(item) for item in results])

def serve() -> None:
"""
Expand Down
2 changes: 1 addition & 1 deletion protos/lirec.proto
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,6 @@ option objc_class_prefix = "HLW";
package lirec_rpc;

service LIReC {
// Sends a greeting
rpc Identify(IdentifyRequest) returns (IdentifyResponse) {}
}

Expand All @@ -17,4 +16,5 @@ message IdentifyRequest {

message IdentifyResponse {
repeated string closed_forms = 1;
repeated string see_also = 2;
}
4 changes: 2 additions & 2 deletions python-backend/call_wrapper.py
Original file line number Diff line number Diff line change
Expand Up @@ -40,7 +40,7 @@ def pcf_limit(a, b, n) -> str:
signal.alarm(0)


def lirec_identify(limit) -> list[sympy.core.numbers.Number]:
def lirec_identify(limit) -> [list[sympy.core.numbers.Number], list[sympy.core.numbers.Number]]:
"""
Invokes LIReC pslq algorithm
"""
Expand All @@ -49,7 +49,7 @@ def lirec_identify(limit) -> list[sympy.core.numbers.Number]:
stub = lirec_pb2_grpc.LIReCStub(channel)
request = lirec_pb2.IdentifyRequest(limit=limit)
response = stub.Identify(request)
return response.closed_forms
return [response.closed_forms, response.see_also]
except TimeoutError:
logger.error("Function execution timed out after {} seconds".format(EXTERNAL_PROCESS_TIMEOUT))
finally:
Expand Down
2 changes: 1 addition & 1 deletion python-backend/constants.py
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,6 @@
# evalf allows for verbose output via param universally set to this:
VERBOSE_EVAL = False
# when calling ResearchTools, only way this many seconds before throwing a timeout exception
EXTERNAL_PROCESS_TIMEOUT = 10
EXTERNAL_PROCESS_TIMEOUT = 30
# the free Wolfram API limits queries to 200 characters
WOLFRAM_CHAR_LIMIT = 200
12 changes: 11 additions & 1 deletion python-backend/main.py
Original file line number Diff line number Diff line change
Expand Up @@ -138,7 +138,8 @@ async def data_socket(websocket: WebSocket):
logger.debug(f"limit: {limit}")
await websocket.send_json({"limit": "Infinity" if type(limit) is Infinity else str(limit)})

computed_values: list[str] = call_wrapper.lirec_identify(limit)
[computed_values, see_also] = call_wrapper.lirec_identify(limit)

json_computed_values = []
for m in computed_values:
logger.debug(f"identify returned: {m}")
Expand All @@ -148,6 +149,15 @@ async def data_socket(websocket: WebSocket):
{"converges_to": json.dumps(json_computed_values)}
)

json_see_also = []
for m in see_also:
logger.debug(f"identify returned see_also: {m}")
json_see_also.append(str(m))

await websocket.send_json(
{"see_also": json.dumps(json_see_also)}
)

await chart_coordinates(pcf=pcf.PCF(sympify(data.a), sympify(data.b)),
limit=mpmath.mpf(limit),
iterations=iterations,
Expand Down
10 changes: 9 additions & 1 deletion react-frontend/src/App.css
Original file line number Diff line number Diff line change
Expand Up @@ -268,7 +268,7 @@ div.chart-container {
padding: 1.2rem;
text-align: left;
font-size: 1.3rem;
width: 600px;
width: 900px;
margin-left: auto;
margin-right: auto;
border-radius: var(--radius);
Expand All @@ -291,6 +291,11 @@ div.closed-form {
margin: 0.5rem;
background-color: var(--muted-light);
border-radius: var(--radius);
display: flex;
flex-wrap: wrap;
& span {
align-self: center;
}
}
p.footnote {
font-size: 0.8rem;
Expand Down Expand Up @@ -380,6 +385,9 @@ div.flex-child {
flex: 1;
align-self: baseline;
}
div.align-self-center {
align-self: center;
}
.metadata {
font-size: 0.8rem;
font-weight: normal;
Expand Down
119 changes: 94 additions & 25 deletions react-frontend/src/components/Charts.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@ interface ChartProps {
limit?: string;
symbol: string;
convergesTo?: string[];
seeAlso?: string[];
deltaData?: CoordinatePair[];
toggleDisplay: () => void;
}
Expand Down Expand Up @@ -41,12 +42,14 @@ type ConstantMetadataWrapper = {
[key: string]: ConstantMetadata;
};

function Charts({ a_n, b_n, limit, symbol, convergesTo, deltaData, toggleDisplay }: ChartProps) {
function Charts({ a_n, b_n, limit, symbol, convergesTo, seeAlso, deltaData, toggleDisplay }: ChartProps) {
const [wolframResults, setWolframResults] = useState<WolframResult[]>();
const [constantMetadata, setConstantMetadata] = useState<Record<string, ConstantMetadata>>({});
const [lirecClosedForm, setLirecClosedForm] = useState<string[]>();
const [seeAlsoClosedForm, setSeeAlsoClosedForm] = useState<string[][]>();
const [pcf, setPcf] = useState('');

// MathJax config
const config = {
tex: {
inlineMath: [['$', '$']],
Expand All @@ -58,9 +61,15 @@ function Charts({ a_n, b_n, limit, symbol, convergesTo, deltaData, toggleDisplay
if (limit) verify();
}, [limit]);

useEffect(() => {
if (Array.isArray(seeAlso) && seeAlso.length > 0) {
setSeeAlsoClosedForm(restructureSeeAlso(seeAlso));
}
}, [seeAlso]);

useEffect(() => {
if (Array.isArray(convergesTo) && convergesTo.length > 0) {
setLirecClosedForm(replaceLirecChars());
setLirecClosedForm(replaceLirecChars(convergesTo));
}
}, [convergesTo]);

Expand All @@ -77,42 +86,71 @@ function Charts({ a_n, b_n, limit, symbol, convergesTo, deltaData, toggleDisplay
}
};

useEffect(() => {
let [a0, a1, a2, a3] = [a_n, a_n, a_n, a_n];
let [b1, b2, b3] = [b_n, b_n, b_n];
if (symbol) {
if (a_n.indexOf(symbol) >= 0) {
a0 = parse(a_n.replaceAll(symbol, '0').replaceAll('**','^')).evaluate();
a1 = parse(a_n.replaceAll(symbol, '1').replaceAll('**','^')).evaluate();
a2 = parse(a_n.replaceAll(symbol, '2').replaceAll('**','^')).evaluate();
a3 = parse(a_n.replaceAll(symbol, '3').replaceAll('**','^')).evaluate();
}
if (b_n.indexOf(symbol) >= 0) {
b1 = parse(b_n.replaceAll(symbol, '1').replaceAll('**','^')).evaluate();
b2 = parse(b_n.replaceAll(symbol, '2').replaceAll('**','^')).evaluate();
b3 = parse(b_n.replaceAll(symbol, '3').replaceAll('**','^')).evaluate();
}
}
let parsed = parse(`${a0} + (${b1} / (${a1} + (${b2} / (${a2} + (${b3} / (${a3} + dots))))))`);
let formatPcf = function(_a_n: string, _b_n:string) {
// preset to input value
console.log('format inputs' ,_a_n, _b_n);
let a = _a_n.replaceAll('**','^');
console.log('a', a);
let a_parsed = parse(a);
console.log('a parsed', a_parsed);
let b = _b_n.replaceAll('**','^');
console.log('b', b);
let b_parsed = parse(b);
console.log('b parsed', b_parsed);
let [a0, a1, a2] = [a_parsed.evaluate({n: 0}), a_parsed.evaluate({n: 1}), a_parsed.evaluate({n: 2})];
console.log('a0',a0, 'a1',a1,'a2',a2);
let [b1_eval, b2_eval, b3_eval] = [b_parsed.evaluate({n: 1}),b_parsed.evaluate({n: 2}),b_parsed.evaluate({n: 3})];
let [,b1_sign, b2_sign, b3_sign] = [undefined, b1_eval > 0 ? '+': '-',b2_eval > 0 ? '+': '-',b3_eval > 0 ? '+': '-'];
console.log('b signs', b1_sign, b2_sign, b3_sign);
let parsed = parse(`${a0} ${b1_sign} (${b1_eval} / (${a1} ${b2_sign} (${b2_eval} / (${a2} ${b3_sign} (${b3_eval} / (dots + ${b} / (${a} + dots)))))))`);
console.log('parsed', parsed);
let mathy = parsed.toTex({ parenthesis: 'auto' });
// this is a hack because mathjs chokes on the dots so we put them in after the expression is Texed
setPcf(`$$${mathy.replaceAll('dots', '...')}$$`);
return `$$${mathy.replaceAll('dots', '...')}$$`;
}

useEffect(() => {
setPcf(formatPcf(a_n, b_n));
}, [a_n, b_n, symbol]);

const replaceLirecChars = () => {
const restructureSeeAlso = (input: string[]) => {
let result = new Array<string[]>();
for (const value of input!!) {
console.log('input',value);
const cleanString = value
.replaceAll('PCF[','')
.replaceAll('] =', '=')
.replaceAll('**', '^')
.replace(/\s\(-?[0-9]+\)$/, '');
console.log('clean', cleanString);
const input = convertLirecConstants(cleanString);
console.log('converted', input);
let [pcf_a, remnant] = input.split(',');
console.log('pcf_a', pcf_a, 'remnant', remnant);
let [pcf_b, exp] = remnant.split('=');
console.log('pcf_b', pcf_b, 'exp', exp);
console.log('wrapped pcf', formatPcf(pcf_a, pcf_b));
console.log('wrapped exp', wrapExpression(exp));
result.push([wrapExpression(exp), formatPcf(pcf_a, pcf_b)]);
}
return result;
};

const replaceLirecChars = (input: string[]) => {
// we are replacing the exponent operator from python to js syntax
// we are also stripping the parentheses at the end of the expression returned from identify
let result = new Array<string>();
for (const value of convergesTo!!) {
for (const value of input!!) {
const cleanString = value
.replaceAll('**', '^')
.replace(' = 0', '')
.replace(/\s\([0-9]+\)$/, '');
.replace(/\s\(-?[0-9]+\)$/, '');
const input = convertLirecConstants(cleanString);
result.push(wrapExpression(input));
}
return result;
};

// e.g. '(20*alpha_GW - 34)/(alpha_GW + 9)'
// should convert to '(20*α[GW] - 34)/(α[GW] + 9)'
const convertLirecConstants = (input: string) => {
Expand Down Expand Up @@ -196,8 +234,7 @@ function Charts({ a_n, b_n, limit, symbol, convergesTo, deltaData, toggleDisplay

const verify = () => {
if (limit) {
axios
.post('/verify', { expression: limit })
axios.post('/verify', { expression: limit })
.then((response) => {
if (response.status != 200) {
console.warn(response.data.error);
Expand Down Expand Up @@ -336,6 +373,38 @@ function Charts({ a_n, b_n, limit, symbol, convergesTo, deltaData, toggleDisplay
) : (
''
)}
{seeAlso ? (
<div className="full-width top-padding">
<p className="center-content">See also</p>
<div className="top-padding center-text">
<p className="footnote">
<i>
Results from{' '}
<a
href="https://github.com/RamanujanMachine/LIReC"
aria-description="Link to LIReC GitHub repository README.">
LIReC
</a>
</i>
</p>
</div>
<div className="closed-form-container">
{seeAlsoClosedForm?.map((pcf: string[]) =>
(<div className="closed-form" key={pcf[0]}>
<MathJax inline dynamic>
{pcf[0]}
</MathJax>
<span className="align-self-center">=</span>
<MathJax inline dynamic>
{pcf[1]}
</MathJax>
</div>)
)}
</div>
</div>
) : (
''
)}
{deltaData && deltaData?.length > 0 ? (
<div className="top-padding plot-container">
<p>
Expand Down
5 changes: 5 additions & 0 deletions react-frontend/src/components/Form.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@ function Form() {
const [noConvergence, setNoConvergence] = useState(false);
const [waitingForResponse, setWaitingForResponse] = useState(false);
const [convergesTo, setConvergesTo] = useState([]);
const [seeAlso, setSeeAlso] = useState([]);
const [limit, setLimit] = useState('');
const [deltaData, setDeltaData] = useState<CoordinatePair[]>([]);

Expand All @@ -29,6 +30,7 @@ function Form() {
}, []);

const resetState = function () {
setSeeAlso([]);
setConvergesTo([]);
setLimit('');
setDeltaData([]);
Expand Down Expand Up @@ -113,6 +115,8 @@ function Form() {
}
} else if (Object.hasOwn(message, 'converges_to')) {
setConvergesTo(JSON.parse(message.converges_to));
} else if (Object.hasOwn(message, 'see_also')) {
setSeeAlso(JSON.parse(message.see_also));
} else if (Object.hasOwn(message, 'delta')) {
const incomingDeltaData = JSON.parse(message.delta);
if (incomingDeltaData.length > 0) {
Expand Down Expand Up @@ -193,6 +197,7 @@ function Form() {
limit={limit}
symbol={isolateSymbol()}
convergesTo={convergesTo}
seeAlso={seeAlso}
deltaData={deltaData}
toggleDisplay={() => {
setNoConvergence(false);
Expand Down
2 changes: 1 addition & 1 deletion react-frontend/src/components/ScatterPlot.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@ import React, { useEffect } from 'react';
import * as d3 from 'd3';
import { CoordinatePair } from '../lib/types';

const svg_width = 560,
const svg_width = 860,
svg_height = 400;

const ScatterPlot = ({ id, data }: { id: string; data?: CoordinatePair[] }) => {
Expand Down
5 changes: 5 additions & 0 deletions react-frontend/src/lib/constants.ts
Original file line number Diff line number Diff line change
Expand Up @@ -334,6 +334,11 @@ const constants: { [abbrev: string]: Constant } = {
url: 'https://mathworld.wolfram.com/WeierstrassConstant.html'
},
W: { name: 'Wallis Constant', url: 'https://mathworld.wolfram.com/WallissConstant.html' },
Zeta2: {
replacement: 'ζ(2)',
name: 'Riemann Zeta Function',
url: 'https://en.wikipedia.org/wiki/Riemann_zeta_function'
},
Zeta3: {
replacement: 'ζ(3)',
name: 'Apery Constant',
Expand Down

0 comments on commit 51c1e33

Please sign in to comment.