Good to know, thanks. I seem to recall that this wasn't always so, or perhaps I just do it out of habit? In any case, that's one less burden to deal with which is always nice...fxm wrote:Even with composite type members, the implicit destructor (added at compilation time by the FB compiler) is sufficient to properly call the destructor (explicit, or implicit as for strings and arrays) of each composite type member.
[SOLVED] turning working KNN code into a static library
Re: [HELP] turning working KNN code into a static library
Re: [SOLVED] turning working KNN code into a static library
Here is an example skipping external files (except the .csv file of course, the code is short anyway)
The number of numerical columns can be retrieved without asking the user.
(don't need constructors or destructors here)
The number of numerical columns can be retrieved without asking the user.
(don't need constructors or destructors here)
Code: Select all
#INCLUDE "file.bi"
Type pt
As Double l(any)
As String nm
As Long done
End Type
Sub printout(p As pt)
For n As Long=1 To ubound(p.l)
Print p.l(n);",";
Next
Print p.nm
End Sub
Function Splitstring(s_in As String,chars As String,result() As String) As Long
Dim As Long ctr,ctr2,k,n,LC=Len(chars)
Dim As boolean tally(Len(s_in))
#macro check_instring()
n=0
While n<Lc
If chars[n]=s_in[k] Then
tally(k)=true
If (ctr2-1) Then ctr+=1
ctr2=0
Exit While
End If
n+=1
Wend
#endmacro
#macro splice()
If tally(k) Then
If (ctr2-1) Then ctr+=1:result(ctr)=Mid(s_in,k+2-ctr2,ctr2-1)
ctr2=0
End If
#endmacro
'================== LOOP TWICE =======================
For k =0 To Len(s_in)-1
ctr2+=1:check_instring()
Next k
If ctr=0 Then
If Len(s_in) Andalso Instr(chars,Chr(s_in[0])) Then ctr=1':beep
End If
If ctr Then Redim result(1 To ctr): ctr=0:ctr2=0 Else Return 0
For k =0 To Len(s_in)-1
ctr2+=1:splice()
Next k
'===================== Last one ========================
If ctr2>0 Then
Redim Preserve result(1 To ctr+1)
result(ctr+1)=Mid(s_in,k+1-ctr2,ctr2)
End If
Return Ubound(result)
End Function
Function loadfiletostring(file As String) As String
Var f=Freefile
Open file For Binary Access Read As #f
Dim As String text
If Lof(f) > 0 Then
text = String(Lof(f), 0)
Get #f, , text
End If
Close #f
Return text
End Function
Function vdist(p1 As pt,p2 As pt) As Double
Dim As Double acc
For n As Long=Lbound(p1.l) To Ubound(p1.l)
acc+=(p1.l(n)-p2.l(n))^2
Next
Return Sqr(acc)
End Function
Function GetClosest(a() As pt,ans() As Long,v As pt,num As Long) As Long
Dim As Double d,i
Dim As Long ctr
Do
d=2e8
For n As Long=Lbound(a) To Ubound(a)
Var dst=vdist(a(n),v)
If d>dst And a(n).done=0 Then d=dst:i=n:a(n).done=1
Next n
ctr+=1
Redim Preserve ans(1 To ctr)
ans(ctr)=i
Loop Until Ubound(ans)>=num
Return Ubound(ans)
End Function
SUB knn_main(f AS STRING)
dim as long col
Dim As String s=loadfiletostring(f)'("knn-dataset-plant.csv")
Redim As String g()
redim as string tmp()
splitstring(s,Chr(10),g()) 'load the file into a string array g()
'test to get col
splitstring(g(1),",",tmp())
col=ubound(tmp)-1 'get the dimension here (col)
Dim As pt array(Lbound(g) To UBOUND(g))
For n As Long=Lbound(array) To UBOUND(array)
splitstring(g(n),",",tmp())''load into tmp() with the , as seperator.
redim (array(n).l)(1 to col)' Must do!!
For m As Long=1 To col
array(n).l(m)=Val(tmp(m)) 'pick out the values to suit the udt, here, the doubles
Next m
array(n).nm=tmp(col+1) 'OK because tmp(col+1)=tmp(ubound(tmp)) which is the string field
print n,
printout(array(n))
Next
print
Redim As Long near()
GetClosest(array(),near(),array(10),3)'' <<-------- here, get 3 closest to array(10)
print "This is a fixed test for 3 (closest to 10 and including 10): using Getclosest()"
Print "index",,"values"
For n As Long=Lbound(near) To Ubound(near)
Print near(n),
printout array(near(n))
Next
'============= new predictions!!!=================
DIM answer AS STRING
DO
DIM predict AS pt
DIM AS DOUBLE x1
DIM neighbors AS LONG
print
dim as string s
do
print "press 1 for closest to a flower"
print "press 2 to enter predicted values"
s=input(1)
loop until s="1" or s="2"
if s="1" then
do
print "Between ";lbound(array);" and ";ubound(array)
INPUT "insert index : "; x1
loop until x1>=lbound(array) and x1<=ubound(array)
end if
if s="2" then
dim as double v
redim predict.l(1 to col)
for n as long=1 to col
print n; " of ";col;", enter a value ";
input; v
print
predict.l(n)=v
next n
end if
INPUT "how many neighbors TO search?: "; neighbors
FOR i AS INTEGER = LBOUND(array) TO UBOUND(array)'reset the array
array(i).done = 0
NEXT
Redim As Long near()
if s="1" then GetClosest(array(),near(),array(x1),neighbors) 'using an existing array element
if s="2" then GetClosest(array(),near(),predict,neighbors)' <- new predictions for new values
print "using Getclosest()"
Print "index",,"values"
For n As Long=Lbound(near) To Ubound(near)
Print near(n),
printout array(near(n))
NEXT
print "another prediction? y/n: "
answer=input(1)
LOOP UNTIL answer = "n"
END SUB
'========== RUN ==========
KNN_MAIN("iris.csv")
SLEEP()
Re: [HELP] turning working KNN code into a static library
Indeed, one can check with this example that the composite type member (ctm) is well destroyed without defining an explicit destructor in UDT1:paul doe wrote:Good to know, thanks. I seem to recall that this wasn't always so, or perhaps I just do it out of habit? In any case, that's one less burden to deal with which is always nice...fxm wrote:Even with composite type members, the implicit destructor (added at compilation time by the FB compiler) is sufficient to properly call the destructor (explicit, or implicit as for strings and arrays) of each composite type member.
Code: Select all
Type UDT0
Dim As Integer I
Declare Destructor ()
End Type
Destructor UDT0 ()
Print "UDT0.Destructor()"
End Destructor
Type UDT1
Dim As UDT0 ctm
End Type
Scope
Dim As UDT1 u1
End Scope
Sleep
Code: Select all
Type UDT0
Dim As Integer I
Declare Destructor ()
End Type
Destructor UDT0 ()
Print "UDT0.Destructor()"
End Destructor
Type Parent Extends Object
Declare Virtual Destructor ()
End Type
Destructor Parent ()
End destructor
Type Child Extends Parent
Dim As UDT0 ctm
Declare Virtual Destructor () Override
End Type
Destructor Child ()
End Destructor
Scope
Dim As Parent Ptr pp = New Child
Delete pp
End Scope
Sleep
Re: [HELP] turning working KNN code into a static library
Ah, I see. May I suggest adding that little clarification to the Wiki?fxm wrote:...
The reason is that implicit destructors are always added by the compiler but currently they are not declared virtual.
https://www.freebasic.net/wiki/KeyPgDestructor
It isn't stated there, and it's useful to know. Thanks!
Re: [SOLVED] turning working KNN code into a static library
This is already described in the Virtual documentation page, but I rewrote the sentence because not very clear:
Constructors, '=' Assignment-Operators, and Destructors (advanced, part #1)
Otherwise all of this is I think pretty well described in the Programmer's Guide:.....
Destructors often must be virtual when deleting an object manipulated through a pointer to its base type, so that the destruction starts at the most derived type and works its way down to the base type. To do this, it may be necessary to add virtual destructors with an empty body anywhere an explicit destruction was not yet required, in order to supersede each non-virtual implicit destructor built by the compiler.
.....
Constructors, '=' Assignment-Operators, and Destructors (advanced, part #1)
Re: [SOLVED] turning working KNN code into a static library
In this thread I don't think a udt holding the .csv file represents anything OOP, so what is the use of empty constructors and destructors?
In fact the whole thing can be done without a udt, in fact an array of string is more suited than a udt.
For a static library just skip the end bit
'========== RUN ==========
KNN_MAIN("iris.csv")
Sleep()
compile -lib
and only
#inclib "mylib"
declare Sub knn_main(f As String)
(so no real need for a .bi file)
In fact the whole thing can be done without a udt, in fact an array of string is more suited than a udt.
For a static library just skip the end bit
'========== RUN ==========
KNN_MAIN("iris.csv")
Sleep()
compile -lib
and only
#inclib "mylib"
declare Sub knn_main(f As String)
(so no real need for a .bi file)
Code: Select all
#INCLUDE "file.bi"
Function Splitstring(s_in As String,chars As String,result() As String) As Long
Dim As Long ctr,ctr2,k,n,LC=Len(chars)
Dim As boolean tally(Len(s_in))
#macro check_instring()
n=0
While n<Lc
If chars[n]=s_in[k] Then
tally(k)=true
If (ctr2-1) Then ctr+=1
ctr2=0
Exit While
End If
n+=1
Wend
#endmacro
#macro splice()
If tally(k) Then
If (ctr2-1) Then ctr+=1:result(ctr)=Mid(s_in,k+2-ctr2,ctr2-1)
ctr2=0
End If
#endmacro
'================== LOOP TWICE =======================
For k =0 To Len(s_in)-1
ctr2+=1:check_instring()
Next k
If ctr=0 Then
If Len(s_in) Andalso Instr(chars,Chr(s_in[0])) Then ctr=1':beep
End If
If ctr Then Redim result(1 To ctr): ctr=0:ctr2=0 Else Return 0
For k =0 To Len(s_in)-1
ctr2+=1:splice()
Next k
'===================== Last one ========================
If ctr2>0 Then
Redim Preserve result(1 To ctr+1)
result(ctr+1)=Mid(s_in,k+1-ctr2,ctr2)
End If
Return Ubound(result)
End Function
Function loadfiletostring(file As String) As String
Var f=Freefile
Open file For Binary Access Read As #f
Dim As String text
If Lof(f) > 0 Then
text = String(Lof(f), 0)
Get #f, , text
End If
Close #f
Return text
End Function
Function vdist(p1 As String,p2 As String,col As Long) As Double
Dim As Double acc
Redim As String t1(),t2()
splitstring(p1,",",t1())
splitstring(p2,",",t2())
For n As Long=1 To col
acc+=(Val(t1(n))-Val(t2(n)))^2
Next
Return Sqr(acc)
End Function
Function GetClosest(a() As String,ans() As Long,v As String,num As Long,col As Long) As Long
Dim As Double d,i
Dim As Long ctr
Dim As Long done(Lbound(a) To Ubound(a))
Do
d=2e8
For n As Long=Lbound(a) To Ubound(a)
Var dst=vdist(a(n),v,col)
If d>dst And done(n)=0 Then d=dst:i=n:done(n)=1
Next n
ctr+=1
Redim Preserve ans(1 To ctr)
ans(ctr)=i
Loop Until Ubound(ans)>=num
Return Ubound(ans)
End Function
Sub knn_main(f As String)
Dim As Long col
Dim As String s=loadfiletostring(f)'("knn-dataset-plant.csv")
Redim As String g()
Redim As String tmp()
splitstring(s,Chr(10),g()) 'load the file into a string array g()
'test to get col
splitstring(g(1),",",tmp())
col=Ubound(tmp)-1 'get the non strings parts of the string here (col)
Print "The file:"
For n As Long=Lbound(g) To Ubound(g)
Print n,g(n)
Next n
Print
Redim As Long near()
GetClosest(g(),near(),g(10),5,col)'' <<-------- here, get 3 closest to array(10)
Print "This is a fixed test for 5 (closest to 10 and including 10): using Getclosest()"
Print "index",,"values"
For n As Long=Lbound(near) To Ubound(near)
Print near(n),
Print g(near(n))
Next
'============= new predictions!!!=================
Dim answer As String
Do
Dim predict As String
Dim As Double x1
Dim neighbors As Long
Print
Dim As String s
Do
Print "press 1 for closest to a flower"
Print "press 2 to enter predicted values"
s=Input(1)
Loop Until s="1" Or s="2"
If s="1" Then
Do
Print "Between ";Lbound(g);" and ";Ubound(g)
Input "insert index : "; x1
Loop Until x1>=Lbound(g) And x1<=Ubound(g)
End If
If s="2" Then
Dim As Double v
Dim As String s
For n As Long=1 To col
Print n; " of ";col;", enter a value ";
Input; v
s+=Str(v)+","
Print
Next n
s=Rtrim(s,",")
predict=s
print, predict
End If
Input "how many neighbors TO search?: "; neighbors
Redim As Long near()
If s="1" Then GetClosest(g(),near(),g(x1),neighbors,col) 'using an existing array element
If s="2" Then GetClosest(g(),near(),predict,neighbors,col) ' <- new predictions for new values
Print "using Getclosest()"
Print "index",,"values"
For n As Long=Lbound(near) To Ubound(near)
Print near(n),
Print g(near(n))
Next
Print "another prediction? y/n: "
answer=Input(1)
Loop Until answer = "n"
End Sub
'========== RUN ==========
KNN_MAIN("iris.csv")
Sleep()
Re: [SOLVED] turning working KNN code into a static library
hello dodicat :)
thank you so much for your code examples and for keeping it simple. i like your last two code examples and the fact that there is no need for manually inserting how many numeric columns (values) there are in the the csv... i will add one of the codes to the library in the source folder...
the iris flower is really beautiful - it's easy to forget that while we occupy ourselves with ML and machine learning algorithms.
i wish to deeply thank you for helping me with the ML KNN and linear regression code examples it was thanks to those code examples i was able to modify and create the libraries for FB...
ron77.
thank you so much for your code examples and for keeping it simple. i like your last two code examples and the fact that there is no need for manually inserting how many numeric columns (values) there are in the the csv... i will add one of the codes to the library in the source folder...
the iris flower is really beautiful - it's easy to forget that while we occupy ourselves with ML and machine learning algorithms.
i wish to deeply thank you for helping me with the ML KNN and linear regression code examples it was thanks to those code examples i was able to modify and create the libraries for FB...
ron77.