Rocksolid Light

Welcome to novaBBS (click a section below)

mail  files  register  newsreader  groups  login

Message-ID:  

The last thing one knows in constructing a work is what to put first. -- Blaise Pascal


computers / comp.theory / Re: Implementing a two-way Turing Machine tape as an improvement to std::deque

Re: Implementing a two-way Turing Machine tape as an improvement to std::deque

<692dnROYz_PMWeD_nZ2dnUU7_83NnZ2d@giganews.com>

  copy mid

https://www.novabbs.com/computers/article-flat.php?id=32264&group=comp.theory#32264

  copy link   Newsgroups: comp.theory
Path: i2pn2.org!i2pn.org!weretis.net!feeder6.news.weretis.net!news.misty.com!border2.nntp.dca1.giganews.com!nntp.giganews.com!buffer2.nntp.dca1.giganews.com!news.giganews.com.POSTED!not-for-mail
NNTP-Posting-Date: Thu, 12 May 2022 21:37:05 -0500
Date: Thu, 12 May 2022 21:37:03 -0500
MIME-Version: 1.0
User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:91.0) Gecko/20100101
Thunderbird/91.9.0
Subject: Re: Implementing a two-way Turing Machine tape as an improvement to
std::deque
Content-Language: en-US
Newsgroups: comp.theory
References: <cNWdnXqV1cXzEuD_nZ2dnUU7_8zNnZ2d@giganews.com>
<87wneq1ejm.fsf@bsb.me.uk> <MeOdncpeZacPMeD_nZ2dnUU7_8zNnZ2d@giganews.com>
<8735he1abh.fsf@bsb.me.uk>
From: NoO...@NoWhere.com (olcott)
In-Reply-To: <8735he1abh.fsf@bsb.me.uk>
Content-Type: text/plain; charset=UTF-8; format=flowed
Content-Transfer-Encoding: 7bit
Message-ID: <692dnROYz_PMWeD_nZ2dnUU7_83NnZ2d@giganews.com>
Lines: 233
X-Usenet-Provider: http://www.giganews.com
X-Trace: sv3-lihfM50aLlo9robcHLXB8QDI1aJCYDrlg596SU4jVnU8A33ywqSDuEdR7QUzPOtY//3CsYYoNqFaEfo!MQH6Otu96d03NYgRDMDkJKtH8qau/v3SfAe+XH3uji1Cv+KB1NmqEVI0JOecFmdah/w8D1MeOAs=
X-Complaints-To: abuse@giganews.com
X-DMCA-Notifications: http://www.giganews.com/info/dmca.html
X-Abuse-and-DMCA-Info: Please be sure to forward a copy of ALL headers
X-Abuse-and-DMCA-Info: Otherwise we will be unable to process your complaint properly
X-Postfilter: 1.3.40
X-Original-Bytes: 9207
 by: olcott - Fri, 13 May 2022 02:37 UTC

On 5/12/2022 8:38 PM, Ben wrote:
> olcott <NoOne@NoWhere.com> writes:
>
>> On 5/12/2022 7:06 PM, Ben wrote:
>>> olcott <NoOne@NoWhere.com> writes:
>>> I've removed the philosophy group and comp.lang.c as this is C++.
>>>
>>>> C/C++ people please critique this as the basis for an improvement to
>>>> std::deque.
>>> You will get critiques of the code on whatever basis people feel
>>> inclined to comment! You can't limit the comments to some particular
>>> context.
>>>
>>>> It seems to have the key functionality of std::deque and
>>>> does it much more simply while saving time and space.
>>> It does not have any of the functionality of std::deque.
>>
>> That is a ridiculously stupid thing to say. It has the key most
>> important functionality of a std:deque
>
> Generally, when you think I am saying something absurd, you should
> re-consider.
>
> A deque has (at least) these operations:
>
> front
> back
> push_front
> push_back
> pop_front
> pop_back
>
> Your Tape_Type has none of these. Even internally it does not maintain
> the right data to be able to provide them.

I also added a reserve so you could do a pre-allocated speed test.

It was easy to add these in terms of the current implementation:

public:
tape_element& front( ) { return Left.back(); }
tape_element& back() { return Right.back(); }
void pop_front() { Left.pop_back(); }
void pop_back() { Right.pop_back(); }
void push_front(tape_element& E) { Left.push_back(E); }
void push_back(tape_element& E) { Right.push_back(E); }

void reserve(unsigned int N)
{ Left.reserve(N); Right.reserve(N); }

>> Double ended queue
>> deque (usually pronounced like "deck") is an irregular acronym of
>> double-ended queue. Double-ended queues are sequence containers with
>> dynamic sizes that can be expanded or contracted on both ends (either
>> its front or its back).
>>
>> All of the rest of the functionality of std::deque can be added as
>> needed.
>
> You mean you could implement a deque using two arrays if you chose to?
> So what? All I am saying is that you haven't got a deque.

If I added these things then I would have a much better deque.

