Skip to content

Commit

Permalink
feat: ✨ 2.7.0——真值缺省支持
Browse files Browse the repository at this point in the history
1. ✨对形如`A.`、`A. %0.5%`的语句增加「空真值」「单真值」支持,使其互转更为精确
2. 🔥基于「真值缺省」支持,不再硬编码默认真值`%1.0; 0.9%`
3. 相应更新测试、各内置解析器和文档导图
  • Loading branch information
ARCJ137442 committed Jan 27, 2024
1 parent d3dd655 commit 551988d
Show file tree
Hide file tree
Showing 23 changed files with 196 additions and 50 deletions.
2 changes: 1 addition & 1 deletion Project.toml
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ uuid = "11330a76-bea1-45e0-8f80-7114e2f607b1"
authors = ["ARCJ137442 <61109168+ARCJ137442@users.noreply.github.com>"]
git-tree-sha1 = "308b5830bd3f1eb7f6bde386a3a23b3ce8b3365e"
repo-url = "https://github.com/ARCJ137442/JuNarsese.jl"
version = "2.6.3"
version = "2.7.0"

[deps]
Reexport = "189a3867-3050-52da-a836-e630ba90ab69"
Expand Down
Binary file modified docs/JuNarsese导图/JuNarsese导图.xmind
Binary file not shown.
Binary file modified docs/JuNarsese导图/词项.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
19 changes: 16 additions & 3 deletions src/Conversion/core/string.jl
Original file line number Diff line number Diff line change
Expand Up @@ -772,13 +772,16 @@ end

begin "语句相关"

"真值→字符串"
"真值→字符串(通用@单真值、双真值)"
narsese2data(parser::StringParser, t::ATruth) = form_truth!budget(
parser.truth_brackets..., parser.truth_separator,
collect(t)
)

"真值→字符串"
"真值→字符串(空真值)"
narsese2data(parser::StringParser, ::TruthNull) = ""

