Complex domain parsing

This commit is contained in:
Adsooi 2020-12-25 01:20:57 +01:00
parent 550b524a27
commit 29cb6a22a1

View file

@ -55,6 +55,10 @@ class Expression {
return Utils.makeExpressionReadable(expr.toString()) return Utils.makeExpressionReadable(expr.toString())
} }
duplicate() {
return new Expression(this.toEditableString())
}
toEditableString() { toEditableString() {
return this.calc.toString() return this.calc.toString()
} }
@ -74,39 +78,20 @@ function executeExpression(expr){
} }
// Domains // Domains
class Domain {
class EmptySet {
constructor() {} constructor() {}
includes(x) { return false } includes(x) { return false }
toString() { return "∅" } toString() { return '???' }
union(domain) { return domain }
intersection(domain) { return this }
static import(frm) { return new EmptySet() } static import(frm) { return new EmptySet() }
}
class Domain { static import(frm) {
constructor(begin, end, openBegin, openEnd) {
if(typeof begin == 'number' || typeof begin == 'string') begin = new Expression(begin.toString())
this.begin = begin
if(typeof end == 'number' || typeof end == 'string') end = new Expression(end.toString())
this.end = end
this.openBegin = openBegin
this.openEnd = openEnd
this.displayName = (openBegin ? "]" : "[") + begin.toString() + ";" + end.toString() + (openEnd ? "[" : "]")
}
includes(x) {
if(typeof x == 'string') x = executeExpression(x)
return ((this.openBegin && x > this.begin.execute()) || (!this.openBegin && x >= this.begin.execute())) &&
((this.openEnd && x < this.end.execute()) || (!this.openEnd && x <= this.end.execute()))
}
toString() {
return this.displayName
}
static importFrom(frm) {
switch(frm.trim().toUpperCase()) { switch(frm.trim().toUpperCase()) {
case "R": case "R":
case "": case "":
@ -144,27 +129,86 @@ class Domain {
return Domain.RME return Domain.RME
break; break;
default: default:
var openBegin = frm.trim().charAt(0) == "]" return EmptySet()
var openEnd = frm.trim().charAt(frm.length -1) == "["
var [begin, end] = frm.substr(1, frm.length-2).split(";")
return new Domain(begin.trim(), end.trim(), openBegin, openEnd)
break; break;
} }
} }
} }
Domain.R = new Domain(-Infinity,Infinity,true,true)
class EmptySet extends Domain {
includes(x) { return false }
toString() { return "∅" }
union(domain) { return domain }
intersection(domain) { return this }
static import(frm) { return new EmptySet() }
}
class Interval extends Domain {
constructor(begin, end, openBegin, openEnd) {
super()
if(typeof begin == 'number' || typeof begin == 'string') begin = new Expression(begin.toString())
this.begin = begin
if(typeof end == 'number' || typeof end == 'string') end = new Expression(end.toString())
this.end = end
this.openBegin = openBegin
this.openEnd = openEnd
this.displayName = (openBegin ? "]" : "[") + begin.toString() + ";" + end.toString() + (openEnd ? "[" : "]")
}
includes(x) {
if(typeof x == 'string') x = executeExpression(x)
return ((this.openBegin && x > this.begin.execute()) || (!this.openBegin && x >= this.begin.execute())) &&
((this.openEnd && x < this.end.execute()) || (!this.openEnd && x <= this.end.execute()))
}
toString() {
return this.displayName
}
union(domain) {
if(domain instanceof EmptySet) return this
if(domain instanceof DomainSet) return domain.union(this)
if(domain instanceof UnionDomain) return domain.union(this)
if(domain instanceof IntersectionDomain) return new UnionDomain(this, domain)
if(domain instanceof MinusDomain) return new UnionDomain(this, domain)
if(domain instanceof Interval) return new UnionDomain(this, domain)
}
intersection(domain) {
if(domain instanceof EmptySet) return domain
if(domain instanceof DomainSet) return domain.intersection(this)
if(domain instanceof UnionDomain) return new IntersectionDomain(this, domain)
if(domain instanceof IntersectionDomain) return domain.intersection(this)
if(domain instanceof MinusDomain) return new IntersectionDomain(this, domain)
if(domain instanceof Interval) return new IntersectionDomain(this, domain)
}
static import(frm) {
var openBegin = frm.trim().charAt(0) == "]"
var openEnd = frm.trim().charAt(frm.length -1) == "["
var [begin, end] = frm.substr(1, frm.length-2).split(";")
return new Interval(begin.trim(), end.trim(), openBegin, openEnd)
}
}
Domain.R = new Interval(-Infinity,Infinity,true,true)
Domain.R.displayName = "" Domain.R.displayName = ""
Domain.RP = new Domain(0,Infinity,true,false) Domain.RP = new Interval(0,Infinity,true,false)
Domain.RP.displayName = "ℝ⁺" Domain.RP.displayName = "ℝ⁺"
Domain.RM = new Domain(-Infinity,0,true,false) Domain.RM = new Interval(-Infinity,0,true,false)
Domain.RM.displayName = "ℝ⁻" Domain.RM.displayName = "ℝ⁻"
Domain.RPE = new Domain(0,Infinity,true,true) Domain.RPE = new Interval(0,Infinity,true,true)
Domain.RPE.displayName = "ℝ⁺*" Domain.RPE.displayName = "ℝ⁺*"
Domain.RME = new Domain(-Infinity,0,true,true) Domain.RME = new Interval(-Infinity,0,true,true)
Domain.RME.displayName = "ℝ⁻*" Domain.RME.displayName = "ℝ⁻*"
class DomainSet { class DomainSet extends Domain {
constructor(values) { constructor(values) {
super()
var newVals = [] var newVals = []
values.forEach(function(value){ values.forEach(function(value){
newVals.push(new Expression(value.toString())) newVals.push(new Expression(value.toString()))
@ -174,27 +218,79 @@ class DomainSet {
includes(x) { includes(x) {
if(typeof x == 'string') x = executeExpression(x) if(typeof x == 'string') x = executeExpression(x)
var found = false for(var i = 0; i < this.values.length; i++)
this.values.forEach(function(value){ if(x == this.values[i].execute()) return true
if(x == value.execute()) { return false
found = true
return
}
})
return found
} }
toString() { toString() {
return "{" + this.values.join(";") + "}" return "{" + this.values.join(";") + "}"
} }
static importFrom(frm) { union(domain) {
if(domain instanceof EmptySet) return this
if(domain instanceof DomainSet) {
var newValues = []
var values = this.values.concat(domain.values).filter(function(val){
newValues.push(val.execute())
return newValues.indexOf(val.execute()) == newValues.length - 1
})
return new DomainSet(values)
}
var notIncludedValues = []
for(var i = 0; i < this.values.length; i++) {
var value = this.values[i].execute()
if(domain instanceof Interval) {
if(domain.begin.execute() == value && domain.openBegin) {
domain.openBegin = false
}
if(domain.end.execute() == value && domain.openEnd) {
domain.openEnd = false
}
}
if(!domain.includes(value))
notIncludedValues.push(this.values[i].toEditableString())
}
if(notIncludedValues.length == 0) return domain
return new UnionDomain(domain, new DomainSet(notIncludedValues))
}
intersection(domain) {
if(domain instanceof EmptySet) return domain
if(domain instanceof DomainSet) {
var domValues = domain.values.map(expr => expr.execute())
this.values = this.values.filter(function(val){
return domValues.indexOf(val.execute()) >= 0
})
return this
}
var includedValues = []
for(var i = 0; i < this.values.length; i++) {
var value = this.values[i].execute()
if(domain instanceof Interval) {
if(domain.begin.execute() == value && !domain.openBegin) {
domain.openBegin = false
}
if(domain.end.execute() == value && !domain.openEnd) {
domain.openEnd = false
}
}
if(domain.includes(value))
includedValues.push(this.values[i].toEditableString())
}
if(includedValues.length == 0) return new EmptySet()
if(includedValues.length == this.values.length) return this
return new IntersectionDomain(domain, new DomainSet(includedValues))
}
static import(frm) {
return new DomainSet(frm.substr(1, frm.length-2).split(";")) return new DomainSet(frm.substr(1, frm.length-2).split(";"))
} }
} }
class UnionDomain { class UnionDomain extends Domain {
constructor(dom1, dom2) { constructor(dom1, dom2) {
super()
this.dom1 = dom1 this.dom1 = dom1
this.dom2 = dom2 this.dom2 = dom2
} }
@ -207,15 +303,36 @@ class UnionDomain {
return this.dom1.toString() + " " + this.dom2.toString() return this.dom1.toString() + " " + this.dom2.toString()
} }
static importFrom(frm) { union(domain) {
if(domain instanceof EmptySet) return this
if(domain instanceof DomainSet) return domain.union(this)
if(domain instanceof Interval) return domain.union(this)
if(domain instanceof UnionDomain) return new UnionDomain(this, domain)
if(domain instanceof IntersectionDomain) return new UnionDomain(this, domain)
if(domain instanceof MinusDomain) return new MinusDomain(this, domain)
}
intersection(domain) {
if(domain instanceof EmptySet) return domain
if(domain instanceof DomainSet) return domain.intersection(this)
if(domain instanceof UnionDomain) return new IntersectionDomain(this, domain)
if(domain instanceof IntersectionDomain) return this.dom1.intersection(domain.dom1).intersection(this.dom2).intersection(domain.dom2)
if(domain instanceof MinusDomain) return new IntersectionDomain(this, domain)
}
static import(frm) {
var domains = frm.trim().split("") var domains = frm.trim().split("")
if(domains.length == 1) domains = frm.trim().split("U") // Fallback if(domains.length == 1) domains = frm.trim().split("U") // Fallback
return new UnionDomain(parseDomain(domains[0].trim()), parseDomain(domains[1].trim())) var dom1 = parseDomain(domains.pop())
var dom2 = parseDomain(domains.join(''))
console.log('Union', dom1, dom2)
return dom1.union(dom2)
} }
} }
class IntersectionDomain { class IntersectionDomain extends Domain {
constructor(dom1, dom2) { constructor(dom1, dom2) {
super()
this.dom1 = dom1 this.dom1 = dom1
this.dom2 = dom2 this.dom2 = dom2
} }
@ -228,14 +345,34 @@ class IntersectionDomain {
return this.dom1.toString() + " ∩ " + this.dom2.toString() return this.dom1.toString() + " ∩ " + this.dom2.toString()
} }
static importFrom(frm) { union(domain) {
if(domain instanceof EmptySet) return this
if(domain instanceof DomainSet) return domain.union(this)
if(domain instanceof Interval) return domain.union(this)
if(domain instanceof UnionDomain) return this.dom1.union(domain.dom1).union(this.dom2).union(domain.dom2)
if(domain instanceof IntersectionDomain) return new UnionDomain(this, domain)
if(domain instanceof MinusDomain) return new MinusDomain(this, domain)
}
intersection(domain) {
if(domain instanceof EmptySet) return domain
if(domain instanceof DomainSet) return domain.intersection(this)
if(domain instanceof UnionDomain) return new IntersectionDomain(this, domain)
if(domain instanceof IntersectionDomain) return new IntersectionDomain(this, domain)
if(domain instanceof MinusDomain) return new IntersectionDomain(this, domain)
}
static import(frm) {
var domains = frm.trim().split("∩") var domains = frm.trim().split("∩")
return new IntersectionDomain(parseDomain(domains[0].trim()), parseDomain(domains[1].trim())) var dom1 = parseDomain(domains.pop())
var dom2 = parseDomain(domains.join(''))
return dom1.intersection(dom2)
} }
} }
class MinusDomain { class MinusDomain extends Domain {
constructor(dom1, dom2) { constructor(dom1, dom2) {
super()
this.dom1 = dom1 this.dom1 = dom1
this.dom2 = dom2 this.dom2 = dom2
} }
@ -248,23 +385,40 @@ class MinusDomain {
return this.dom1.toString() + "" + this.dom2.toString() return this.dom1.toString() + "" + this.dom2.toString()
} }
static importFrom(frm) { static import(frm) {
var domains = frm.trim().split("") var domains = frm.trim().split("")
if(domains.length == 1) domains = frm.trim().split("\\") // Fallback if(domains.length == 1) domains = frm.trim().split("\\") // Fallback
return new MinusDomain(parseDomain(domains[0].trim()), parseDomain(domains[1].trim())) var dom1 = parseDomain(domains.pop())
var dom2 = parseDomain(domains.join(''))
return new MinusDomain(dom1, dom2)
} }
} }
Domain.RE = new MinusDomain("R", "{0}") Domain.RE = new MinusDomain("R", "{0}")
Domain.RE.displayName = "*" Domain.RE.displayName = "*"
var refedDomains = []
function parseDomain(domain) { function parseDomain(domain) {
if(domain.indexOf("U") >= 0 || domain.indexOf("") >= 0) return UnionDomain.importFrom(domain) if(!domain.includes(')') && !domain.includes('(')) return parseDomainSimple(domain)
if(domain.indexOf("∩") >= 0) return IntersectionDomain.importFrom(domain) var domStr
if(domain.indexOf("") >= 0 || domain.indexOf("\\") >= 0) return MinusDomain.importFrom(domain) while((domStr = /\(([^)(]+)\)/.exec(domain)) !== null) {
if(domain.charAt(0) == "{" && domain.charAt(domain.length -1) == "}") return DomainSet.importFrom(domain) var dom = parseDomainSimple(domStr[1]);
if(domain.indexOf("]") >= 0 || domain.indexOf("]") >= 0) return Domain.importFrom(domain) console.log(domain, domStr[0])
if(domain.toUpperCase().indexOf("R") >= 0 || domain.indexOf("") >= 0) return Domain.importFrom(domain) domain = domain.replace(domStr[0], 'D' + refedDomains.length)
refedDomains.push(dom)
}
return parseDomainSimple(domain)
}
function parseDomainSimple(domain) {
console.log('Parsing domain', domain, typeof domain)
if(domain[0] == 'D') return refedDomains[parseInt(domain.substr(1))]
if(domain.indexOf("U") >= 0 || domain.indexOf("") >= 0) return UnionDomain.import(domain)
if(domain.indexOf("∩") >= 0) return IntersectionDomain.import(domain)
if(domain.indexOf("") >= 0 || domain.indexOf("\\") >= 0) return MinusDomain.import(domain)
if(domain.charAt(0) == "{" && domain.charAt(domain.length -1) == "}") return DomainSet.import(domain)
if(domain.indexOf("]") >= 0 || domain.indexOf("[") >= 0) return Interval.import(domain)
if(domain.toUpperCase().indexOf("R") >= 0 || domain.indexOf("") >= 0) return Domain.import(domain)
return new EmptySet() return new EmptySet()
} }