>>> There is a
>>> commonly used (though not particularly efficient) way to implement a
>>> deque using two arrays, but this is not it.
>>>
>>>> #define tape_element unsigned char
>>> Use a typedef or using declaration. Also, I'd put the typedef in the
>>> class as the type belongs to the class (as least that appears to be the
>>> case from the name you've chosen).
>>>
>>>> class Tape_Type
>>>> {
>>>> private:
>>>> int Tape_Head = 0; // Can be negative
>>>> std::vector<tape_element> Left; // Stores left expansion
>>>> std::vector<tape_element> Right; // Stores right expansion
>>>> tape_element & operator[](int index);
>>>>
>>>> public:
>>>> void move_left(); // Tape_Head--; Left.push_back(0); as needed
>>>> void move_right(); // Tape_Head++; Left.push_back(0); as needed
>>> The comments are wrong since you push_back('_').
>>>
>>>> void Write(tape_element Y){ this->operator[](Tape_Head) = Y; };
>>>> tape_element Read() { return this->operator[](Tape_Head); };
>>> I'd write (*this)[Tape_Head] but I suppose that's just a matter of style.
>>>
>>>> Tape_Type(){ Right.push_back('_'); } // constructor
>>> The constructor leaves a Tape_Type object in an unusable state, but
>>> that's due to a bug in operator[]. Did you test?
>>
>> Yes I tested so I don't see what you mean.
>
> Testing should have caught the bug in operator[].

It is was a new refactoring of existing working code.

>>>> void Output();
>>>> };
>>>>
>>>> tape_element& Tape_Type::operator[](int index)
>>>> {
>>>> if (index > 0)
>>>> return Right[index];
>>> Bug. You meant index >= 0 I think.
>>
>> Yes Richard caught that. That was a new refactoring.
>>>
>>>> int Left_Index = ((index * -1) -1);
>>> Why not -index - 1?
>>>
>>>> return Left[Left_Index];
>>> Do you think introducing a new variable really make the code clearer
>>> that simply writing
>>> return Left[-index - 1];
>>> ? Personally, I'd write the whole thing as
>>> return index >= 0 ? Right[index] : Left[-index - 1];
>>>
>>>> }
>>>>
>>>> void Tape_Type::Output()
>>>> {
>>>> printf("Tape_Type::Output()\n");
>>>>
>>>> if (Left.size())
>>>> {
>>>> int Last_One = Left.size() - 1;
>>>> for (int N = Last_One; N >= 0; N--)
>>>> {
>>>> int TH = (N + 1) * -1; // determine Tape_Head from N
>>>> printf("[%04d]:%c Left[%02d]\n", TH, Left[N], N);
>>>> }
>>>> }
>>>> if (Right.size())
>>>> for (int N = 0; N < Right.size(); N++)
>>>> printf("[%04d]:%c Right[%02d]\n", N, Right[N], N);
>>>> }
>>>>
>>>> void Tape_Type::move_left()
>>>> {
>>>> Tape_Head--;
>>>> int Left_Index = ((Tape_Head * -1) -1);
>>>> if (Left_Index == Left.size())
>>>> Left.push_back('_');
>>>> }
>>>>
>>>> void Tape_Type::move_right()
>>>> {
>>>> Tape_Head++;
>>>> if (Tape_Head == Right.size())
>>>> Right.push_back('_');
>>>> }
>>>
>>> I find the capitalisation odd and unhelpful as there does not seem to be
>>> any consistency about it.
>>
>> I found all of your suggestions very helpful.
>> I don't see the bug in the constructor.
>
> There is none. I just said the constructor leaves the tape unusable
> because of the bug in operator[].

Oh, OK.

>
>> I like mixed case because it is easier to read, mine not be consistent.
>>
>> Here they are implemented.
>>
>> //
>> // Tape_Type implements a two-way Turing machine tape.
>> // Right contains Tape_Head >= 0 values (right expansion)
>> // Left contains Tape_Head < 0 values (left expansion)
>> //
>> // Tape_Type has functionality very similar to std::deque
>
> This comment is not correct.
>
>> // yet implements this functionality much more simply.
>> // This saves time and space.
>> //
>> class Tape_Type
>> {
>> typedef unsigned char tape_element;
>
> You probably want that to be a public typedef. And now that it's in the
> class, the name can be sorter. The usual convention is _t for types:
>
> typedef unsigned char element_t;
>
> I plugged your tape class into my C++ TM interpreter and it made it
> slightly slower for the "big" BB(5) test compared with my naive tape
> that just uses a single string.
>

std::string or char * ?
If char * was pre-allocated that would give it a big speed advantage.

I could add reserve(left/right):
void reserve(unsigned int N)
{ Left.reserve(N); Right.reserve(N); }

> Note: this is not a comment on the design of your tape. There's nothing
> wrong with it (except a little inconvenience, see below). The speed
> will be determined almost entirely by how std::string and std::vector
> are implemented. You might see completely different timings just by
> linking with a different library.
>
> Mind you, I prefer using a string to all the other methods I've tried
> because it's so convenient. You can set up the TM with an input simply
> by writing
>
> tape = input
>
> and you can debug by printing the tape any time you like. And I use a
> string_view to get the non-blank "result" out of the TM and the end of a
> run. All easy to get round with a couple of functions, but still, since
> it's fast I see no reason t change.
>

What about memory allocation?

--
Copyright 2022 Pete Olcott

"Talent hits a target no one else can hit;
Genius hits a target no one else can see."
Arthur Schopenhauer

SubjectRepliesAuthor
o Implementing a two-way Turing Machine tape as an improvement to

By: olcott on Thu, 12 May 2022

35olcott
server_pubkey.txt

rocksolid light 0.9.8
clearnet tor