"预算值→字符串"
narsese2data(parser::StringParser, b::ABudget) = form_truth!budget(
parser.budget_brackets..., parser.budget_separator,
collect(b)
Expand Down Expand Up @@ -875,6 +878,7 @@ begin "语句相关"
parser::StringParser, ::Type{Truth}, s::AbstractString,
stripped::Bool = false
)
# 未剥皮⇒剥皮 #
if !stripped
left::String, right::String = parser.truth_brackets
return data2narsese(
Expand All @@ -883,7 +887,16 @@ begin "语句相关"
true # 标示已经剥皮
)
end
# 剥皮后
# 剥皮后⇒尝试分隔,分为「无真值、单真值与双真值」 #
# 空字串⇒空真值
isempty(s) && return TruthNull()
# 无分隔符⇒单真值
if !contains(s, parser.truth_separator) # 无分隔符
return Narsese.default_precision_truth(
Narsese.parse_default_float(s)
)
end
# 最终⇒双真值
f_str::AbstractString, c_str::AbstractString = split(
s, # 已剥皮,待分割
parser.truth_separator # 分隔符
Expand Down
8 changes: 4 additions & 4 deletions src/Narsese/Sentences/sentence.jl
Original file line number Diff line number Diff line change
Expand Up @@ -44,7 +44,7 @@ end
@inline function SentenceJudgement(
term::Term; # 下面无顺序,作为可选参数
stamp::Stamp = StampBasic(),
truth::ATruth = Truth64(1.0, 0.5),
truth::ATruth = truth_null, # !【2024-01-27 16:29:04】现在默认为空真值(未指定状态)
)
SentenceJudgement(
term,
Expand All @@ -69,7 +69,7 @@ end
@inline function SentenceGoal(
term::Term; # 下面无顺序,作为可选参数
stamp::Stamp = StampBasic(),
truth::ATruth = Truth64(1.0, 0.5),
truth::ATruth = truth_null, # !【2024-01-27 16:29:04】现在默认为空真值(未指定状态)
)
SentenceGoal(
term,
Expand All @@ -93,7 +93,7 @@ end
@inline function SentenceQuestion(
term::Term; # 下面无顺序,作为可选参数
stamp::Stamp = StampBasic(),
truth::UNothing{TruthBasic} = nothing # 📝Julia: 可选参数中不能省略参数变量名,会导致「畸形表达式」错误
truth::UNothing{ATruth} = nothing # 📝Julia: 可选参数中不能省略参数变量名,会导致「畸形表达式」错误
)
SentenceQuestion(
term,
Expand All @@ -115,7 +115,7 @@ end
@inline function SentenceQuest(
term::Term; # 下面无顺序,作为可选参数
stamp::Stamp = StampBasic(), # 将「只有一个参数」的情况交给上面
truth::UNothing{TruthBasic} = nothing
truth::UNothing{ATruth} = nothing
)
SentenceQuest(
term,
Expand Down
126 changes: 113 additions & 13 deletions src/Narsese/Sentences/truth.jl
Original file line number Diff line number Diff line change
@@ -1,11 +1,18 @@
#=
实现Narsese中的「二元真值」数据结构
- ⚠只提供结构,不提供算法
- 📝因「语法缺省」引出的几个概念:
- 空真值:f、c均缺省,二值均未定义的真值(占位符)
- 单真值:f已指定,但c仍缺省的真值(部分占位符)
- 双真值:f、c均已指定的真值(完全体)
=#

# 导出 #

export AbstractTruth, ATruth, Truth
export TruthNull, truth_null
export TruthSingle
export TruthSingle16, TruthSingle32, TruthSingle64, TruthSingleBig
export TruthBasic
export Truth16, Truth32, Truth64, TruthBig
export get_f, get_c, default_precision_truth
Expand All @@ -29,13 +36,16 @@ const Truth = ATruth = AbstractTruth

# 抽象类方法 #

"获取频率f"
"获取频率f: get_f(t::Truth)::Real"
# function get_f end # !【2024-01-27 16:57:06】暂不启用「抽象函数」的定义方式
# ! 其在作为Truth子类型,但【未实现获取f、c值,也未特化iterate方法(但string默认能collect)】并获取f/c报错时,会因「打印又需f/c」而继发报错
get_f(t::Truth) = error("$(typeof(t)): 未实现的`get_f`方法!")
"获取信度c"
"获取信度c: get_c(t::Truth)::Real"
# function get_c end
get_c(t::Truth) = error("$(typeof(t)): 未实现的`get_c`方法!")

"""
判等の法:相等@f,c
【通用】判等の法:相等@f,c
- 判等忽略数值精度
"""
Base.:(==)(t1::Truth, t2::Truth)::Bool = (
Expand All @@ -51,21 +61,109 @@ Base.iterate(t::Truth, state=1) = iterate([get_f(t), get_c(t)], state)
"长度恒等于2"
Base.length(t::Truth) = 2

# 空结构(作占位符) #

"""
定义在CommonNarsese中因【缺省】而对应的真值
- 在一个语句中充当【真值f、c完全缺省】的占位符
- 即:f、c均未指定
- 🔗参考:OpenNARS、PyNARS
@example nse"<A --> B>. :|:" ⇔ 空真值
"""
struct TruthNull <: AbstractTruth end

"空真值的单例常量"
const truth_null = TruthNull()

#= "锁定单例模式"
# !【2024-01-27 16:04:52】📝Juliaの无参结构 默认为单例模式
# * Juliaの单例模式:不管怎样,使用`TruthNull()`构造出来的都是一个对象(使用`===`仍然相等)
TruthNull() = truth_null =#

"判等逻辑"
Base.:(==)(::TruthNull, ::TruthNull) = true
Base.:(==)(::TruthNull, ::Truth) = false
Base.:(==)(::Truth, ::TruthNull) = false

"迭代为空:直接结束"
Base.iterate(::TruthNull) = nothing
Base.iterate(::TruthNull, ::Any) = nothing

"长度恒为0(便于区分)"
Base.length(::TruthNull) = 0

"获取f、c报错"
get_f(::TruthNull) = error("尝试获取空真值的f值")
get_c(::TruthNull) = error("尝试获取空真值的c值")

# 单值结构(作占位符) #

"""
定义在CommonNarsese中因【缺省】而对应的真值
- 在一个语句中充当【具有真值f,但c缺省】的占位符
- f值已指定 为实数
- c值交由对应「NARS实现」决定
- 🔗参考:OpenNARS、PyNARS
@example nse"<A --> B>. %0.5%" ⇔ 单真值(0.5)
"""
struct TruthSingle{F_TYPE <: Real} <: AbstractTruth
f::F_TYPE

"内部构造方法: 检查数值是否越界"
function TruthSingle{F_TYPE}(f::F_TYPE) where {F_TYPE <: Real}
# 检查边界
@assert 0 f 1 "数值`$f`越界!"# 闭区间
# 构造
new{F_TYPE}(f)
end
end

"外部构造方法:对于任意实数,都尝试转换为目标类型"
TruthSingle{F_TYPE}(f::Real) where {F_TYPE <: Real} = TruthSingle{F_TYPE}(convert(F_TYPE, f))

"外部构造方法(面向默认):使用默认精度"
@inline TruthSingle(f::Real) = TruthSingle{DEFAULT_FLOAT_PRECISION}(DEFAULT_FLOAT_PRECISION(f))

"【专用】判等逻辑:仅判断f相等"
Base.:(==)(t1::TruthSingle, t2::TruthSingle) = number_value_eq(get_f(t1), get_f(t2))
Base.:(==)(::TruthSingle, ::Truth) = false
Base.:(==)(::Truth, ::TruthSingle) = false

"迭代为空:直接结束"
Base.iterate(t::TruthSingle, state=1) = iterate([get_f(t)], state)

"长度恒等于1"
Base.length(t::TruthSingle) = 1

"获取f有值"
get_f(t::TruthSingle) = t.f
"获取c报错"
get_c(::TruthSingle) = error("尝试获取单真值的c值")

# 别名:各类精度的单真值 #
const TruthSingle16::DataType = TruthSingle{Float16}
const TruthSingle32::DataType = TruthSingle{Float32}
const TruthSingle64::DataType = TruthSingle{Float64}

const TruthSingleBig::DataType = TruthSingle{BigFloat} # 大浮点

# 基础结构 #

"""
可配置的「真值」类型
- 允许背后对f、c值类型的自定义
- 二者必须是[0,1]的浮点数
- 二者必须是[0,1]的实数
"""
struct TruthBasic{F_TYPE <: AbstractFloat, C_TYPE <: AbstractFloat} <: AbstractTruth
struct TruthBasic{F_TYPE <: Real, C_TYPE <: Real} <: AbstractTruth
f::F_TYPE
c::C_TYPE

"内部构造方法: 检查数值是否越界"
function TruthBasic{F_TYPE, C_TYPE}(f::F_TYPE, c::C_TYPE) where {
F_TYPE <: AbstractFloat,
C_TYPE <: AbstractFloat,
F_TYPE <: Real,
C_TYPE <: Real,
}

# 检查边界
Expand All @@ -79,8 +177,8 @@ end

"外部构造方法:对于任意实数,都尝试转换为目标类型"
function TruthBasic{F_TYPE, C_TYPE}(f::Real, c::Real) where {
F_TYPE <: AbstractFloat,
C_TYPE <: AbstractFloat,
F_TYPE <: Real,
C_TYPE <: Real,
}

TruthBasic{F_TYPE, C_TYPE}(
Expand All @@ -89,18 +187,20 @@ function TruthBasic{F_TYPE, C_TYPE}(f::Real, c::Real) where {
)
end

"外部构造方法:只指定一个参数类型,相当于复制两个类型"
"外部构造方法:只指定一个参数类型,相当于复制两个类型(但仍然是双真值)"
@inline TruthBasic{V_TYPE}(args...) where {V_TYPE} = TruthBasic{V_TYPE, V_TYPE}(args...)

"外部构造方法(面向默认):使用默认精度"
@inline TruthBasic(f::Real, c::Real) = TruthBasic{DEFAULT_FLOAT_PRECISION}(
DEFAULT_FLOAT_PRECISION(f), DEFAULT_FLOAT_PRECISION(c)
)

"外部构造方法(面向默认):提供默认精度,并统一提供默认值"
default_precision_truth(f::Real = 1.0, c::Real = 0.5) = TruthBasic(f, c)
"外部构造方法(面向默认)" # ! 不再提供默认真值,而是经由「空真值/单真值」交给下游处理(以保证可互转)
default_precision_truth() = truth_null
default_precision_truth(f::Real) = TruthSingle(f)
default_precision_truth(f::Real, c::Real) = TruthBasic(f, c)

# 别名:各类精度的真值 #
# 别名:各类精度的双真值 #
const Truth16::DataType = TruthBasic{Float16, Float16}
const Truth32::DataType = TruthBasic{Float32, Float32}
const Truth64::DataType = TruthBasic{Float64, Float64}
Expand Down
2 changes: 1 addition & 1 deletion src/Narsese/Terms/methods.jl
Original file line number Diff line number Diff line change
Expand Up @@ -60,7 +60,7 @@ begin "NAL信息支持"
- 等价于:虚方法/抽象方法
- 需要被子类实现
"""
@inline get_syntactic_complexity(t::Term) = error("$(typeof(t))未定义的计算!")
@inline get_syntactic_complexity(t::Term) = error("$(typeof(t)): 未定义的计算!")

"""
(默认)原子の复杂度 = 1
Expand Down
2 changes: 1 addition & 1 deletion test/conversion/test_api.jl
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
(@isdefined JuNarsese) || include("../commons.jl") # 已在此中导入JuNarsese、Test
(@isdefined JuNarsese) || include("../test_commons.jl") # 已在此中导入JuNarsese、Test

@testset "Conversion/API" begin

Expand Down
2 changes: 1 addition & 1 deletion test/conversion/test_parsers.jl
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
(@isdefined JuNarsese) || include("../commons.jl") # 已在此中导入JuNarsese、Test
(@isdefined JuNarsese) || include("../test_commons.jl") # 已在此中导入JuNarsese、Test

begin "报错debug专用"
# 测试@原生对象
Expand Down
6 changes: 3 additions & 3 deletions test/narsese/test_api.jl
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
(@isdefined JuNarsese) || include("../commons.jl") # 已在此中导入JuNarsese、Test
(@isdefined JuNarsese) || include("../test_commons.jl") # 已在此中导入JuNarsese、Test

# 词项接口:用于后续扩展自定义词项/语句/任务 #
@testset "Narsese/API" begin
Expand All @@ -16,8 +16,8 @@

@test @expectedError get_syntactic_complexity(t)

@test @expectedError get_f(tt)
@test @expectedError get_c(tt)
@test @expectedError get_f(tt) # 未定义
@test @expectedError get_c(tt) # 未定义

@test @expectedError get_p(tb)
@test @expectedError get_d(tb)
Expand Down
45 changes: 33 additions & 12 deletions test/narsese/test_construction.jl
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
(@isdefined JuNarsese) || include("../commons.jl") # 已在此中导入JuNarsese、Test
(@isdefined JuNarsese) || include("../test_commons.jl") # 已在此中导入JuNarsese、Test

# 词项构建测试 #
@testset "construction" begin
Expand Down Expand Up @@ -154,17 +154,38 @@

# 真值/欲望值/预算值越界

@test @expectedError SentenceJudgement(
s5,
StampBasic(),
Truth64(1.1, 0.9), # f越界
)

@test @expectedError SentenceGoal(
s5,
StampBasic(),
Truth64(0, -1.0), # c越界
)
# 空真值
@test TruthNull() isa TruthNull # 无需参数
@test TruthNull() === TruthNull() === truth_null # 单例模式
@test @expectedError TruthNull(1.0) # 参数过多
@test @expectedError TruthNull(0.1, 0.9) # 参数过多
@test @expectedError get_f(truth_null) # 非法获取f值
@test @expectedError get_c(truth_null) # 非法获取c值

@test isempty(string(truth_null)) # 本身为「字符串缺省」而设计
@test !contains(string(nse"A."), ';') # 本身为「字符串缺省」而设计
@test get_truth(nse"A.") === truth_null # 缺省占位符@判断
@test get_truth(nse"<{SELF} --> [good]>!") === truth_null # 缺省占位符@目标

# 单真值
for T in [TruthSingle16, TruthSingle32, TruthSingle64, TruthSingleBig]
@test @expectedError T(0.1, 0.9) # 参数过多
@test @expectedError T(1.1) # f越界@大于一
@test @expectedError T(-0.1) # f越界@负数
@test @expectedError get_c(T(0.5)) # 非法获取c值

@test !contains(string(nse"A. %0.5%"), ';') # 本身为「字符串缺省」而设计
@test get_truth(nse"A. %0.5%") isa TruthSingle # 缺省占位符@判断
@test get_truth(nse"<{SELF} --> [good]>! %0.5%") isa TruthSingle # 缺省占位符@目标
end

# 双真值
for T in [Truth16, Truth32, Truth64, TruthBig]
@test @expectedError T(1.1, 0.9) # f越界@大于一
@test @expectedError T(-0.1, 0.9) # f越界@负数
@test @expectedError T(0, 1.1) # c越界@大于一
@test @expectedError T(0, -1.0) # c越界@负数
end

# 合法情况
@test BudgetBasic(1, 1.0, 0.1) isa Budget
Expand Down
2 changes: 1 addition & 1 deletion test/narsese/test_methods.jl
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
(@isdefined JuNarsese) || include("../commons.jl") # 已在此中导入JuNarsese、Test
(@isdefined JuNarsese) || include("../test_commons.jl") # 已在此中导入JuNarsese、Test

@testset "Narsese/methods" begin

Expand Down
Loading

0 comments on commit 551988d

Please sign in to comment.